Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouEster Penha de Sousa Alterado mais de 7 anos atrás
1
Algoritmos e Estruturas de Dados I – Modularização
Profa. Mercedes Gonzales Márquez
2
Modularização Sempre é possível dividir problemas grandes e complicados em problemas menores e de solução mais simples. Problemas simples: Resolução direta. Problemas mais complexos: Quebrar em problemas menores. Cada problema menor pode se tornar um módulo.
3
Modularização O algoritmo principal é aquele por onde começa a execução, e chama, eventualmente, os demais módulos. Módulo é um algoritmo que, geralmente, resolve um pequeno problema, e que está subordinado a um outro algoritmo que solicitará seu acionamento. É possível que um módulo chame outro módulo.
4
Construindo módulos 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.
5
Vantagens da Modularização
Evitar extensos blocos de programa e portanto difíceis de ler e entender. Dividir o programa em partes que possam ser logicamente compreendidas de forma isolada. Reaproveitar blocos de programa já construídos (por você ou por outros programadores), minimizando erros e facilitando alterações.
6
Definindo um módulo Um módulo é definido da seguinte forma:
tipo nome(tipo parâmetro1, ..., tipo parâmetroN) Inicio comandos Fim retorne valor de retorno Todo módulo deve ter um tipo (inteiro, real). Esse tipo determina qual será o tipo de seu valor de retorno. Este módulo recebe o nome de função.
7
Definindo um módulo Um módulo é definido da seguinte forma:
tipo nome(tipo parâmetro1, ..., tipo parâmetroN) Inicio comandos Fim retorne valor de retorno O módulo também pode executar uma ação sem produzir um valor de retorno. Neste caso o troca-se o tipo pela palavra “nulo” e o comando retorne deixa de existir. Este tipo de módulo recebe o nome de procedimento.
8
Definindo um módulo Um módulo é definido da seguinte forma:
tipo nome(tipo parâmetro1, ..., tipo parâmetroN) Inicio comandos Fim retorne valor de retorno Os parâmetros são variáveis que são inicializadas com valores indicados durante a invocação do módulo. O comando retorne devolve para o invocador do módulo o resultado da execução deste.
9
Invocando um módulo Quando o nome de um módulo é encontrado, ocorre um desvio no algoritmo principal ou módulo chamador para que os comandos do módulo chamado sejam executados. Ao término do módulo, a execução retornará ao ponto subsequente ao da sua chamada. Exemplo:
10
Invocando um módulo Exemplo: Algoritmo <exemplo 1>
real soma(real:x, real:y) Início retorne (x+y) Fim Escreva (“Digite dois números reais: “) Leia ( x,y ) Escreva (“A soma de” x, “e”, y, “eh:”soma(x,y))
11
Parâmetros Parâmetros são canais pelos quais se estabelece uma comunicação bidirecional entre um módulo e o algoritmo chamador (algoritmo principal ou outro módulo). 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.
12
Parâmetros Parâmetros Formais: São os nomes simbólicos introduzidos no cabeçalho dos módulos, usados na definição dos parâmetros do mesmo. Parâmetros Reais (ou argumentos):São aqueles que substituem os parâmetros formais quando da chamada do módulo.
13
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
14
Passagem de Parâmetros
Exemplo: Algoritmo <teste> Inteiro:x Modulo porvalor(inteiro:a) Inicio a ← 5 Fim x ← 10 porvalor(x) escreva (x)
15
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 módulo (parâmetro formal) durante a execução do mesmo. Qualquer alteração da variável do módulo (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.
16
Passagem de Parâmetros
Exemplo: Algoritmo <teste> Inteiro:x Procedimento porreferencia(inteiro:*a) Inicio *a ← 5 Fim x ← 10 porreferencia(&x) escreva (x)
17
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 fora deste módulo.
18
Variáveis globais e locais
Uma variável local é criada (alocada na memória) no momento em que o módulo que a define é chamado. Uma variável local é liberada da memória no momento em que o módulo que a define termina. Uma variável local somente existe (só pode ser utilizada) dentro do módulo que a define.
19
Variáveis globais e locais
Caso um mesmo identificador (nome de variável) seja declarado em módulos 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 módulo sem interferir em outros módulos.
20
Exemplos 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.
21
Algoritmo <combinacoes> real fatorial(inteiro: x) real: fat ← 1
inteiro: i Inicio para (i ← x ; i >1; -1) fat ← fat * i fim para retorne fat Fim 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 Três chamadas a função fatorial
22
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> real fatorial(inteiro: x) nulo troca(int *x, int *y) inteiro: aux Inicio aux ←*x *x ← *y *y ← aux Fim Inteiro: n,p,C Leia (n,p) se (p > n) entao troca(&p,&n) Fim se Se ((p >= 0) e (n >= 0)) entao C ← fatorial(n)/(fatorial(p)*(fatorial(n-p))) escreva C Passagem por referência de p e n.
23
Algoritmo <Pares_Impares>
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 par(inteiro:w) Início se (mod(w,2)=0) então retorne (1) senão retorne(0) fim se Fim inteiro: n,i,x,somapar=0 Leia (n) Para (i ← 1; i<=n; i ←i+1) Leia ( x ) somapar ← somapar+par(x) Fim para O retorno de par(x) será 1 ou 0, permitindo fazer a contagem sem o uso explícito de um contador
24
Ex.5.Escreva um algoritmo que leia as medidas dos três lados a, b e c de um paralelepípedo, calcule e escreva o valor da sua diagonal. L=sqr(a2+b2) D=sqr(L2+c2) c D b L a Algoritmo <paralelepipedo> real hipotenusa(real: a, real:b) real: hip Início hip ←sqr(a**2+b**2) retorne(hip) fim real:a,b,c,d leia (a,b,c) d←hipotenusa(hipotenusa(a,b),c) escreva d Fim A função hipotenusa é invocada com os parâmetros: (1) hipotenusa (a,b) e (2) c A função hipotenusa é invocada com os parâmetros: (1) a e (2) b
25
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.
26
Algoritmo <conjectura> inteiro primo(inteiro: n) inteiro:i
Lembre-se que a raiz de n divide os divisores de n em dois grupos: os menores e os maiores que a sua raiz, sendo os de um grupo de certa forma “complementares” aos do outro grupo. Então será suficiente procurarmos divisores triviais de n percorrendo somente até a raiz de n. Algoritmo <conjectura> inteiro 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 inteiro: i,par leia (par) enquanto (par>0) faça para (i ←1; i<= par; i←i+1) se (primo(i) e primo (par-i)) então escreva (i, par-i) i ←par fim para Fim Se i é um primo então resta verificar se par-i é também um primo, o que fará que tenhamos os dois números cuja soma dará o número par.
27
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.
28
Algoritmo <amigos> 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 retorne(soma) fim inteiro: a,b,m,n leia (a,b) para (m←a; m<=b; m←m+1) n ← soma_div(m) se (n>=a e n<=b e soma_div(n)=m) escreva (m,n) Lembre-se que a raiz de n divide os divisores de n em dois grupos: os menores e os maiores que a sua raiz, sendo os de um grupo de certa forma “complementares” aos do outro grupo. Então se acharmos um divisor i menor que a raiz, também haverá um divisor n/i no grupo dos maiores que a raiz.
29
Funções com registros como parâmetros
Uma função não somente considera dados primitivos como parâmetros, podemos também ter necessidade de dados da passagem de dados tipo registro como no exemplo abaixo. 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: Que calcula a distância entre dois pontos do espaço; Que calcula a área de um triângulo em função de seus lados onde é o semi-perímetro do triângulo (a+b+c)/2.
30
Funções com registros como parâmetros
Como os 4 vértices do tetraedro são pontos no espaço, podemos criar um registro chamado ponto3d, que considere as três coordenadas de um ponto no espaço. Assim: Tipo ponto3d : registro real: x,y,z Fim registro Assim podemos usar um vetor de 4 elementos do tipo ponto3d que contenha os 4 vértices do tetraedro.
31
Funções com vetores como parâmetros
3131 Funções com vetores como parâmetros Um vetor passado como parâmetro é implicitamente passado por referência. o acesso aos elementos de v não precisa do modificador * Qualquer alteração de valor de um elemento de v é uma alteração no valor do vetor ‘original’. Exemplo: O seguinte procedimento lê um vetor de tamanho tam. nulo le_vetor(inteiro: vet[], inteiro: tam){ inteiro: i Para i de 1 até tam repita leia (vet[i])
32
Funções com vetores como parâmetros
3232 Funções com vetores como parâmetros E no algoritmo principal dois vetores são declarados e passados por referência para fazer a leitura dos seus dados. Inicio inteiro: vet1[5], vet2[5] le_vetor(vet1,5) le_vetor(vet2,5) Fim Acrescente um procedimento que faça a troca dos elementos entre dois vetores e outro procedimento que imprima os valores dos vetores. Faça a chamada do procedimento imprima antes da troca e depois da troca.
33
Ex 9. 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
34
Ex.10 -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”.
35
Algoritmo <ganhadores>
inteiro ganhador(inteiro:V[], inteiro: n) Inteiro: i,maior,contmaior,cont[6] Inicio Para (i ←1; i<= 6; i ←i+1) cont[i] ←0 Fim Para Para (i ←1; i<= n; i ←i+1) cont[V[i]] ← cont[V[i]]+1 maior←1 contmaior←cont[1] Para (i ←2; i<= 6; i ←i+1) Se (cont[i]>contmaior) então contmaior← cont[i] maior←i Fim se Retorne(maior) Fim Os valores possíveis contidos no vetor V são os inteiros de 1 até o 6, então é prático criar um vetor de 6 contadores, onde o valor contido no índice i deste vetor corresponderá ao número de ocorrências do valor i no vetor V.
36
Para (i ←1; i<= 30; i ←i+1) para (j ←1; j<= 40; j ←j+1)
Inicio inteiro: i Para (i ←1; i<= 30; i ←i+1) para (j ←1; j<= 40; j ←j+1) leia dia[j] fim para mes[i] ← ganhador(dia,40) ganhador_mensal ← ganhador(mes,30) Fim
37
Funções e Procedimentos
Ex.11 - 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. nulo leia (habitante:dados[]) inteiro: i Início Para (i ←1; i<= 50; i ←i+1) 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.
38
Funções e Procedimentos
Faça um procedimento que receba o vetor de registro definido no 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. nulo informacoes(habitante:dados[], inteiro:*maioridade,*soma) inteiro: i Início *soma←0 *maioridade ← 0 Para (i ←1; i<= 50; i ←i+1) 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 Fim
39
Exemplo um pouco extenso
Vamos fazer um algoritmo (em C) para determinar que tipo de número é um inteiro lido pelo usuário. As opções são primo, perfeito, abundante e defectivo. Ou seja: um algoritmo de 5 funções, com a seguinte tela inicial: Segue-se o conceito de cada tipo de número. Primo: todo número natural maior que 1 cujos únicos divisores são o 1 e o próprio número. Exemplos: 2, 3, 5,…
40
Exemplo um pouco extenso
Perfeito: todo número natural que é igual à soma dos seus divisores próprios DP(todos seus divisores exceto ele mesmo). Exemplo, o 6 é um número perfeito pois seus DP são 1, 2, e 3 e se cumpre que 1+2+3=6. Abundante: todo número natural cuja soma dos seus DP é maior que o próprio número. Por exemplo, 12 é abundante já que sus DP son 1, 2, 3, 4 e 6 e se cumpre que =16, que é maior que 12. Defectivo: todo número natural cuja soma dos seus DP é menor que o próprio número. Por exemplo, 16. Números amigos: pares (A,B) de números cuja suma dos DP de A é igual a B, e a soma dos DP de B é igual a A. Exemplo 220 y 284 são amigos.
41
Exemplo um pouco extenso
Vamos criar as seguintes funções: main() que apenas chame o procedimento menu() menu() que irá exibir as opções para o usuário escolher, encaminha() que irá encaminhar a execução às funções correspondentes para a determinação dos tipos de números. Esta função considera os 'case' necessários. leitura() que fará a leitura e validação da entrada do(s) número(s). primo() que determina se um número é primo ou não. somadivisores() que determinará a soma dos DP de um inteiro n, esta função será necessária para determinar se um número é perfeito, abundante, defectivo, e se dois números são amigos.
42
Exemplo um pouco extenso
Perfeito() que determinará, nesta única função, se o número é perfeito, é abundante ou defectivo Amigos() que determinará se dois números são amigos. Ou seja: um programa de 7 funções além da main(). Veja a implementação descrita no programa TiposNumeros.c no site da disciplina. Ele possui 152 linhas. Quando um programa é extenso precisamos organizá-lo em mais de um arquivo para facilitar a sua compreensão.
43
Exemplo um pouco extenso
Mostraremos que podemos criar um projeto para organizar TiposNumeros.c em dois arquivos: Um que contenha o programa principal (main.c) e outro que contenha somente as funções de um programa (funcoes.c). Pode também criar um arquivo header, veja na aula PCI-FuncoesProcedimentos.ppt
Apresentações semelhantes
© 2025 SlidePlayer.com.br Inc.
All rights reserved.