130 likes | 442 Views
7. 1. 9. 2. 8. 3. 4. 5. 6. 1 2 3 4 5 6 7 8 9 10. 14. 10. 8. 16. 9. 4. 3. 7. 2. 16. 14. 10. 8. 8. 7. 9. 3. 2. 4. 1. Sortowanie: kopce. Parent( i ) return i /2 Left( i ) return 2 i Right( i ) return 2 i+1. 10.
E N D
7 1 9 2 8 3 4 5 6 1 2 3 4 5 6 7 8 9 10 14 10 8 16 9 4 3 7 2 16 14 10 8 8 7 9 3 2 4 1 Sortowanie: kopce Parent(i) return i/2 Left(i) return 2i Right(i) return 2i+1 10 Własność kopca: dla każdego węzła i, który nie jest korzeniem: A[Parent(i)] A[i] 1
Przywracanie własności kopca Zakładamy, że drzewa binarne zaczepione w Left(i) i Right(i) są kopcami, ale A[i] może być mniejszy od swoich synów, przez co narusza własność kopca. Żeby spełniała się własność kopca, stosujemy procedurę Heapify: Heapify(A, i) 1 l := Left(i) 6 ifr heap-size[A] i A[l]> A[i] 2 r := Right(i) 7 thenlargest := r 3 ifl heap-size[A] i A[l]>A[i] 8 iflargest i 4 thenlargest := l 9 then zamień A[i]A[largest] 5 elselargest := i 10 Heapify(A, largest)
3 4 5 1 2 3 5 4 3 2 1 1 2 5 4 14 8 2 14 4 7 4 2 2 14 4 8 7 8 7 6 6 6 1 1 1 c) a) b) Przykład działania procedury Heapify Czas działania Heapify - O(lg n) = O(h) (n - liczba węzłów drzewa, h - wysokość drzewa)
Budowanie kopca Z dowolngo drzewa binarnego można zrobić kopiec w sposób wstępujący (bottom-up) Build-Heap(A) 1 heap-size[A] := length[A] 2 for i:= length[A]/2 downto 1 3 do Heapify(A, i) Czas działania Build-Heap - O(n)
8 2 4 2 2 14 7 1 Sortowanie przez kopcowanie 8 7 4 7 4 1 1 14 8 14 4 4 2 2 1 2 1 1 4 7 8 14 7 8 14 7 8 14 1 2 4 7 8 14
Sortowanie przez kopcowanie Heapsort(A) 1 Build-Heap(A) 2 fori := length[A] downto 2 3 do zamień A[1] A[i] 4heap-size[A] := heap-size[A]-1 5 Heapify(A, 1). Czas działania Heapsort: O(n) + (n-1)O(lg n) = O(n lg n).
Quicksort - sortowanie szybkie Algorytm sortowania szybkiego jest oparty na technice „dziel i zwyciężaj”. Dziel: Tablica A[p…r] jest dzielona na dwie niepuste podtablice A[p…q] i A[q+1…r] takie, że każdy element A[p…q] jest nie większy niż każdy element A[q+1…r]. Zwyciężaj: Dwie podtablice A[p…q] i A[q+1…r] są sortowane za pomocą rekurencyjnych wywołań algorytmu Quicksort. Quicksort(A, p, r) 1 if p < r 2 then q := Partition(A, p, r) 3 Quicksort(A, p, q) 4 Quicksort(A, q+1, r)
5 3 2 8 6 4 1 3 7 i j j j i j i j i i Dzielenie tablicy Partition(A, p, r) 1 x := A[p] 2 i := p - 1 3 j := r + 1 4 while True 5 do repeatj := j - 1 6 untilA[j] x 7 repeati:= i + 1 8 untilA[i] x 9 ifi < j 10 then zamień A[i]A[j] 11 else returnj 5 3 2 6 8 4 1 3 7 3 3 2 8 6 4 1 5 7 3 3 2 8 6 4 1 5 7 3 3 2 1 4 6 5 7
Czas działania Quicksort Najgorszy przypadek podziałów: (n2) Najlepszy przypadek podziałów: (n lg n) Czas działania w średnim przypadku zbliżony jest do najlepszego: (nlgn) n n n n 1 n-1 n n/2 n/2 n n/4 n/4 n/4 n/4 n n 1 n-2 n-1 n lg n 1 2 3 1 1 2 1 1 1 1 1 1 1 1 n Najlepszy przypadek Najgorszy przypadek (nlg n) (n2)
Probabilistyczna wersja Randomized-Partition(A, p, r) 1 i := Random(p, r) 2 zamień A[p] A[i] 3 return Partition(A, p, r) Randomized-Quicksort(A, p, r) 1 ifp < r 2 thenq := Randomized-Partition(A, p, r) 3 Randomized-Quicksort(A, p, q) 3 Randomized-Quicksort(A, q+1, r)
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 A B 3 6 4 1 3 4 4 1 4 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 C C C 2 2 2 2 0 2 2 4 4 3 7 6 0 7 7 8 8 1 Sortowanie przez zliczanie Counting-Sort(A, B, k) 1 fori := 1 tok 2 doC[i] := 0 3 forj := 1 to length[A] 4 doC[A[i]] := C[A[i]] + 1 5 // C[i] zawiera teraz liczbę elementów równych i 6 fori := 2 tok 7 doC[i] := C[i] + C[i-1] 8 // C[i] zawiera liczbę elementów mniejszych lub równych i 9 forj := length[A] downto 1 10 doB[C[A[i]]] := A[i] 11 C[A[i]] := C[A[i]] - 1
Sortowanie pozycyjne Radix-Sort(A, d) 1 fori := 1 tod 2 do posortuj przez zliczanie tablicę A według cyfry I 329 720 720 329 Sortowanie przez zliczanie 457 355 329 355 i sortowanie pozycyjne 657 436 436 436 działają w czasie liniowym 839 457 839 457 436 657 355 657 720 329 457 720 355 839 657 839