CodeGym /Kursy /JAVA 25 SELF /Zagnieżdżone pętle i ich zastosowania

Zagnieżdżone pętle i ich zastosowania

JAVA 25 SELF
Poziom 4 , Lekcja 5
Dostępny

1. Wprowadzenie

Zacznijmy od pytania: po co w ogóle wkładać jedną pętlę do środka drugiej? Chodzi o to, że nasze dane lub zadania są często zorganizowane nie w jedną linię, lecz na przykład w tabelę, siatkę albo nawet w strukturę wielowymiarową. Załóżmy, że chcesz wyświetlić tabliczkę mnożenia, przejść po tablicy dwuwymiarowej lub policzyć przecięcia między wszystkimi parami elementów. Jeden cykl pętli tu nie wystarczy — potrzebna jest pętla w pętli.

W programowaniu zagnieżdżona pętla to jak dwa budziki: zewnętrzny zaczyna dzwonić, a w jego wnętrzu uruchamia się jeszcze jeden, który będzie dzwonił za każdym razem, gdy pierwszy jest aktywny. Tak więc podczas jednej „zewnętrznej” iteracji wewnętrzna przechodzi całą swoją drogę (i robi to raz po raz dla każdej iteracji zewnętrznej).

Dobry przykład — godziny i minuty. Godziny — to pętla zewnętrzna od 0 do 23, minuty — pętla wewnętrzna od 0 do 59. Na każdą zmianę pętli zewnętrznej wewnętrzna zdąży przebiec wszystkie swoje wartości.

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

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

// Pętla zewnętrzna for
for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 4; j++)  // Pętla wewnętrzna for
    {
        System.out.print(i + "," + j + " ");
    }
    System.out.println(); // Przejście do nowej linii po pętli wewnętrznej
}

Tutaj pętla zewnętrzna steruje 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 pełni od j == 0 do j == 3. Jeśli uruchomisz ten kod, zobaczysz ładną 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 

Analogiczny przykład z użyciem while:

int i = 0;
while (i < 3)
{
    int j = 0;
    while (j < 4)
    {
        System.out.print(i + "," + j + " ");
        j++;
    }
    System.out.println();
    i++;
}

Zwróć uwagę: w każdym przebiegu pętli zewnętrznej zmienna pętli wewnętrznej (j) musi być na nowo inicjalizowana, w przeciwnym razie zobaczymy tylko jeden wiersz!

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

Przykład 1: wypisanie szachownicy (8x8)

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

for (int row = 0; row < 8; row++)
{
    for (int col = 0; col < 8; col++)
    {
        // Jeśli suma indeksów wiersza i kolumny jest parzysta — pole białe, w przeciwnym razie czarne
        if ((row + col) % 2 == 0)
            System.out.print("_");
        else
            System.out.print("#");
    }
    System.out.println(); // Po każdym wierszu nowa linia
}

Wynik:

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

Ważny punkt: zagnieżdżenie zapewnia, że dla każdej linii (row) w pełni przechodzimy po wszystkich kolumnach (col). Bez zagnieżdżenia nie otrzymalibyśmy struktury planszy — tylko jeden wiersz albo jedną kolumnę.

Przykład 2: tabliczka mnożenia

Jeden z klasycznych kandydatów do zagnieżdżonych pętli! Wypiszmy tabliczkę mnożenia 1–9:

for (int i = 1; i <= 9; i++)
{
    for (int j = 1; j <= 9; j++)
    {
        System.out.print(i * j + "\t");
    }
    System.out.println();
}

Formatowanie i * j + "\t" dodaje znak tabulacji, aby 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

W tym miejscu wielu początkujących popełnia błąd! Jeśli używasz break lub continue w pętli wewnętrznej, wpływają one tylko na tę pętlę. Pętla zewnętrzna działa dalej jak gdyby nigdy nic.

Przykład: przedwczesne wyjście tylko z pętli wewnętrznej

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!
        System.out.print(i + "," + j + " ");
    }
    System.out.println();
}

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. pilnie zakończyć wyszukiwanie przy pierwszym udanym dopasowaniu w tabeli), zwykle używa się flagi lub specjalnego zabiegu (np. return — jeśli wszystko dzieje się wewnątrz funkcji).

5. Wizualizacja zagnieżdżonych pętli

Czasem bywa trudno „zobaczyć” sekwencję wykonania zagnieżdżonych pętli. Spójrzmy na następujący schemat blokowy:

nested-loops-scheme

W formie tabeli — ile łącznie iteracji będzie przy i od 1 do 3, j od 1 do 4?

i j (iterowane 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

Częsty błąd — niewłaściwa inicjalizacja zmiennej pętli wewnętrznej. Na przykład zadeklarowanie jej poza pętlą zewnętrzną i brak resetowania na każdym kroku. W rezultacie pętla wewnętrzna może w ogóle się nie wykonywać albo działać niepoprawnie.

int j = 0;
for (int i = 0; i < 3; i++)
{
    while (j < 4) // Ups! j mógł już mieć wartość 4 po pierwszej iteracji.
    {
        System.out.print(i + "," + j + " ");
        j++;
    }
    System.out.println();
}

Tutaj pętla wykona się tylko raz. Pamiętaj, aby inicjalizować zmienne pętli wewnętrznych wewnątrz zewnętrznych!

Ponadto, jeśli przypadkowo napiszesz dwie zagnieżdżone pętle z takimi samymi zmiennymi (for (int i = 0; ...) { for (int i = 0; ...) { ... } }), kompilator zgłosi błąd: zmienna jest już zdefiniowana.

1
Ankieta/quiz
Pętle, poziom 4, lekcja 5
Niedostępny
Pętle
Pętle while, for, do-while
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION