|
MC102 |
| LAÇOS ANINHADOS |
Suponha que quiséssemos desenhar um quadrado 10 X 10 de *. Como faríamos?
Faça 10 vezes:
escreva uma linha com 10 *
|
Naturalmente, um programa que use esse algoritmo fucniona:
FOR cont:=1 TO 10 DO writeln('**********');
|
Mas, e se quisermos deixar o tamanho do quadrado como variável?
FOR cont:=1 TO l DO escreva l vezes um *
|
Como escrevemos l vezes um *? Da mesma forma que fizemos os l conjuntos de l *:
faça l vezes:
escreva um *
|
Ou seja:
FOR cont:=1 TO l DO write('*');
|
Então, para nosso quadrado:
FOR cont:=1 TO l DO
BEGIN
FOR cont2 := 1 to l do write('*');
writeln;
END;
|
Rode o programa e veja sua saída. Será um quadrado com o lado que você determinar em l.
Reparou que as duas variáveis contadoras são diferentes? Elas tem que ser diferentes, senão, ao mudarmos o valor de uma, estaremos mudando também o valor da que controla o outro for (pois são a mesma). Por exemplo, veja a execução do seguinte programa, observe o valor das variáveis:
l := 3;
FOR cont:=1 TO l DO
BEGIN
FOR cont := 1 to l do write('*');
writeln
END;
cont
1 do primeiro FOR
1 do segundo FOR
2 do segundo FOR
3 do segundo FOR
saída:
***
|
Por que parou? Porque cont já chegou a l no laço interno (de fato, l é 4), então o laço externo entende que já fez as 3 vezes dele também. Não confunda! Não use a mesma variável!
Mas, e se tivermos 2 laços disjuntos? Aí podemos usar a mesma variável. Quer um exemplo? Vamos desenhar 2 quadrados l X l, um ao lado do outro:
FOR cont:=1 TO l DO
BEGIN
FOR cont2 := 1 TO l DO write('*');
write(' ');
FOR cont2 := 1 TO l DO write('*');
writeln
END;
|
Então posso usar a mesma variável, mas somente para laços disjuntos. No caso acima, a coisa funciona porque quando o segundo FOR interno muda o valor de cont2, o primeiro laço não precisava mais desse valor. Mas se um FOR estiver dentro do outro, então eles não são disjuntos, e não posso usar a mesma variável para ambos os contadors.
E se, agora, quisermos escrever n quadrados de lado l, um ao lado do outro?
FOR cont:=1 TO l DO
BEGIN
FOR cont2 := 1 TO n DO
BEGIN
FOR cont3 := 1 TO l DO write('*');
write(' ')
END;
writeln
END;
saída (n := 3, l := 3):
*** *** ***
*** *** ***
*** *** ***
|
| ITERAÇÕES ANINHADAS |
Vejamos outro exemplo: desenhe o seguinte triângulo:
...*...
..***..
.*****.
*******
|
Primeiro, vamos observar que esse é um retângulo de pontos e asteriscos de tamanho l X (2l-1), onde l é o número de linhas e (2l-1) o de colunas. Então temos uma relação entre as dimensões do retângulo.
Note também que:
para cada linha l, até n linhas faça:
desenhe n-l '.'
desenhe 2l-1 '*'
desenhe n-l '.'
|
E como fazemos isso em pascal?
FOR l:=1 TO n DO
BEGIN
FOR cont := 1 TO (n-l) DO write('.');
FOR cont := 1 TO (2*l-1) DO write('*');
FOR cont := 1 TO (n-l) DO write('.');
writeln
END;
|
Reparou que usei cont para todos? Mais do que isso, notou como os limites dos FOR internos depende do contador do FOR externo? Ou seja, tome o primeiro FOR interno, seu limite é (n-l), ou seja, a cada iteração do FOR externo, o valor de l aumenta, aumentando esse limite. Isso é uma iteração aninhada.
Com isso vemos uma característica do FOR: o ponto de início e o de fim de um laço pode ser qualquer expressão de resultado inteiro.
Note também que quando l valer n, o primeiro e o terceiro FOR interno não serão executados, pois (n-l) será 0, e o final do laço é menor que o início.
| DOWNTO |
Como vimos, o comando FOR incrementa seu contador de forma crescente. Mas, e se quiséssemos decrementar o contador, ou seja, subtrair 1 dele a cada laço, fazendo uma contagem regressiva? Para tal usamos downto:
FOR cont:=10 DOWNTO l DO writeln(cont);
saída:
10
9
8
...
3
2
1
|
Simples não? Vejamos um exemplo, vamos gerar dois triângulos, um em cima do outro, assim:
..*..
.***.
*****
*****
.***.
..*..
|
Como fazemos isso? Usamos o seguinte algoritmo:
escrevemos um triângulo normal
escrevemos um triângulo de cabeça para baixo
|
A primeira parte já vimos como fazer, mas e a segunda? Como desenhamos um triângulo de cabeça para baixo? Vamos primeiro ver como desenhávamos um triângulo normal:
escrevíamos a primeira linha
escrevíamos a segunda linha
...
escrevíamos a n-ésima linha
|
E como fazemos com o invertido?
escrevemos a n-ésima linha
escrevemos a (n-1)-ésima linha
...
escrevemos a primeira linha
|
Ou seja:
FOR l:=n DOWNTO 1 DO
BEGIN
FOR cont := 1 TO (n-l) DO write('.');
FOR cont := 1 to (2*l-1) DO write('*');
FOR cont := 1 to (n-l) DO write('.');
writeln
END;
|
Se antes o FOR não era executado se contador > limite, agora não será se contador < limite. Por exemplo, o seguinte for:
FOR cont:=1 DOWNTO 2 DO write('não vai escrever');
|
não é executado nenhuma vez.