Sortowanie w czasie liniowym

Transkrypt

Sortowanie w czasie liniowym
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