Sortowanie danych

Sortowanie danych – przykład na tablicy wielowymiarowej (C++)

Sortowanie to jedna z najczęstszych operacji na danych: chcemy uporządkować rekordy rosnąco/malejąco według wybranego kryterium (np. nazwiska, wyniku, wieku, ceny). W praktyce dane często mają postać „rekordów” z wieloma polami – można je zapisać jako:

  • tablicę struktur (bardziej „C++-owo”), albo

  • tablicę wielowymiarową (2D), gdzie każdy wiersz to rekord, a kolumny to pola.

W tym przykładzie użyjemy tablicy 2D int dane[N][M], gdzie:

  • dane[i][0] = ID

  • dane[i][1] = wynik (po nim sortujemy)

  • dane[i][2] = wiek (dodatkowe pole)

Na czym polega sortowanie bąbelkowe?

Sortowanie bąbelkowe (bubble sort) działa tak:

  1. Przechodzi po tablicy i porównuje sąsiadujące elementy.

  2. Jeśli są w złej kolejności, zamienia je miejscami.

  3. Po jednej pełnej rundzie największa wartość „wypływa” na koniec (jak bąbelek).

  4. Powtarza rundy, aż całość będzie posortowana.

To algorytm prosty do nauki i debugowania, ale ma słabą wydajność dla dużych danych (zwykle O(n²)).

#include <iostream>

#include <iomanip>

using namespace std;

const int N = 6; // liczba rekordów (wierszy)

const int M = 3; // liczba pól (kolumn): ID, wynik, wiek

void wypiszTablice(const int t[N][M]) {

    cout << "  [ID, wynik, wiek]\n";

    for (int i = 0; i < N; i++) {

        cout << "  ";

        for (int j = 0; j < M; j++) {

            cout << setw(4) << t[i][j] << (j < M - 1 ? " " : "");

        }

        cout << "\n";

    }

}

int main() {

    // Tablica wielowymiarowa: każdy wiersz to rekord [ID, wynik, wiek]

    int dane[N][M] = {

        {101,  72, 17},

        {102,  55, 16},

        {103,  88, 18},

        {104,  55, 17},

        {105,  61, 16},

        {106,  90, 19}

    };

    cout << "Dane poczatkowe:\n";

    wypiszTablice(dane);

    cout << "\nSortowanie bombelkowe po kolumnie 'wynik' (rosnaco).\n\n";

    // Bubble sort po kolumnie 1 (wynik)

    for (int pass = 0; pass < N - 1; pass++) {

        bool swapped = false;

        cout << "=== Runda " << pass + 1 << " ===\n";

        for (int i = 0; i < N - 1 - pass; i++) {

            cout << "Porownuje wiersz " << i << " (wynik=" << dane[i][1]

                 << ") z wierszem " << i + 1 << " (wynik=" << dane[i + 1][1] << ")... ";

            if (dane[i][1] > dane[i + 1][1]) {

                cout << "ZAMIANA!\n";

                // zamiana calego rekordu (calego wiersza)

                for (int col = 0; col < M; col++) {

                    int tmp = dane[i][col];

                    dane[i][col] = dane[i + 1][col];

                    dane[i + 1][col] = tmp;

                }

                swapped = true;

                cout << "Stan po zamianie:\n";

                wypiszTablice(dane);

            } else {

                cout << "OK (bez zmiany)\n";

            }

        }

        cout << "Koniec rundy " << pass + 1 << ", stan tablicy:\n";

        wypiszTablice(dane);

        cout << "\n";

        if (!swapped) {

            cout << "Brak zamian w tej rundzie -> tablica juz posortowana. Koniec.\n";

            break;

        }

    }

    cout << "Wynik koncowy (posortowane po 'wynik' rosnaco):\n";

    wypiszTablice(dane);

}

Można to też zrobić prościej

#include <algorithm>
#include <vector>
#include <iostream>

int main() {
std::vector<int> v = {5, 2, 4, 1, 3};
std::sort(v.begin(), v.end());

for (const auto& x : v) {
std::cout << x << "\n";
}

}



std::vector<std::vector<int>> m = {{5,2,4},{1,3,0},{9,8,7}};

// sortuj każdy wiersz

for (auto& row : m) {

    std::sort(row.begin(), row.end());

}

 

Pytania do artykułu / kodu (z odpowiedziami)

  1. Co oznacza, że użyliśmy tablicy wielowymiarowej 2D int dane[N][M]?

    Odp.: To tabela wierszy i kolumn. Każdy wiersz to rekord, a każda kolumna to jedno pole rekordu (np. ID, wynik, wiek).

  2. Która kolumna w przykładzie jest kluczem sortowania i jak to widać w kodzie?

    Odp.: Kolumna 1 (wynik). W porównaniu używamy dane[i][1] > dane[i+1][1].

  3. Dlaczego podczas zamiany w bubble sort zamieniamy cały wiersz, a nie tylko wynik?

    Odp.: Bo rekord musi pozostać spójny. Jeśli zamienilibyśmy tylko wyniki, to ID i wiek „przykleiłyby się” do złych osób.

  4. Ile rund wykona bubble sort w najgorszym przypadku dla N elementów?

    Odp.: Maksymalnie N-1 rund.

  5. Po co jest warunek i < N – 1 – pass w pętli wewnętrznej?

    Odp.: Po każdej rundzie największy element trafia na koniec, więc nie trzeba go już porównywać w kolejnych rundach.

  6. Co oznacza zmienna swapped i czemu przyspiesza program?

    Odp.: Informuje, czy w danej rundzie była jakakolwiek zamiana. Jeśli nie było zamian, tablica jest już posortowana i można przerwać.

  7. Jak rozpoznać w konsoli, że nastąpiła zamiana?

    Odp.: Pojawia się komunikat ZAMIANA! oraz wypisywany jest stan tablicy „Stan po zamianie”.

  8. Jaka jest złożoność czasowa bubble sort i co to oznacza praktycznie?

    Odp.: Zwykle O(n²) — dla dużych danych działa wolno, bo liczba porównań rośnie kwadratowo.

  9. Czy bubble sort jest stabilny i co to znaczy w tym kontekście?

    Odp.: Tak (w typowej wersji z warunkiem >). Stabilny znaczy, że elementy o takim samym kluczu (np. wynik=55) zachowują swoją kolejność względem siebie.

  10. Jak zrobić sortowanie malejące w tym kodzie?

    Odp.: Zmienić warunek na dane[i][1] < dane[i+1][1].


Podsumowanie

W przykładzie dane zostały zapisane jako tablica 2D, gdzie każdy wiersz to jeden rekord (ID, wynik, wiek). Następnie zastosowaliśmy sortowanie bąbelkowe, które porównuje sąsiednie rekordy i w razie potrzeby zamienia całe wiersze, aby nie pomieszać pól rekordu. Dzięki wypisywaniu informacji w konsoli można łatwo śledzić porównania, zamiany oraz stan tablicy po każdej rundzie. Bubble sort jest prosty i świetny do nauki, ale dla dużych zbiorów danych jest mało wydajny (O(n²)).

Zostaw komentarz

Koszyk