CodeGym /Kursy /C# SELF /Zagnieżdżone pętle i ich zastosowanie

Zagnieżdżone pętle i ich zastosowanie

C# SELF
Poziom 4 , Lekcja 5
Dostępny

1. Wprowadzenie

Zacznijmy od pytania: po co w ogóle wkładać jedną pętlę w drugą? Chodzi o to, że często nasze dane lub zadania są zorganizowane nie tylko w jednej linii, ale np. w tabeli, siatce albo nawet w wielowymiarowej strukturze. Załóżmy, że chcesz wyświetlić na ekranie tabliczkę mnożenia, przejść przez dwuwymiarową tablicę albo policzyć przecięcia między wszystkimi parami elementów. Tutaj jedna pętla to za mało — potrzebujesz pętli w pętli.

W programowaniu zagnieżdżona pętla to jak dwa budziki: zewnętrzny zaczyna dzwonić, a w środku niego uruchamia się jeszcze jeden, który będzie dzwonił za każdym razem, gdy pierwszy jest aktywny. Tak więc, gdy trwa jedna "zewnętrzna" iteracja, wewnętrzna przechodzi całą swoją drogę (i robi to znowu i znowu dla każdej iteracji zewnętrznej).

Dobry przykład — godziny i minuty. Godziny — to zewnętrzna pętla od 0 do 23, minuty — wewnętrzna pętla od 0 do 59. Przy każdej zmianie zewnętrznej pętli wewnętrzna zdąży przelecieć przez wszystkie swoje wartości.

2. Składnia zagnieżdżonych pętli

W C# składnia zagnieżdżonych pętli niczym się nie różni od zwykłych pętli — po prostu piszesz jedną pętlę wewnątrz ciała drugiej. Zobaczmy przykłady z for i while:


for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 4; j++)
    {
        Console.Write($"{i},{j} ");
    }
    Console.WriteLine();
}
Zagnieżdżone pętle for do wyświetlania współrzędnych

Tutaj pętla zewnętrzna kontroluje zmienną i (od 0 do 2), a wewnętrzna — zmienną j (od 0 do 3). Dla każdej wartości i pętla wewnętrzna przechodzi w całości od j=0 do j=3. Jeśli uruchomisz ten kod, zobaczysz fajną tabelkę współrzędnych:

0,0 0,1 0,2 0,3 
1,0 1,1 1,2 1,3 
2,0 2,1 2,2 2,3 

Podobny przykład z użyciem while:

int i = 0;
while (i < 3)
{
    int j = 0;
    while (j < 4)
    {
        Console.Write($"{i},{j} ");
        j++;
    }
    Console.WriteLine();
    i++;
}

Zwróć uwagę: w każdej iteracji zewnętrznej pętli zmienna pętli wewnętrznej (j) musi być zainicjalizowana od nowa, inaczej zobaczysz tylko jeden wiersz!

3. Przykłady działania zagnieżdżonych pętli

Przykład 1: wyświetlanie szachownicy (8x8)

