Informatyka

Sortowanie bąbelkowe: jak działa algorytm i jak go zapisać

Sortowanie bąbelkowe: porównywanie sąsiadów, przebiegi na przykładzie, kod w Pythonie z flagą zamiany, złożoność O(n²) i porównanie z innymi metodami.

Ilustracja: rząd słupków o różnej wysokości, w którym największe z nich przesuwają się jak bąbelki w stronę końca rzędu
Obraz wygenerowany przez AI

Na czym polega sortowanie bąbelkowe

Polega na porównywaniu dwóch kolejnych elementów i zamianie ich kolejności, jeżeli zaburza ona porządek, w jakim sortuje się tablicę. Cały algorytm to dwie zagnieżdżone pętle:

  1. Przejdź listę od początku, porównując każdą parę sąsiadów.
  2. Jeśli lewy element jest większy od prawego (przy sortowaniu rosnącym), zamień je miejscami.
  3. Po przejściu całej listy największy element jest na końcu, więc kolejny przebieg może go pominąć.
  4. Powtarzaj, aż lista będzie posortowana.

Pseudokod:

dla i od 1 do n-1:
    dla j od 1 do n-i:
        jeśli lista[j] > lista[j+1]:
            zamień lista[j] z lista[j+1]

Przykład krok po kroku

Weź listę [5, 1, 4, 2, 8] i posortuj ją rosnąco.

  • Przebieg 1. Porównania: (5, 1) zamiana, (5, 4) zamiana, (5, 2) zamiana, (5, 8) bez zamiany. Piątka „przepłynęła” w prawo, a 8 już stoi na końcu.
  • Przebieg 2. Ostatni element jest na swoim miejscu, więc porównujesz trzy pary: (1, 4) bez zamiany, (4, 2) zamiana, (4, 5) bez zamiany.
  • Przebieg 3. Dwa porównania, (1, 2) i (2, 4), i żadnej zamiany. Brak zamian oznacza, że lista jest posortowana.

Przesuń tabelę, aby zobaczyć wszystkie kolumny →

PrzebiegPorównaniaZamianyLista po przebiegu
początek––[5, 1, 4, 2, 8]
143[1, 4, 2, 5, 8]
231[1, 2, 4, 5, 8]
320[1, 2, 4, 5, 8]

Razem wyszło 9 porównań i 4 zamiany.

Kod w Pythonie z flagą zamiany

Podstawowa wersja zawsze wykonuje wszystkie przebiegi. Prosta optymalizacja to flaga informująca, czy w danym przebiegu doszło do zamiany: jeśli nie, lista jest już posortowana i pętlę można przerwać.

def bubble_sort(lista):
    n = len(lista)
    for i in range(n - 1):
        zamiana = False
        for j in range(n - 1 - i):
            if lista[j] > lista[j + 1]:
                lista[j], lista[j + 1] = lista[j + 1], lista[j]
                zamiana = True
        print(f"Przebieg {i + 1}: {lista}")
        if not zamiana:
            break

dane = [5, 1, 4, 2, 8]
bubble_sort(dane)
print("Wynik:", dane)

Wynik uruchomienia w Pythonie 3.13:

Przebieg 1: [1, 4, 2, 5, 8]
Przebieg 2: [1, 2, 4, 5, 8]
Przebieg 3: [1, 2, 4, 5, 8]
Wynik: [1, 2, 4, 5, 8]

Wypisane listy zgadzają się z tabelą przebiegów. Zakres wewnętrznej pętli range(n - 1 - i) skraca się z każdym przebiegiem, bo ostatnie i elementów jest już na miejscu. Flaga wydłuża wprawdzie pojedynczy przebieg (trzeba ją wyzerować, ustawić i sprawdzić), ale na liście już posortowanej wystarczy jeden przebieg: bubble_sort([1, 2, 3, 4, 5]) kończy po pierwszym wypisaniu, bo nie zaszła żadna zamiana.

Złożoność i stabilność

Dla listy o n elementach algorytm wykonuje do n − 1 przebiegów, a w każdym kolejnym o jedno porównanie mniej. W sumie daje to rzędu n² porównań, czyli złożoność czasową O(n²). Bez flagi dzieje się tak dla każdego układu danych; z flagą lista już posortowana kończy się po jednym przebiegu (rzędu n porównań). Pamięć dodatkowa to O(1): potrzebna jest tylko zmienna na zamianę i flaga. Sortowanie bąbelkowe jest stabilne, czyli nie zmienia względnej kolejności elementów o równych kluczach, o ile zamieniasz tylko wtedy, gdy lewy element jest ściśle większy od prawego (znak >, nie >=).

Przy podwojeniu liczby elementów liczba porównań rośnie mniej więcej czterokrotnie. Dla kilkudziesięciu elementów różnica jest niewidoczna, dla setek tysięcy staje się wyraźna.

Porównanie z innymi metodami sortowania

Przesuń tabelę, aby zobaczyć wszystkie kolumny →

AlgorytmTypowy czasStabilnyPamięć dodatkowa
BąbelkoweO(n²)takO(1)
Przez wstawianieO(n²)takO(1)
Przez wybieranieO(n²)nie (w typowej wersji)O(1)
Przez scalanieO(n log n)takO(n) w wersji na tablicach
Szybkie (quicksort)średnio O(n log n), w najgorszym przypadku O(n²)zwykle niezwykle O(log n)

Sortowanie przez wstawianie ma ten sam rząd złożoności co bąbelkowe, ale na ogół działa szybciej i jest równie proste, dlatego to ono częściej pojawia się w praktyce i podręcznikach. Metody O(n log n) są dla dużych zbiorów znacznie szybsze. Na co dzień nie pisze się własnego sortowania: wbudowane sorted() i list.sort() w Pythonie korzystają z gotowego, wydajnego algorytmu.

Zobacz też: Schemat blokowy, Matura z informatyki.

Najczęstsze pytania (FAQ)

Czy sortowanie bąbelkowe jest wolne?

Dla dużych zbiorów tak: ma złożoność O(n²), a najlepsze ogólne metody O(n log n). Dla kilkunastu czy kilkudziesięciu elementów różnica jest praktycznie niewidoczna.

Po co się go uczy, skoro jest wolne?

Bo jest najprostsze do zrozumienia i zapisania. Na jego przykładzie poznajesz pętle zagnieżdżone, zamianę elementów, złożoność obliczeniową i stabilność.

Do czego służy flaga zamiany?

Pozwala przerwać sortowanie, gdy w całym przebiegu nie było żadnej zamiany, czyli lista jest już uporządkowana. Dla danych prawie posortowanych oszczędza przebiegi.

Jak posortować malejąco?

Zmień warunek porównania z lista[j] > lista[j + 1] na lista[j] < lista[j + 1]. Wtedy na koniec trafia najmniejszy element.

Czym różni się bubble sort od sortowania bąbelkowego?

Niczym: bubble sort to angielska nazwa tego samego algorytmu.

← Więcej: Informatyka