Algoritmos e Estruturas de Dados I – Estruturas de Controle de Fluxo e Combinações delas Profa. Mercedes Gonzales Márquez Estrutura de Repetição • Considere a seguinte situação: Desejamos imprimir uma sequência de números na tela, especificamente de 1 até 5. • A primeira ideia seria usar a estrutura sequencial e fazermos algo como: escreva (1) escreva (2) escreva (3) escreva (4) escreva (5) • Isto não é prático, mais ainda se considerarmos uma sequência muito grande como imprimir os números entre 1 e 1.000.000. • Nestes casos usamos uma variável para guardar um primeiro número inteiro e depois incrementamos repetidamente a esse número. Isto poderá ser feito usando a estrutura de repetição: Estrutura de Repetição Execução de uma sequência de comandos repetidas vezes. O computador abandona o fluxo natural da execução (de cima para baixo) e volta a executar a sequência de ações desejada. Deve-se identificar basicamente dois elementos: 1. Os comandos da repetição 2. A condição para a repetição. E dentro da condição identificamos duas situações ainda: 2.1. Inicialização ou leitura de valores 2.2. Atualizações de valores Enquanto-faça Instrução Enquanto-Faça Formato. Enquanto <condição> faça <bloco de comandos> Fim enquanto •Nesta instrução, <bloco de comandos> só é executado se <condição> for verdadeira, ou seja quando a condição for falsa a repetição termina. •A repetição também se diz que é controlada por sentinela ou flag. O valor flag é o que torna a condição falsa. •Antes de ser executado pela primeira vez é necessário que a <condição> esteja definida. •Se na primeira vez em que a <condição> for testada ela for falsa, o loop não é executado nenhuma vez. •Dentro do loop deve existir uma instrução que altera o valor da <condição>, caso contrário, o loop pode se tornar de execução infinita (não parar). Enquanto-faça Na impressão da sequência dos primeiros 1.000.000 números considera-se: 1. Comandos da repetição • Impressão de um número da sequência 2. Condição para a repetição • Quando o número for menor ou igual que 1.000.000 2.1. Inicialização de valores envolvidos na condição temos M← 1 2.2. Atualização de valores, temos M←M+1 M← 1 enquanto (M < =1.000.000) faça escreva (M) M←M+1 Fim enquanto Enquanto-faça Exemplo 1. Faça um algoritmo que determine os quadrados de um conjunto de números inteiros positivos. 1. Comandos de repetição: • Escrever o quadrado do número lido Algoritmo <quadrados> inteiro: numero 2. Condição da repetição • numero>0 2.1. Leitura inicial de numero 2.2. Atualização de número Inicio leia (numero) enquanto (numero>0) faça escreva (numero*numero) Critério de parada • Flag = numero<=0 leia (numero) fim enquanto Fim Enquanto-faça Exemplo 2: Imprimir a soma de vários pares de números informados pelo usuário. • Devemos ingressar repetidamente pares de números e fazer a soma, mas em que momento devemos parar o ingresso? • A condição da repetição não foi especificada. Então podemos usar uma das seguintes duas opções: 1. Estabelecer uma quantidade exata de pares de números 2. Estabelecer como condição de parada que ambos os números sejam zeros. Enquanto-faça Algoritmo <soma_pares1> Inicio inteiro: a,b,cont cont ←1 enquanto (cont<=30) faça leia (a,b) escreva (a+b) cont ←cont+1 fim enquanto Fim Algoritmo <soma_pares2> Inicio inteiro: a,b leia (a,b) enquanto (a<>0 ou b<>0) faça /* o flag é quando a=0 e b=0*/ escreva (a+b) leia (a,b) fim enquanto Fim Enquanto-faça Exemplo 3: Faça um algoritmo que encontre a primeira potência de 2 maior que 1000. Algoritmo <potencia> inteiro: pot 1. Comandos de repetição: Inicio pot ←1 /* primeira potencia de 2*/ 2. Condição para a repetição Pot<=1000 2.1. Inicialização de pot com 1 2.2. Atualização de pot com seu dobro Critério de parada • Flag = potencia>1000 enquanto (pot<=1000) faça pot ←2*pot /*gerando próxima potencia de 2*/ fim enquanto escreva (pot) Fim a Determinando menor ou maior de um grupo Exercício 4. Tem-se a altura e o nome de 50 pessoas. Fazer um algoritmo que escreva o nome da pessoa mais alta. Se tiver mais de uma pessoa possuindo a maior altura, escreva o nome de quaisquer delas. Comandos de repetição: • Ler um nome e altura, comparar a altura com a referência do maior, se a altura for maior que a referência, esta deve ser atualizada. • Critério de parada quando o contador for maior que 50 Algoritmo <altura> inteiro: i ←1 literal: nome,nomemaisalta real:altura, maioralt Inicio maioralt←0 enquanto (i<=50) faça leia (nome,altura) se (altura>maioralt) então maioralt←altura nomemaisalta←nome fim se i ←i+1 fim enquanto escreva (nomemaisalta,maioralt) Determinando menor ou maior de um grupo Exercício 5. Num frigorífico existem 90 bois. Cada boi traz preso no pescoço um cartão contendo seu número de identificação e seu peso. Fazer um algoritmo que escreva o número e peso do boi mais gordo e do boi mais magro. Algoritmo <bois> inteiro: i,numero,gordo,magro real:peso,pesomenor, pesomaior Inicio i ←1 pesomenor←10000 pesomaior←0 Enquanto (i<=90) faça leia (numero,peso) se (peso>pesomaior) então pesomaior←peso gordo←numero fim se se (peso<pesomenor) então pesomenor←peso magro←numero fim se i ←i+1 Fim enquanto escreva (gordo,pesomaior) escreva (magro,pesomenor) Fim Acumuladores Exercício 6: Imprimir S=1+2+3+...+(n-2)+(n1)+n, para um n fornecido pelo usuário. • O algoritmo usará uma técnica elementar em programação que é o uso de acumuladores. O acumulador usado é a variável (soma) cujo papel e incorporar ou acumular valores. • A variável é inicializada com um valor nulo e na sequência, ela é atualizada com outros valores, os quais são os números naturais obtidos pelo contador i que incrementa em cada passo da repetição. • A inicialização do acumulador com o valor zero deve-se ao fato deste ser o elemento neutro da adição. Se fosse uma multiplicação de vários números, o acumulador deveria ser inicializado com o elemento neutro da multiplicação, isto é, o 1. Acumuladores Algoritmo <soma> inteiro: i , n, soma inicio leia (n) soma ← 0 /*inicialização do acumulador com o neutro da adição*/ i←1 enquanto (i <=n) faça /* o i vai de 1 até n*/ soma ← soma +i /* atualização do acumulador que “soma” mais um i*/ i←i+1 fim enquanto escreva( soma) fim Acumuladores Exercício 7: Imprimir o fatorial de um número inteiro positivo n fornecido pelo usuário. O fatorial de n e assim definido: n!= n x (n -1) x (n - 2) x ... x 3 x 2 x1 Acumuladores Algoritmo <fatorial> /* Fatorial de um único inteiro n*/ inteiro: i , n, fat inicio leia (n) fat ← 1 /*inicialização do acumulador com o neutro da multiplicação*/ i←n enquanto (i >= 1) faça /* o i vai de n até 1 em forma decrescente*/ fat ← fat * i /* atualização do acumulador que “multiplica” mais um i*/ i←i–1 fim enquanto escreva( fat ) fim Acumuladores Como a multiplicação é comutativa, temos que: n!= n x (n -1) x ... x 3 x 2 x1 = 1 x 2 x 3 x ... x (n-1) x n Algoritmo <fatorial> /* Fatorial de inteiro n*/ inteiro: i , n, fat inicio leia (n) fat ← 1 i←1 enquanto (i <=n) faça/* o i vai de 1 até n em forma crescente*/ fat ← fat * i i ← i +1 fim enquanto escreva( fat ) fim Acumuladores Exemplo 8: Faça um algoritmo que leia uma lista de números inteiros. A leitura de dados terminará quando for ingressado o número zero (flag). Pede-se a soma e a média de todos os números lidos (excluindo o zero). Algoritmo <media> se (cont>0) então inteiro: numero,soma,cont media ←soma/cont real: media escreva (media) Inicio fim se cont ←0 Fim soma ←0 leia (numero) enquanto (numero<>0) faça soma ← soma+numero mais um numero */ cont ← cont+1 leia (numero) fim enquanto /*acumulador que “soma” Acumuladores Exercício 9. Faça um algoritmo que calcule e escreva o valor da seguinte somatória S 1 4 9 25 ... n * n -Vejamos mais claramente colocando na seguinte forma: S = 1*1 2 * 2 3 * 3 4 * 4 5 * 5 ... n * n Algoritmo <somatorio> inteiro: i,s,n Início leia (n) s ←0, i ←1 Enquanto (i<=n) faça s←s+i*i i ←i+1 Fim Enquanto Fim Acumuladores Exercício 10. Faça um algoritmo que calcule e escreva o valor da seguinte somatória 1 1 1 1 S 1 ... 2 3 4 n Algoritmo <somatorio> inteiro: i,n real: s Início leia (n) s ←0, i ←1 Enquanto (i<=n) faça s←s+1/i i ←i+1 Fim Enquanto Fim Acumuladores Exercício 11. Faça um algoritmo que calcule e escreva o valor da seguinte somatória 2 4 8 16 S = 1 + + 3 9 27 81 Vejamos mais claramente colocando na seguinte forma: Algoritmo <somatorio2> real: s Inteiro: i Início s ←0, i ←0 Enquanto (i<=4) faça s←s+2**i/3**i i ←i+1 Fim Enquanto Fim 2 2 2 23 2 4 S = 1 + 2 3 + 4 3 3 3 3 Acumuladores Exercício 12. Faça um algoritmo que calcule e escreva o valor da seguinte somatória 2 4 8 16 S=1− + − + 3 9 27 81 -Procurando uma fórmula Algoritmo <somatorio2> inteiro: i,s Início s ←1, i ←1 Enquanto (i<=4) faça s←s+(-1 )**i*2**i/3**i i ←i+1 Fim Enquanto 2 22 23 2 4 S=1− + 2 − 3 + 4 3 3 3 3 Algoritmo <somatorio2> inteiro: i,s Início s ←1, i ←1 Enquanto (i<=4) faça s ←s+(-2)**i/3**i i ←i+1 Fim Enquanto Outra estrutura de Repetição Instrução Repita-Até-Que Formato. repita <bloco de comandos> até que <condição> •Nesta instrução, <bloco de comandos> pelo menos uma vez porque somente após a sua execução a <condição> é testada. •Dentre as instruções do loop deve existir pelo menos uma que altere o valor de <condição>. •Para o mesmo problema as condições de controle dos comandos enquanto-faça e repita-até-que são condições complementares. Observe que a negação de A>0 é A<=0 e vice-versa. Repita-até que VS enquanto-faça Exemplo comparativo.- Faça um algoritmo que determine os quadrados de um conjunto de números inteiros positivos. Algoritmo <quadrados> Algoritmo <quadrados> inteiro: numero inteiro: numero Inicio Inicio leia (numero) leia (numero) enquanto (numero>0) faça repita escreva (numero*numero) escreva (numero*numero) leia (numero) leia (numero) fim enquanto até que (numero<=0) Fim Fim Observe que a primeira estrutura de repetição (enquanto-faça) é mais conveniente para resolver o problema proposto. Exercício13: Suponha que no ano N a população americana seja maior que a brasileira. Sabendo-se que os Estados Unidos possuem um crescimento anual de 2% na sua população e que o Brasil tem crescimento anual de 4%, determinar o ano em que as duas populações serão iguais (em quantidade). São dados os números de habitantes dos Estados Unidos e do Brasil no ano N. Algoritmo <populacao> Algoritmo <populacao> inteiro: ano,br,am inteiro: ano,br,am Inicio Inicio leia (ano,br,am) leia (ano,br,am) repita enquanto (am>br) faça br ←br*1.04 am ←am*1.02 am ←am*1.02 br ←br*1.04 ano ←ano+1 ano ←ano+1 até que (br>=am) escreva (ano) Fim fim enquanto escreva (ano) Fim Repita-até que VS enquanto-faça 1. Se usarmos repita-até-que, as duas populações primeiro sofrem um acréscimo, e depois o teste da condição será executado. Esta instrução é indicada se considerarmos sabido que inicialmente a população americana é de fato maior que a população brasileira. 2. Se usarmos enquanto-faça Se os valores de entrada fossem desconhecidos, esta instrução é mais adequada, pois primeiro o teste da condição é efetuado e conforme o resultado do teste o bloco será ou não executado dentro do loop. Combinação de EstruturasEstrutura Condicional dentro de Repetições Nesta seção veremos exemplos de problemas cujas soluções requerem o uso de desvios condicionais aninhados dentro de um escopo de um comando de repetição. Exercício 14.Ler uma sequência de números e imprimir separadamente a soma dos que são pares e a soma dos que são ímpares. O algoritmo deve terminar quando o numero lido for o zero. Este último numero também deve ser ignorado. Estrutura Condicional dentro de Repetições Algoritmo <somaParesImpares> inteiro: x, somapares , somaimpares Inicio somapares ← 0 somaimpares ← 0 leia (x) enquanto (x <> 0) faça se (mod(x,2)= 0) entao somapares ← somapares + x senão somaimpares ← somaimpares + x leia (x) fim enquanto escreva (somapares , somaimpares) Fim. Estrutura Condicional dentro de Repetições Exercício 15. Escrever um algoritmo 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 número; •somar os números da segunda coluna que tenham um número ímpar na primeira coluna. O total obtido é o produto procurado. Exemplo: 9x6 9 6→ 6 4 12 2 24 1 48→ +48 ___ 54 Estrutura Condicional dentro de Repetições Algoritmo <produto> inteiro: i,a,b,pro Inicio leia (a,b) pro←0 Enquanto (a<>1) faça Se (mod(a,2)<>0) então pro←pro+b /* Acumulador*/ Fim se a←div(a,2) /* atualização de a*/ b←b*2 /* atualização de b*/ Fim enquanto pro ←pro+b /* incluimos o ultimo b que correspondente a a=1*/ Fim Estrutura Condicional dentro de Repetições Exemplo 16: Faça um algoritmo que calcule a soma dos divisores de um número n, exceto ele próprio. Algumas observações se fazem necessárias: (A) Se um número inteiro X possui um divisor Y menor que sua raiz quadrada, o quociente da divisão de X por Y será maior que a raiz quadrada de X e será, também, um divisor de X. (B) Se um número inteiro X possui um divisor Y igual a sua raiz quadrada, o quociente da divisão de X por Y será o próprio divisor Y. Estrutura Condicional dentro de Repetições Algoritmo <somadivisores> inteiro:n, soma,divisor Inicio leia (n) soma←0 divisor←1 Enquanto (divisor<n)) faça Se (mod(n,divisor)=0) então soma←soma+divisor Fim se divisor←divisor+1 Fim enquanto Fim Estrutura Condicional dentro de Repetições Algoritmo <somadivisores> inteiro:n, soma,divisor Inicio leia (n) soma←1 divisor←2 Enquanto (divisor<sqr(n)) faça Se (mod(n,divisor)=0) então soma←soma+divisor+div(n,divisor) Fim se3 divisor←divisor+1 Fim enquanto se (divisor=sqr(n)) soma ←soma+divisor fim se Fim Estrutura Condicional dentro de Repetições Exemplo 17: Faça um algoritmo que determine se um número inteiro n é um número primo. Um número inteiro X é um número primo se ele possui como únicos divisores 1 e ele próprio. Estrutura Condicional dentro de Repetições Algoritmo <numeroprimo> inteiro:n,j ←2 logico:primo Inicio leia (n) primo←1 Enquanto (j<n) faça Se (mod(n,j)=0) entáo primo←0 Fim se j←j+1 Fim enquanto Se (primo) então escreva (“O número é primo”) Fim se Fim Estrutura Condicional dentro de Repetições Exemplo 18: Sejam dois intervalos fechados [a,b] e [c,d], onde a,b,c e d são números inteiros fornecidos pelo usuário com as seguintes condições: a<b, c<d e a<c. Seja também um inteiro n fornecido pelo usuário. Faça um algoritmo que determine se n pertence somente ao intervalo [a,b] ou somente ao intervalo [c,d] ou, se n pertence a ambos ou se n não pertence a nenhum dos dois. Em cada caso imprimir uma mensagem conveniente. Faça a leitura do número n até que seja ingressado o valor N como resposta para a pergunta: Deseja continuar <S/N>? Estrutura Condicional dentro de Repetições Quando temos um único valor n. Algoritmo <pertinencia> inteiro:n,a,b,c,d Inicio leia (a,b,c,d,n) se (n>=c e n<=b) então Escreva (“n pertence a ambos intervalos”) senão se (n>=a e n<=b) então Escreva (“n pertence ao intervalo [a b]”) senão se (n>=c e n<=d) então Escreva (“n pertence ao intervalo [c d]) senão Escreva (“n não pertence a nenhum dos dois intervalos”) Fim se Fim se Fim se Fim Estrutura Condicional dentro de Repetições Faça para vários valores de n conforme pede o enunciado. Combinação de EstruturasEstrutura Repetição dentro de Condicional Agora veremos o contrário da combinação anterior, isto é, um comando de repetição no escopo do comando de desvio condicional. Exercício 19: Imprimir o Maximo Divisor Comum (MDC) entre dois números dados. Combinação de EstruturasEstrutura Repetição dentro de Condicional Exercício 19: Imprimir o Maximo Divisor Comum (MDC) entre dois números dados. O conceito matemático de máximo divisor comum entre dois números dados a e b envolve a fatoração de cada numero como um produto de fatores primos, escolhendose os fatores primos que se repetem com a potência mínima. Exemplo: Calcular o MDC entre 72 e 135. 72 = 2*2*2*3*3 135 = 3*3*3 *5 Da teoria conclui-se que o MDC entre 72 e 135 é 3*3, pois o 3 e o único fator primo que se repete em ambos os números de entrada, e a menor potência comum é 2. Combinação de EstruturasEstrutura Repetição dentro de Condicional Baseado nesse resultado temos que: A ideia é dividir o maior número pelo menor, e depois fazer divisões sucessivas do último divisor pelo último resto, até obtermos uma divisão exata. Exemplo: Estrutura Repetição dentro de Condicional Algoritmo <mdc> inteiro:x, y, resto Inicio leia (x,y) se ((x <> 0) e (y <> 0)) então resto ← mod(x,y) enquanto (resto <> 0) faça x ← y; y ← resto ; resto ← mod(x,y) fim enquanto escreva( “mdc =”, x) senão escreva (“ algoritmo nao funciona para entradas nulas.”) fim Combinação de EstruturasEstrutura Repetição Aninhadas Vamos ver problemas para os quais os algoritmos exigem o aninhamento de repetições. Exercício 20: Imprimir as tabuadas do 1 ao n. Estrutura Repetição Aninhadas Algoritmo <tabuada> inteiro: i , j,n Inicio i←1 leia (n) enquanto (i <= n) faça j←1 enquanto (j <= 10) faça escreva ( i ,'x' , j ,“= ”, i*j ) ; ( comando mais interno ) j←j+1 fim enquanto i←i+1 fim enquanto fim Combinação de EstruturasEstrutura Repetição Aninhadas Exercício 21: Imprimir o valor do fatorial de todos os números entre 1 e n, sendo n fornecido pelo usuário. O fatorial de n e assim definido: n= n x (n -1) x (n - 2) x ... x 3 x 2 x1 No exercício 6 vimos o algoritmo para o fatorial de um único número n e agora veremos o algoritmo para o fatorial de um conjunto de números. Estrutura Repetição Aninhadas Algoritmo <fatorial> /* Fatorial de um único inteiro n*/ inteiro: i , n, fat inicio leia (n) fat ← 1 ( inicializacao do acumulador ) i←n enquanto (i >= 1) faça fat ← fat * i i←i–1 fim enquanto escreva( fat ) fim Estrutura Repetição Aninhadas Algoritmo <fatorial> /* Fatorial de um conjunto de inteiros*/ inteiro: i , n, fat, cont inicio leia (n) cont← 1 enquanto (cont<=n) faça fat ←1 ( inicializacao do acumulador ) i ← cont enquanto (i >= 1) faça fat ← fat * i i←i–1 fim enquanto escreva( fat ) cont ←cont+1 fim enquanto fim Combinação de EstruturasEstrutura Repetição Aninhadas O algoritmo funciona, mas e extremamente ineficiente e repleto de cálculos redundantes. Perceba a seguinte propriedade de fatorial: n!=nx(n-1)! Ou seja quando você calcular o fatorial de n você pode aproveitar o calculo do fatorial do número anterior, isto é, n-1. Assim sendo, temos uma versão mais eficiente do algoritmo anterior. Combinação de EstruturasEstrutura Repetição Aninhadas Algoritmo <fatorial> inteiro: i , n, fat, cont inicio leia (n) cont← 1 fat← 1 enquanto (cont<=n) faça fat ← fat * cont escreva ( fat ) cont ← cont + 1; fim enquanto fim