MC102
Algoritmos e Programação de Computadores
Parte VI



Norton Trevisan Roman




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:

Ótimo! Temos uma fórmula. Então vamos ao algoritmo:
    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.





‹— Parte VPágina da disciplinaParte VII —›