Przeczytaj
Sortowanie kubełkowekubełkowe należy do algorytmów, które porządkują dane w czasie liniowym. Sortowane dane powinny być liczbami całkowitymi, może być ich wiele, jednak ich zakres nie powinien być zbyt duży.
Zasada działania algorytmu – liczby całkowite
Jak sama nazwa wskazuje, w algorytmie posługujemy się kubełkami. Pracę rozpoczynamy od ustalenia, ilu ich potrzebujemy. W tym celu wyszukujemy w sortowanej tablicy największą oraz najmniejszą wartość. Oznaczamy je jako oraz . Wartości te definiują liczbę kubełków . Potrzebujemy osobnego kubełka dla każdej liczby całkowitej w przedziale , co opisane jest wzorem:
Atrybutem każdego kubełka jest indeks odpowiadający konkretnej liczbie z sortowanej tablicy. Rozpoczynamy od pierwszego kubełka, nadając mu indeks , a kończymy na ostatnim, któremu przydzielimy indeks .
Przyjmujemy, że każdy kubełek początkowo przechowuje liczbę 0, jednak docelowo wartość ta ma przedstawiać liczbę wystąpień danego składnika sortowanej tablicy. Po kolei odczytujemy liczbę powtórzeń poszczególnych elementów i aktualizujemy liczbę elementów umieszczonych w kubełkach.
Ostatnim krokiem jest zapełnianie tablicy wynikowej. Wpisujemy indeksy kolejnych kubełków do tablicy tyle razy, ile wynosi wartość danego kubełka. Rozpoczynamy od indeksu , a kończymy na . W rezultacie tej operacji otrzymujemy posortowaną tablicę.
Używając algorytmu sortowania kubełkowego, posortujemy niemalejąco zbiór . Wartości oraz prezentują się następująco:
Obliczamy, ilu kubełków potrzebujemy.
Jako oznaczenie kubełków przyjmiemy . Wartość każdego z nich początkowo równa jest 0.
Ustalamy liczbę wystąpień kolejnych składników zbioru.
Liczba 0 występuje jeden raz, zatem kubełek przyjmuje wartość 1.
Liczba 1 występuje dwa razy, zatem kubełek przyjmuje wartość 2.
Liczba 2 nie występuje ani razu, zatem kubełek przyjmuje wartość 0 itd.
W konsekwencji otrzymujemy następujące kubełki:
Możemy teraz posortować liczby na podstawie wartości kubełków, rozpoczynając od . Wartości z kubełków oznaczają, ile razy ma wystąpić liczba podana jako indeks kubełka. Wpisujemy do wynikowej tablicy odpowiednio jedną liczbę 0, dwie liczby 1 itd. Dopiero z niej wypisujemy posortowany zbiór:
Wróćmy do kwestii dużej różnicy między maksymalną i minimalną wartością sortowanego zbioru. Załóżmy, że do posortowania mamy następujący zbiór: . Wartości oraz prezentują się następująco:
Ustalamy, ilu kubełków potrzebujemy:
Pomimo że mamy do posortowania tyle samo elementów co w przykładzie 1, znacząco zwiększa się liczba kubełków, które należy utworzyć. Co powoduje, że zajmujemy więcej zasobów obliczeniowych komputera.
Nie zawsze w danym kubełku przechowujemy jedną liczbę. Istnieje możliwość stworzenia kubełków zawierających elementy tablicy z wybranych przedziałów (wszystkie przedziały muszą być tej samej długości). Wówczas wewnątrz każdego z kubełków należy wykonać osobno proces sortowania. Można do tego użyć dowolnego algorytmu sortującego. W ostatnim kroku wpisujemy po kolei posortowane wartości z kubełków do tablicy.
Pseudokod
Zapiszmy algorytm sortowania kubełkowego dla liczb całkowitych za pomocą pseudokodu.
Specyfikacja problemu:
Dane:
n
– liczba elementów w tablicytab
do posortowaniatab[0..n‑1]
– tablica liczb całkowitych zawierająca dane do posortowania
Wynik:
tab[0..n‑1]
– tablica liczb całkowitych posortowana niemalejąco
Ustalmy teraz liczbę kubełków potrzebnych do wykonania algorytmu. Skorzystamy z przywoływanego już wzoru, a wynik zapiszemy w zmiennej k
. Wymagane do tego będzie wskazanie wartości minimalnej oraz maksymalnej, które znajdują się w tablicy tab
.
Następnie tworzymy kubełki i przypisujemy im domyślną wartość 0.
Zliczamy, ile razy dana wartość występuje w wejściowej tablicy tab
. Ustalamy, w którym kubełku należy zapisać informację o liczbie wystąpień danej liczby. Odejmiemy od każdej rozpatrywanej liczby wartość zmiennej xmin
, co spowoduje zapisanie liczby wystąpień najmniejszej liczby w tablicy w kubełku o indeksie 0, drugiej najmniejszej do kubełka o indeksie 1 itd. Dla każdej liczby dokonujemy inkrementacji wartości znajdującej się w przypisanym do niej kubełku.
Wypełniamy tablicę posortowanymi liczbami. Odczytujemy, ile razy wystąpił dany element, a następnie tyle razy wypisujemy go do wynikowej tablicy.
Implementacja algorytmu sortowania kubełkowego zapisana za pomocą pseudokodu prezentuje się następująco:
Złożoność czasowa algorytmu
Ważną cechą każdego algorytmu jest jego złożoność czasowazłożoność czasowa, która pozwala porównywać między sobą różne metody obliczeniowe. Aby ją oszacować, nie mierzy się czasu wykonywania algorytmu, który zależny jest od implementacji i sprzętu, lecz wyróżnia się jakąś operację dominującą. Liczba wykonanych operacji dominujących zależy od rozmiaru wejścia, można więc powiedzieć, że złożoność czasowa to pewna funkcja danych wejściowych. Rząd wielkości tej funkcji wyrażającej liczbę operacji dominujących zapisuje się za pomocą notacji dużego O.
W przypadku przedstawionego wcześniej algorytmu sortowania kubełkowego rozmiarem wejścia będzie liczba elementów w tablicy wejściowej, którą oznaczymy jako , oraz liczba kubełków – .
Operacje dominujące w przedstawionym algorytmie:
Podczas wyszukiwania elementu minimalnego i maksymalnego operacją dominującą jest porównanie, trzeba wykonać operacji.
Podczas przygotowywania kubełków operacją dominującą jest przypisanie, trzeba wykonać takich operacji.
Podobnie zliczenie wystąpień również wymaga operacji przypisania.
Przepisanie liczb do tablicy wynikowej wymaga sprawdzenia (operacja porównania) kubełków i wykonania przypisań, daje to: operacji.
Funkcję wyrażającą liczbę operacji dominujących możemy więc zapisać jako . Ponieważ przy zapisie oszacowania pomijamy stałe, ostatecznie mamy do czynienia ze złożonością liniową .
Jeżeli elementów będzie dużo, ale o małym zakresie wartości ( znacznie większe niż ), to algorytm będzie działał w czasie liniowym ze względu na liczbę elementów w tablicy tab
: .
Natomiast w przypadku odwrotnym, czyli gdy będzie do posortowania mało elementów, ale z dużego zakresu wartości, algorytm będzie działał w czasie liniowym ze względu na zakres wartości: .
Zasada działania algorytmu – liczby rzeczywiste
Zapoznaj się z algorytmem sortowania kubełkowego liczb rzeczywistych z przedziału . Przeanalizuj kolejne jego kroki, a następnie zastanów się nad różnicami pomiędzy sortowaniem liczb całkowitych i zmiennoprzecinkowych.
Pseudokod
Zapiszmy algorytm sortowania kubełkowego dla liczb rzeczywistych za pomocą pseudokodu.
Specyfikacja problemu:
Dane:
n
– liczba elementów w tablicytab
do posortowaniatab[0..n‑1]
– tablica liczb rzeczywistych z przedziału zawierająca dane do posortowania
Wynik:
tab[0..n‑1]
– tablica liczb rzeczywistych posortowana niemalejąco
Przyjmujemy także, że kubełków jest 10. Każdy z nich będzie listą (tablicą z możliwością dowolnego jej rozszerzania) i zawierał będzie liczby z przedziału dla . Tworzymy zatem te kubełki.
Następnie każdą liczbę z sortowanej tablicy tab
umieszczamy w odpowiadającym jej kubełku.
Jako algorytm pomocniczy implementujemy sortowanie bąbelkowesortowanie bąbelkowe.
Wykorzystując sortowanie bąbelkowe, sortujemy każdy kubełek osobno.
Na koniec przepisujemy liczby z kolejnych kubełków do tablicy wynikowej.
Cały algorytm zapisany za pomocą pseudokodu prezentuje się następująco:
Słownik
podprzedział wyodrębniony z sortowanego zbioru danych
czynność polegająca na uporządkowaniu danych w zbiorze względem danego kryterium
ilość czasu potrzebnego do wykonania zadania, wyrażona jako funkcja ilości danych
ilość zasobów komputerowych potrzebnych do wykonania zadania