Sortowanie w czasie liniowym 1
Sortowanie - zadanie Definicja (dla liczb): wejście: ciąg n liczb A = (a 1, a 2,, a n ) wyjście: permutacja (a 1,, a n ) taka, że a 1 a n Po co sortować? Podstawowy problem dla algorytmiki Wiele algorytmów wykorzystuje sortowanie jako procedurę pomocniczą Pozwala pokazać wiele technik Dobrze zbadane (czas) 2
Zestawienie czasów działania Ø Przez wybór: O(N 2 ) zawsze Ø Bąbelkowe: O(N 2 ) najgorszy przypadek; O(N) najlepszy przyp. Ø Wstawianie: O(N 2 ) średnio; O(N) najlepszy przypadek Ø Shellsort: O(N 3/2 ) Ø Heapsort: O(NlogN) zawsze Ø Mergesort: O(NlogN) zawsze Ø Quicksort: O(NlogN) średnio; O(N 2 ) najgorszy przypadek Ø Zliczanie: O(N) zawsze Ø Radix sort: O(N) zawsze Ø zewnętrzne: O(b logb)) dla pliku o b stronach. 3
Przegląd Ø Czy możliwe jest sortowanie w czasie lepszym niż dla metod porównujących elementy (poprzednio najlepsze algorytmy dawały czas O(NlogN))? Ø Algorytmy o liniowym czasie działania: Przez zliczanie (Counting-Sort) Pozycyjne (Radix-Sort) Kubełkowe (Bucket-sort) Ø Potrzeba dodatkowych założeń! 4
Sortowanie o czasie liniowym Ø Możliwe przy dodatkowych informacjach (założeniach) o danych wejściowych. Ø Przykłady takich założeń: Dane są liczbami całkowitymi z przedziału [0..k] i k = O(n). Dane są liczbami wymiernymi z przedziału [0,1) o rozkładzie jednostajnym na tym przedziale Ø Trzy algorytmy: Counting-Sort Radix-Sort Bucket-Sort 5
Zliczanie (Counting sort) wejście: n liczb całkowitych z przedziału [0..k], dla k = O(n). pomysł: dla każdego elementu wejścia x określamy jego pozycje (rank): ilość elementów mniejszych od x. jeśli znamy pozycję elementu umieszczamy go na r+1 miejscu ciągu przykład: jeśli wiemy, że w ciągu jest 6 elementów mniejszych od 17, to 17 znajdzie się na 7 miejscu w ciągu wynikowym. powtórzenia: jeśli mamy kilka równych elementów umieszczamy je kolejno poczynając od indeksu pozycja 6
Zliczanie (Counting sort) A = Rank = 4 2 1 3 5 1 2 3 4 5 Dla każdego A[i], liczymy elementy od niego. Daje to rank (pozycję) elementu B = 1 2 3 4 5 Jeśli nie ma powtórzeń i n = k, Rank[A[i]] = A[i] i B[Rank[A[i]] ß A[i] 7
Zliczanie (Counting sort) A = 5 2 1 3 Jeśli nie ma powtórzeń i n < k, Rank = 1 2 3 4 B = 1 2 3 5 Niektóre komórki tablicy rank pozostają niewykorzystane, ale algorytm działa. 8
Zliczanie (Counting sort) A = 4 2 1 2 3 Jeśli n > k i mamy powtórzenia, Rank = 1 32 4 5 B = 1 2 2 3 4 umieszczamy na wyjściu powtarzające się elementy w takiej kolejności, w jakiej występowały w oryginalnym ciągu (stabilność) 9
Zliczanie (Counting sort) A[1..n] tablica wejściowa B [1..n] tablica wyjściowa C [0..k] pomocnicza tablica (do zliczania) Counting-Sort(A, B, k) 1. for i ß 0 to k 2. do C[i] ß 0 3. for j ß 1 to length[a] 4. do C[A[j]] ß C[A[j]] +1 5. /* C zawiera ilości elementów równych i 6. for i ß 1 to k 7. do C[i] ß C[i] + C[i 1] 8. /* C zawiera ilości elementów i 9. for j ß length[a] downto 1 10. do B[C[A[j]]] ß A[j] 11. C[A[j]] ß C[A[j]] 1 10
Sortowanie przez zliczanie przykład (1) A = C = C = 1 2 3 4 5 6 7 8 2 5 3 0 2 3 0 3 0 1 2 3 4 5 2 0 2 3 0 1 0 1 2 3 4 5 2 2 4 7 7 8 1 2 3 4 5 6 7 8 B = 3 C = 0 1 2 3 4 5 2 2 4 76 7 8 n = 8 k = 6 C[A[j]] ß C[A[j]] +1 po p.4 C[i] ß C[i] + C[i 1] po p. 7 B[C[A[j]]] ß A[j] C[A[j]] ß C[A[j]] 1 po p. 11 11
Sortowanie przez zliczanie przykład (2) A = C = 1 2 3 4 5 6 7 8 2 5 3 0 2 3 0 3 0 1 2 3 4 5 2 2 4 6 7 8 1 2 3 4 5 6 7 8 B = C = 0 3 0 1 2 3 4 5 21 2 4 6 7 8 12
Sortowanie przez zliczanie przykład (3) A = C = 1 2 3 4 5 6 7 8 2 5 3 0 2 3 0 3 0 1 2 3 4 5 2 2 4 6 7 8 1 2 3 4 5 6 7 8 B = C = 0 3 3 0 1 2 3 4 5 1 2 4 65 7 8 13
Counting sort czas działania Ø Pętla for w p.1-2 zajmuje czas Θ(k) Ø Pętla for w p.3-4 zajmuje czas Θ(n) Ø Pętla for w p.6-7 zajmuje czas Θ(k) Ø Pętla for w p.9-11 zajmuje czas Θ(n) Ø Stąd dostajemy łączny czas Θ(n+k) Ø Ponieważ k = O(n), T(n) = Θ(n) à algorytm jest optymalny!! Ø Konieczne jest założenie k = O(n). Jeśli k >> n to potrzeba to potrzeba dużej ilości pamięci. Ø Nie jest to sortowanie w miejscu. 14
Radix sort sortowanie pozycyjne wejście: n liczb całkowitych, d-cyfrowych, łańcuchów o d-pozycjach pomysł: zajmować się tylko jedną z cyfr (sortować względem kolejnych pozycji cyfr/znaków). Zaczynamy od najmniej znaczącej cyfry/ znaku, potem kolejne pozycje (cyfry/znaki), aż do najbardziej znaczącej. Musimy stosować metodą stabilną. Ponieważ zbiór możliwych wartości jest mały (cyfry 0-9, znaki a - z ) możemy zastosować metodę zliczania, o czasie O(n) Po zakończeniu ciąg będzie posortowany!! 15
Radix sort przykład 3 2 9 7 2 0 7 2 0 3 2 9 4 5 7 3 5 5 3 2 9 3 5 5 6 5 7 4 3 6 4 3 6 4 3 6 8 3 9 4 5 7 8 3 9 4 5 7 4 3 6 6 5 7 3 5 5 6 5 7 7 2 0 3 2 9 4 5 7 7 2 0 3 5 5 8 3 9 6 5 7 8 3 9 16
Radix-Sort pseudokod Radix-Sort(A, d) 1. for i ß 1 to d 2. do zastosuj stabilną metodę sortowania do cyfry d dla tablicy A uwagi: złożoność: T(n) = Θ(d(n+k)) à Θ(n) dla stałego d i k = O(1) wartości cyfr/znaków są z zakresu [0..k 1] dla k = O(1) Metoda stosowana dla poszczególnych pozycji musi być stabilna! 17
Sortowanie kubełkowe Bucket sort wejście: n liczb rzeczywistych z przedziału [0..1) ważne jest, aby były równomiernie rozłożone (każda wartość równie prawdopodobna) pomysł: dzielimy przedział [0..1) na n podprzedziałów ( kubełków ):0, 1/n, 2/n. (n 1)/n. Elementy do odpowiednich kubełków, a i : 1/i a i 1/(i+1). Ponieważ rozkład jest równomierny to w żadnym z przedziałów nie powinno znaleźć się zbyt wiele wartości. Jeśli wkładamy je do kubełków zachowując porządek (np. przez wstawianie Insertion-Sort), dostaniemy posortowany ciąg. 18
Bucket sort przykład.78 0.12.17 1.12.17.17.39.26.72.94. 21 2 3 4 5.21.39.23.26.21.23.26.39.12 6.68.68.23 7.72.78.72.68 8.78 9.94.94 19
Bucket-Sort A[i] tablica wejściowa B[0], B[1], B[k 1] lista kubełków Bucket-Sort(A) 1. n ß length(a) 2. for i ß 0 to k 3. do wstaw A[i] do listy B[floor(kA[i])] 4. for i ß 0 to k 1 5. do Insertion-Sort(B[i]) 6. Połącz listy B[0], B[1], B[k 1] 20
Bucket-Sort złożoność czasowa Ø Wszystkie instrukcje z wyjątkiem 5 (Insertion-Sort) wymagają czasu O(n), w przypadku pesymistycznym. Ø W przypadku pesymistycznym, O(n) liczb trafi do jednego kubełka czyli ich sortowanie zajmie czas O(n 2 ). Ø Jednak w średnim przypadku ilość elementów wpadających do jednego przedziału wynosi n/k stąd czas średni wyniesie O(n). 21