Sortowanie w czasie liniowym
1
Sortowanie - zadanie Definicja (dla liczb): wejście: ciąg n liczb A = (a1, a2, …, an) wyjście: permutacja (a1,…, 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(N2) zawsze Ø Bąbelkowe: O(N2) najgorszy przypadek; O(N) najlepszy przyp. Ø Wstawianie: O(N2) średnio; O(N) najlepszy przypadek Ø Shellsort:
O(N3/2)
Ø Heapsort:
O(NlogN) zawsze
Ø Mergesort:
O(NlogN) zawsze
Ø Quicksort:
O(NlogN) średnio; O(N2) 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= 4 2 1 3 5
Dla każdego A[i], liczymy elementy ≤ od niego. Daje to rank (pozycję) elementu
Rank = 1 2 3 4 5
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 Rank = 1 2 3
B=
1 2 3
Jeśli nie ma powtórzeń i n < k,
4
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) 1
2
3
4
5
6
7
8
A= 2 5 3 0 2 3 0 3 0
1
2
3
4
5
C[A[j]] ß C[A[j]] +1 po p.4
C= 2 0 2 3 0 1 0
1
2
3
4
5 C[i] ß C[i] + C[i –1] po p. 7
C= 2 2 4 7 7 8 1
2
3
4
5
n=8 k=6
6
7
8
3
B= 0
1
2
C= 2 2 4
3
4
76 7 8
5
B[C[A[j]]] ß A[j] C[A[j]] ß C[A[j]] – 1 po p. 11 11
Sortowanie przez zliczanie – przykład (2) 1
2
3
4
5
6
7
8
A= 2 5 3 0 2 3 0 3 0
1
2
3
4
5
C= 2 2 4 6 7 8 1
2
3
4
5
6
7
3
0
B= 0
1
8
2
3
4
5
C = 21 2 4 6 7 8 12
Sortowanie przez zliczanie – przykład (3) 1
2
3
4
5
6
7
8
A= 2 5 3 0 2 3 0 3 0
1
2
3
4
5
C= 2 2 4 6 7 8 1
2
3
4
5
0
1
7
8
3 3
0
B=
6
2
3
4
5
C = 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
329
720
720
329
457
355
329
355
657
436
436
436
839
457
839
457
436
657
355
657
720
329
457
720
355
839
657
839
16
Radix-Sort – pseudokod
Radix-Sort(A, d) 1. 2.
for i ß 1 to d 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, ai: 1/i ≤ ai ≤ 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 .17 .39 .26 .72 .94 . 21
0
.12
1
.12
2
.21
3
.39
.23
.26
.21 .23
4
.26
5
.39
6
.68
.23
7
.72
.68
8
.12
.17
.17
9
.68 .78
.72 .78
.94
.94 19
Bucket-Sort A[i] tablica wejściowa B[0], B[1], … B[n –1] lista „kubełków”
Bucket-Sort(A) 1. n ß length(A) 2. for i ß 0 to n 3. do wstaw A[i] do listy B[floor(nA[i])] 4. for i ß 0 to n –1 5. do Insertion-Sort(B[i]) 6. Połącz listy B[0], B[1], … B[n –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(n2). Ø Jednak w średnim przypadku stała ilość elementów wpada do jednego przedziału – stąd czas średni wyniesie O(n).
21