Niech naszym pierwszym zadaniem będzie wyświetlenie na ekranie klasycznej szachownicy w postaci czarnych i białych pól (niech # — czarne, _ — białe). Zróbmy to za pomocą zagnieżdżonych pętli for:


for (int row = 0; row < 8; row++)
{
    for (int col = 0; col < 8; col++)
    {
        if ((row + col) % 2 == 0)
            Console.Write("_");
        else
            Console.Write("#");
    }
    Console.WriteLine();
}
Zagnieżdżone pętle do wyświetlania szachownicy

Wynik:

_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_

Ważny moment: zagnieżdżenie zapewnia, że dla każdego wiersza (row) przechodzimy w całości przez wszystkie kolumny (col). Bez zagnieżdżenia nie dostalibyśmy struktury planszy — tylko jeden wiersz albo jedną kolumnę.

Przykład 2: tabliczka mnożenia

Jeden z klasycznych kandydatów na zagnieżdżone pętle! Wyświetlmy tabliczkę mnożenia 1-9:


for (int i = 1; i <= 9; i++)
{
    for (int j = 1; j <= 9; j++)
    {
        Console.Write($"{i * j,3} ");
    }
    Console.WriteLine();
}
Zagnieżdżone pętle do wyświetlania tabliczki mnożenia

Formatowanie ${i * j,3} dodaje odstępy, żeby tabela wyglądała schludnie.

Wynik:

   1   2   3   4   5   6   7   8   9
  2   4   6   8  10  12  14  16  18 
  3   6   9  12  15  18  21  24  27 
  4   8  12  16  20  24  28  32  36 
...
  9  18  27  36  45  54  63  72  81 

4. Zagnieżdżone pętle i sterowanie nimi — niuanse

O wpływie break i continue w zagnieżdżonych pętlach

Tu wielu początkujących się łapie! Jeśli używasz break albo continue w pętli wewnętrznej, wpływają one tylko na tę pętlę. Zewnętrzna działa dalej jak gdyby nigdy nic.


for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 5; j++)
    {
        if (j == 3)
            break; // wychodzimy tylko z pętli wewnętrznej!
        Console.Write($"{i},{j} ");
    }
    Console.WriteLine();
}
break wychodzi tylko z pętli wewnętrznej

Wynik:

0,0 0,1 0,2 
1,0 1,1 1,2 
2,0 2,1 2,2 

Jeśli musisz wyjść od razu z dwóch zagnieżdżonych pętli (np. natychmiast zakończyć szukanie przy pierwszym trafieniu w tabeli), zwykle używa się flagi lub specjalnego triku (np. return — jeśli wszystko dzieje się w funkcji).

5. Wizualizacja zagnieżdżonych pętli

Czasem trudno "zobaczyć" kolejność wykonywania zagnieżdżonych pętli. Spójrz na ten schemat blokowy:

Wizualizacja zagnieżdżonych pętli

W formie tabelarycznej — ile będzie wszystkich iteracji przy i od 1 do 3, j od 1 do 4?

i j (przeglądane dla każdego i) Iteracji pętli wewnętrznej
1 1, 2, 3, 4 4
2 1, 2, 3, 4 4
3 1, 2, 3, 4 4
Razem: 3 × 4 = 12

6. Błędy i pułapki przy pracy z zagnieżdżonymi pętlami

Popularny błąd — niepoprawna inicjalizacja zmiennej pętli wewnętrznej. Na przykład zadeklarować ją poza pętlą zewnętrzną, ale nie resetować przy każdym kroku. W efekcie pętla wewnętrzna może się w ogóle nie wykonać, albo wykonać się źle.

int j = 0;
for (int i = 0; i < 3; i++)
{
    while (j < 4) // Ups! j mogło już być równe 4 po pierwszej iteracji.
    {
        Console.Write($"{i},{j} ");
        j++;
    }
    Console.WriteLine();
}

Tutaj pętla wykona się tylko raz. Nie zapominaj inicjalizować zmiennych pętli wewnętrznych wewnątrz pętli zewnętrznych!

Również, jeśli przypadkowo napiszesz dwie zagnieżdżone pętle z tymi samymi zmiennymi, kompilator się obrazi: zmienna już została zadeklarowana.


for (int i = 0; i < 3; i++)
{
    for (int i = 0; i < 3; i++)
    {
        Console.Write($"{i},{i} ");
    }
    Console.WriteLine();
}
2
Zadanie
C# SELF, poziom 4, lekcja 5
Niedostępne
Szachownica
Szachownica
2
Zadanie
C# SELF, poziom 4, lekcja 5
Niedostępne
Tabliczka mnożenia
Tabliczka mnożenia
1
Ankieta/quiz
Pętle, poziom 4, lekcja 5
Niedostępny
Pętle
Zagnieżdżone pętle i ich zastosowanie
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION