Algoritmos e Estruturas de Dados I – Modularização Profa. Mercedes Gonzales Márquez Modularização Sempre é possível dividir problemas grandes e complicados em problemas menores e de solução mais simples. A decomposição de um problema é fator determinante para a redução da sua complexidade. Um algoritmo que envolve um problema grande pode ser dividido em um algoritmo principal e em diversos subalgoritmos ou módulos, tantos quantos forem necessários ou convenientes. Modularização O algoritmo principal é aquele por onde começa a execução, e chama, eventualmente, os demais subalgoritmos. Subalgoritmo é um algoritmo que, geralmente, resolve um pequeno problema, e que está subordinado a um outro algoritmo que solicitará seu acionamento. É possível que um subalgoritmo chame outro subalgoritmo. Construindo sub-algoritmos • Critérios para orientar o processo de decomposição. Dividir o problema em suas partes principais. Analisar a divisão obtida para garantir coerência. Se alguma parte ainda permanecer complexa, sub-dividi-la mais. Analisar o resultado para garantir entendimento e coerência. Vantagens da Modularização Dividir problemas grandes em vários problemas menores, de baixa complexidade. Número pequeno de variáveis Poucos caminhos de controle (caminhos do início ao fim) Utilizar soluções gerais para classes de problemas ao invés de soluções específicas para problemas particulares. Reusabilidade Solucionar uma única vez o problema Vantagens da Modularização Permite delimitar o escopo (nível de abrangência) de variáveis. Variáveis locais. Evita a repetição, dentro de um mesmo algoritmo, de uma sequência de ações em diferentes pontos. Variáveis globais e locais Todo módulo é constituído por um sequência de comandos que operam sobre um conjunto de variáveis que podem ser globais ou locais. Variáveis globais : Podem ser usadas em módulos internos a outro módulo do algoritmo onde foram declaradas. Variáveis locais: Só podem ser usadas no módulo do algoritmo onde foram declaradas. Elas não possuem significado Variáveis globais e locais Uma variável local é criada (alocada na memória) no momento em que o subalgoritmo que a define é chamado. Uma variável local é liberada da memória no momento em que o sub-algoritmo que a define termina. Uma variável local somente existe (só pode ser utilizada) dentro do subalgoritmo que a define Variáveis globais e locais Caso um mesmo identificador (nome de variável) seja declarado em subalgoritmos distintos, esses identificadores são considerados distintos entre si (variáveis distintas) O uso de variáveis locais minimiza a ocorrência de “efeitos colaterais” : o programador pode definir e utilizar as variáveis que desejar em um subalgoritmo sem interferir com outros subalgoritmos Sintaxe de um algoritmo modularizado Algoritmo <nome> Definição de tipos Declaração de variáveis globais Definição de módulos Início Conjunto de ações do algoritmo principal (incluídas as chamadas aos módulos com seus correspondentes nomes) Fim • Quando o nome de um módulo é encontrado, ocorre um desvio no algoritmo principal ou (sub)algoritmo chamador para que os comandos do módulo sejam executados. Ao término do módulo, a execução retornará ao Parâmetros Parâmetros são canais pelos quais se estabelece uma comunicação bidirecional entre um subalgoritmo e o algoritmo chamador (algoritmo principal ou outro subalgoritmo). Os dados são passados pelo algoritmo chamador através de argumentos ou também chamados parâmetros reais, e são recepcionados por meio de parâmetros formais. Parâmetros Parâmetros Formais: São os nomes simbólicos introduzidos no cabeçalho dos subalgoritmos, usados na definição dos parâmetros do mesmo. Dentro de um subalgoritmo trabalha-se com estes nomes da mesma forma como se trabalha com variáveis locais ou globais. Parâmetros Reais (ou argumentos):São aqueles que substituem os parâmetros formais quando da chamada do subalgoritmo. Passagem de Parâmetros Por valor O argumento ou parâmetro real é avaliado, gerando um valor que é copiado para a variável declarada no módulo (parâmetro formal) Qualquer alteração do parâmetro formal não é "transmitida" para a variável do argumento. O argumento da chamada (parâmetro real) pode ser uma constante, uma variável ou uma expressão: 5, v1, v1+5-v2 Passagem de Parâmetros Exemplo: Algoritmo <teste> Inteiro:x Modulo porvalor(inteiro:a) Inicio a←5 Fim Inicio x ← 10 porvalor(x) escreva (x) Fim Passagem de Parâmetros Por referência - O argumento ou parâmetro real tem que ser uma variável: v1, v2 ... - A variável do argumento (parâmetro real) é associada com a variável declarada no subalgoritmo (parâmetro formal) durante a execução do subalgoritmo. - Qualquer alteração da variável do subalgoritmo (parâmetro formal) acontece também na variável do argumento. - Usaremos a seguinte convenção: o símbolo & indicará a passagem por referência no argumento e * no parâmetro formal. Passagem de Parâmetros Exemplo: Algoritmo <teste> Inteiro:x Procedimento porreferencia(inteiro:*a) Inicio *a ← 5 Fim Inicio x ← 10 porreferencia(&x) escreva (x) Fim Tipos de sub-algoritmos Tipos de Sub-algoritmos: Funções (functions) Procedimentos (procedures) Procedimentos Procedimento: Um conjunto de ações que não irá devolver valores ao (sub)algoritmo chamador. Forma geral de um procedimento (sintaxe): Procedimento <nome>(<parâmetros formais>) Declaração de variáveis locais do procedimento Início Comandos do procedimento Fim Chamada de um procedimento (sintaxe): Nome_procedimento(argumentos) Procedimentos Juntando definição e chamada de u procedimento : Algoritmo <nome_algoritmo> Definição de tipos Declaração de variáveis globais Procedimento <nome_procedim>(<parâmetro formais>) Declaração de variáveis locais do procedimento Inicio Comandos do procedimento Fim /* algoritmo principal*/ Início Comandos do algoritmo principal nome_procedimento(argumentos) Comandos do algoritmo principal Procedimentos – Exemplos simples Exemplo 1: Faça um algoritmo que dado um valor real global x, chame um procedimento que calcula o quadrado de x. Algoritmo <Quad> real: x Procedimento Quadrado() real: z Início z ← x*x Escreva (“O quadrado do número é =“,z) Fim Início Escreva (“Digite um número: “) Leia ( x ) Quadrado() Fim Procedimentos Exemplo 2 (muito simples com finalidade de explicar a diferença entre variáveis locais e globais) : Faça um algoritmo que use um procedimento para ler o nome de uma pessoa e outro para mudá-lo. Algoritmo <EscreveNome> iteral: nome Procedimento le_nome() nício Leia (nome) Fim Procedimento muda_nome() nício escreva (“Vamos mudar o nome”) leia (nome) Fim nício Le_nome Escreva (nome) Muda_nome Escreva (nome) Procedimentos Exemplo 3 (muito simples com finalidade de explicar a diferença entre variáveis locais e globais) : Faça um algoritmo que use um procedimento para ler o nome de uma pessoa e outro para mudá-lo (use nome como var local) Algoritmo <EscreveNome> literal: nome Procedimento le_nome() Início Leia (nome) Fim Procedimento muda_nome() literal:nome Início escreva (“Vamos mudar o nome”) leia (nome) Fim Início Le_nome Escreva (nome) Muda_nome Procedimentos No exemplo 3, a variável global nome e a variável local nome representam posições de memória totalmente diferentes, logo, qualquer mudança no conteúdo da variável local, não afetará o conteúdo da variável global. Funções Função Um conjunto de ações cujo objetivo é retornar ao ponto de sua chamada um valor, o qual será associado ao próprio nome que identifica a função. Por isso, as funções podem ser utilizadas em expressões como se fossem variáveis. O conceito de funções é originário da ideia de função matemática, onde um valor é calculado a partir de outro(s) valor(es) fornecido(s) à função. O comando retorne explicita qual é o valor a retornar. Funções Forma geral de uma função (sintaxe): Função tipo <nome>(<parâmetros-formais>) Declaração de variáveis locais da função Início Comandos Fim onde, tipo é o tipo do valor que será retornado, lista-de-parâmetros-formais é a lista das variáveis (com seus tipos) que recepcionam as variáveis fornecidas quando da chamada da função Funções Chamada de uma função (sintaxe): nome(lista-de-parâmetros-reais) onde, lista-de-parâmetros-reais é a lista das variáveis que se corresponderão com os parâmetros formais durante a execução da função. Os parâmetros reais devem concordar em números, ordem e tipo com os parâmetros formais. Exemplo: Funções INSTRUÇÃO Retorne Comando usado apenas nas funções que tem o efeito de parar a execução da função e enviar um valor para o algoritmo chamador. No corpo de instruções da função deve haver, pelo menos, uma instrução Retorne. Sintaxe: Retorne ( <expressão> ) Exemplos: Retorne ( area ) Retorne ( pi*r*r ) Funções Exemplo 1: Faça um algoritmo que dado um valor real x, chame uma função que retorne o quadrado de x. Algoritmo <Quad> real: x, y Função real quadrado(real:w) real: z Início z ← w*w retorne (z) Fim Início Escreva (“Digite um número: “) Leia ( x ) y ← quadrado (x) Escreva (“ y = “ , y ) Funções • Ex.2 –Faça um algoritmo que calcule o número de combinações de n eventos em conjuntos de p eventos, p <=n. • Sem o conceito de função, teríamos que repetir três vezes as instruções para calculo do fatorial de um numero x. Com o conceito de função, precisamos apenas escrever essas instruções uma única vez e substituir x por n, p, e (n-p) para saber o resultado de cada calculo fatorial. Algoritmo <combinacoes> Função real fatorial(inteiro: x) real: fat ← 1 inteiro: i Inicio para i de x até 1 passo -1 repita fat ← fat * i fim para retorne fat Fim Funções Inicio Inteiro: n,p,C Leia (n,p) Se ((p >= 0) e (n >= 0) e (p <= n) entao C ← fatorial(n)/(fatorial(p)*(fatorial(n-p))) escreva C Fim se Fim Funções e Procedimentos • Ex.3 Modifique o algoritmo anterior para trocar os valores das variáveis p e n quando p>n, para satisfazer a condição do enunciado que exige que p<=n. Algoritmo <combinacoes> Função real fatorial(inteiro: x) Procedimento troca(int *x, int *y) inteiro: aux Inicio aux ←*x; /*conteudo de x e atribudo ao conteudo de aux */ *x ← *y; /* conteudo de y e atribudo ao conteudo de x */ *y ← aux; /*conteudo de aux e atribudo ao conteudo de y*/ Fim Funções Inicio Inteiro: n,p,C Leia (n,p) se (p > n) entao troca(&p,&n) /* passa os enderecos de p e de n */ Fim se Se ((p >= 0) e (n >= 0)) entao C ← fatorial(n)/(fatorial(p)*(fatorial(n-p))) escreva C Fim se Fim Funções Ex.4 - Faça uma função para determinar se um número inteiro é par ou não. Utilize esta função para calcular o total de números pares dentre um total de n números inteiros positivos. Algoritmo <Pares_Impares> inteiro: n,i,x,somapar=0 Função inteiro par(inteiro:w) Início se (mod(w,2)=0) então retorne (1) senão retorne(0) fim se Fim Início Leia (n) Para i de 1 até n repita Leia ( x ) somapar ← somapar+par(x) Fim para Funções e Procedimentos Ex.5.Escreva um algoritmo que leia as medidas dos tres lados a, b e c de um paralelepípedo, calcule e escreva o valor da sua diagonal. c b D L a L=sqr(a2+b2) D=sqr(L2+c2) Funções Algoritmo <paralelepipedo> double:a,b,c,d Função double hipotenusa(double: a,b) double: hip Início hip ←sqr(a**2+b**2) retorne(hip) fim Início leia (a,b,c) d←hipotenusa(hipotenusa(a,b),c) escreva d Fim Funções e Procedimentos Ex.6. Segundo a conjectura de Goldbach, qualquer número par, maior que 2, pode ser escrito como a soma de dois números primos. Ex. 8=3+5, 16=11+5, 68=31+37, etc. Dado um conjunto de números inteiros positivos pares, fazer um algoritmo que calcule, para cada número, um par de números primos cuja soma seja igual ao próprio número. Adotar como flag um número negativo. Para verificar se um número é primo, fazer uma função que deverá retornar em uma variável lógica o valor verdadeiro, se o número for primo, e falso, em caso contrário. Funções Algoritmo <conjectura> inteiro: i,par Função logico primo(inteiro: n) inteiro:i Início i ←2 enquanto (i<=sqr(n)) faça se (mod(n,i)=0) então retorne(0) fim se i ←i+1 fim enquanto retorne(1) fim Início leia (par) enquanto (par>0) faça para i de 1 até par repita se (primo(i) e primo (par-i)) então escreva (i, par-i) i ←par fim se fim para leia (par) fim enquanto Fim Funções Início leia (par) enquanto (par>0) faça para i de 1 até par repita se (primo(i) e primo (par-i)) então escreva (i, par-i) i ←par fim se fim para leia (par) fim enquanto Fim Funções e Procedimentos Ex.7. Fazer uma função que, dado um número inteiro N, retorne a soma dos divisores deste número, exceto ele próprio. Fazer um algoritmo que, utilizando a função anterior, determine e escreva todos os pares de números amigos em um intervalo ´[A,B]. Os valores de A e B (A<B), inteiros maiores que zero , deverão ser lidos. Dois números inteiros M e N são amigos se a soma dos divisores de M, excluindo M, é igual a N e a soma dos divisores de N, excluindo N, é igual a M. Funções Algoritmo <amigos> inteiro: a,b,m,n Função inteiro soma_div(inteiro: n) inteiro:soma, i Início soma ←1 i ←2 enquanto (i<sqr(n)) faça se (mod(n,i)=0) então soma ←soma+ i + n/i fim se i ←i+1 fim enquanto se (i=sqr(n)) soma←soma+i fim se retorne(soma) fim Funções Início leia (a,b) para m de a até b repita n ← soma_div(m) se (n>=a e n<=b e soma_div(n)=m) escreva (m,n) fim se fim se fim Funções e Procedimentos Ex.8. Calcular e escrever a área total de 10 tetraedros, dadas as coordenadas de cada um de seus quatro vértices. Para tanto, deverão ser utilizados os seguintes módulos: (a) Que calcula a distância entre dois pontos do espaço; (b) Que calcula a área de um triângulo em função de seus lados AREA x( a)x( b) x( c) onde é o semi-perímetro do triângulo (a+b+c)/2. Funções Ex.9 - Escrever uma função que receba dois números inteiros positivos, e determine o produto dos mesmos, utilizando o seguinte método de multiplicação. Dividir, sucessivamente , o primeiro número por 2, até que se obtenha 1 como quociente; Paralelamente, dobrar, sucessivamente, o segundo nro; Somar os números da segunda coluna que tenham um número ímpar na primeira coluna. O total obtido é o 9 x 6 produto procurado. Exemplo: 9 6→ 6+ 4 12 2 24 1 48→48 -----54 Faça um algoritmo que use a função definida e calcule o produto dos nros inteiros contidos em um intervalo [a,b]. Funções função inteiro produto(inteiro:x,y) inteiro:produto Início produto ←0 Enquanto (x<>1) faça Se (mod(x,2)=1) então produto←produto+y Fim se x←div(x,2) y←y*2 Fim enquanto retorne(produto+y) Fim Funções Ex.10 -A mediana de um conjunto de números é o elemento m do conjunto, tal que a metade dos números restantes é maior ou igual a m e a metade é menor ou igual a m, se o número de elementos do conjunto for ímpar. Se for par, a mediana será a média dos dois elementos, m1 e m2, tal que a metade dos elementos restantes no vetor é maior ou igual a m1 e m2 e metade é menor ou igual a m1 e m2. Escreva uma função que leia um conjunto A de inteiros e calcule a mediana do conjunto. Funções função real mediana(inteiro:V[], n) Início /* Use um algoritmo de ordenação de vetores de forma que os elementos de V já fiquem ordenados*/ Se (mod(n,2)=0) então retorne((V[n/2]+V[(n/2)+1])/2) senão retorne(V[(n+1)/2]) fim se Fim Funções Ex 11. Escreva uma função chamada MAIORES com três parâmetros de entrada: Um valor inteiro x, um vetor de inteiros V e o tamanho n (1<n<50). A função deverá retornar a quantidade de inteiros em V maiores ou iguais que x. Escreva um algoritmo que, dado um conjunto de n números inteiros diferentes, use a função MAIORES para mostrar os números na ordem decrescente Funções Ex.11 -A função ganhador determina o número que apareceu mais vezes dentre um conjunto de n números. Supõe-se que os valores possíveis de cada número estão entre 1 e 6, inclusive, e que sempre haverá um único número vencedor. Obs. Os n números estão armazenados em um vetor V que é passado como parâmetro e o valor n é também passado por parâmetro. Sabendo-se que um jogo de dados ocorre 40 vezes por dia, faça um algoritmo que lendo os dados dos 30 dias correspondentes a um mês de jogo: (a) Determine o número ganhador do dia, utilizando-se a função anterior e escreva este número e a mensagem “RESULTADO DIARIO”; (b) Verifique também qual o número ganhador do mês e escreva este número e a mensagem “RESULTADO MENSAL DO JOGO”. Funções Algoritmo <ganhadores> inteiro: i função inteiro ganhador(inteiro:V[], n) Inteiro: i,maior,contmaior,cont[6] Inicio Para i de 1 até 6 repita cont[i] ←0 Fim Para Para i de 1 até n repita cont[V[i]] ← cont[V[i]]+1 Fim Para maior←1 contmaior←cont[1] Para i de 2 até 6 repita Se (cont[i]>contmaior) então contmaior← cont[i] maior←i Fim se Fim Para Retorne(maior) Fim Funções para i de 1 até 30 repita para j de 1 até 40 repita leia dia[j] fim para mes[i] ← ganhador(dia,40) fim para ganhador_mensal ← ganhador(mes,30) Fim Funções e Procedimentos Ex.12. Determinar os números inteiros, menores que 50.000.000 que são capicuas. Capicuas são números que têm o mesmo valor se lidos da esquerda para a direita ou da direita para a esquerda. Exemplo: 44, 232, 1661, etc. Deverão ser escritos os seguintes algoritmos: •Um módulo principal •Uma função que calcule quantos algarismos tem um determinado número inteiro •Uma procedimento para separar um número em n algarismos •Uma procedimento para formar o número na ordem inversa Algoritmo <capicuas> inteiro:i,na ,V[8] Função inteiro numero_algarismos (inteiro: num) inteiro:i Inicio i ←0 enquanto (num<>0) repita num ←div(num,10) i ←i+1 fim enquanto retorne(i) Funções e Procedimentos Procedimento separa_algarismos (inteiro: na,num,*V[]) inteiro:i Inicio Para i de 1 ate na repita *V[i] ←mod(num,10) num←div(num,10) Fim Para Fim Função inteiro numero_ordem_inversa (inteiro:na,V[]) inteiro:i,inverso Inicio inverso ←0 Para i de 1 ate na repita inverso ←V[i]*10**(na-i)+inverso Fim Para Retorne(inverso) Fim Inicio /*modulo principal*/ Para i de 1 até 50000000 repita na←numero_algarismos(i) separa_algarismos(na,i,&V[8]) se (i=numero_ordem_inversa(na,V[8])) escreva (“O numero”,i,“é um numero capicua”) Funções e Procedimentos Ex.13 - Foi realizada uma pesquisa de algumas características físicas de 50 habitantes de uma certa região. De cada habitante foram coletados os seguintes dados: sexo, cor dos olhos (azuis, verdes ou castanhos), cor dos cabelos (louros, pretos ou castanhos) e idade. Faça um procedimento que leia esses dados em um vetor de registro. O vetor de registro deve ser enviado por referência. Procedimento leia (habitante:*dados[50]) inteiro: i Início Para i de 1 até 50 repita leia(*dados[i].sexo,*dados[i].cor_olhos,*dados[i].cor_cab) leia(*dados[i].idade) Fim para Fim Nota: No algoritmo principal deve ser definido o tipo habitante. Funções e Procedimentos Faça um procedimento que receba o vetor de registro definido n exercício anterior, por referëncia, e retorne também por referëncia: a maior idade entre os habitantes e a quantidade de individuos do sexo feminino cuja idade está entre 18 e 35 (inclusive) e que tenham olhos verdes e cabelos louros. Procedimento informacoes(habitante:*dados[50], inteiro:*maioridade,*soma) inteiro: i Início *soma←0 *maioridade ← 0 Para i de 1 até 50 repita se (*dados[i].idade>*maioridade) *maioridade ← *dados[i].idade se (*dados[i].sexo=“F” e *dados[i].idade>=18 e *dados[i].idade<=35 e *dados[i].cor_olhos=“verdes” e *dados[i].cor_cab=“louros”) *soma ←*soma+1 fim se Fim para Funções e Procedimentos Ex.14.Escreva um algoritmo que leia uma sequência de 100 números e os armazene em um vetor. Depois deve ser lida uma subsequência de 5 números. Desenvolva um módulo para verificar se a subsequência aparece completa e na mesma ordem em algum ponto do vetor, caso ocorra informar a primeira posição do vetor onde a subsequência ocorre. Exemplo: Sequência de 100 números 5574610257489135791224576789… Subsequência 57489 Resposta: Subsequência ocorre a partir da posição 9 Funções e Procedimentos Função logico comparasubsequencia (inteiro: V[100],S[5], *pos) Inteiro: i,j Inicio Para i de 1 até 96 repita j ←1 Se (V1[i]=S[1]) então Enquanto (j<=4 & V[i+j]=S[j+1]) faça j←j+1 Fim enquanto Se (j=5) então *pos ←i Retorne (1) /*se os elementos de S forem diferentes faça i←i+j para buscar outra subsequencia*/ Fim se Fim se Fim para Retorne(0) Funções e Procedimentos Ex.15.Dado um polinômio na forma P(x) = a1xn + a2xn-1 + ... + anx + an+1, (a) Fazer um módulo que retorne o valor do polinômio e o sua derivada no ponto x, recebendo como parâmetros entrada a ordem do polinômio, os coeficientes e o x. (b) Fazer um algoritmo que: - leia a ordem do polinômio e os seus coeficientes. -utilizando o módulo da parte (a), calcule o valor polinômio e o de sua derivada para n diversos valores x, onde o n os valores x são lidos. de de do de Funções e Procedimentos Função real valor_polinomio (inteiro: n, real: a[],real:x) inteiro: i Real: valor Inicio valor ←0 Para i de 1 até n+1 repita valor ←valor + a[i]*x**(n+1-i) Fim Para retorne (valor) Fim Algoritmo <valor_polinomio_e_polderivada> Inteiro: i,num_x,j real: a[100],x Inicio Leia (n) Para i de 1 até n+1 repita leia (a[i]) Funções e Procedimentos Leia (num_x) Para i de 1 até num_x repita leia (x) valor_pol ←valor_polinomio(n,a,x) /*Calculo dos coeficientes do polinomio derivada*/ Para j de 1 até n repita b[j] ←(n+1-j)*a[j] Fim Para valor_der ←valor_polinomio(n-1,b,x) Fim Para Fim