Præsentation er lastning. Vent venligst

Præsentation er lastning. Vent venligst

1 Sortering II. 2 Plan Avancerede sorteringsmetoder: Metoder med kompleksitet O(n logn): - Quicksort (ekskurs: udvælgelse) - Sortering ved fletning ----------------------------------------------------------

Lignende præsentationer


Præsentationer af emnet: "1 Sortering II. 2 Plan Avancerede sorteringsmetoder: Metoder med kompleksitet O(n logn): - Quicksort (ekskurs: udvælgelse) - Sortering ved fletning ----------------------------------------------------------"— Præsentationens transcript:

1 1 Sortering II

2 2 Plan Avancerede sorteringsmetoder: Metoder med kompleksitet O(n logn): - Quicksort (ekskurs: udvælgelse) - Sortering ved fletning ---------------------------------------------------------- - Hob-sortering (prioritetskøer) En metode med kompleksitet O(n): - Radixsortering

3 3 Quicksort (Hoare, 1960) Quicksort er i praksis den hurtigste algoritme til intern sortering. Desuden er den forholdsvis let at implementere. Ide: For at sortere et array, så del det i en venstre og en højre del, således at alle elementer i den venstre del er mindre end alle elementer i den højre del. venstre delhøjre del ≤ Sorter derefter den venstre del og den højre del rekursivt.

4 4 Deling (partition) Delingen af et array a kan foretages således: (1)Vælg en delingsværdi, v, blandt værdierne i a. (2)Gennemløb a fra venstre mod højre, indtil der findes et element a[i] ≥ v. (3)Gennemløb a fra højre mod venstre, indtil der findes et element a[j] ≤ v. (4) Ombyt a[i] og a[j]. (5)Fortsæt med at gennemløbe og ombytte, indtil de to gennemløb “krydser” hinanden.

5 5 v: delingsværdien i: venstre-mod-højre-pegeren j: højre-mod-venstre-pegeren i j ≤ v ≥ v a[i] ≥ va[j] ≤ v XY i j ≤ v≥ vYX ≤ v≥ v

6 6 Deling af a[l:r] med hensyn til v : i = l; j = r; while (i <= j) { while (a[i] < v) i++; while (a[j] > v) j--; if (i <= j) { swap(a, i, j); i++; j--; } } Implementering Resultat: a[l:j] ≤ a[i:r] og i > j. Kan bevises ved at påvise gyldigheden af løkkeinvarianten { a[l:i-1] ≤ v ≤ a[j+1:r] } for den yderste løkke.

7 7 void quicksort(int a[], int l, int r) { if (l < r) { int v = a[(l+r)/2]; int i = l, j = r; while (true) { while (a[i] < v) i++; while (a[j] > v) j--; if (i >= j) break; swap(a, i, j); i++; j--; } quicksort(a, l, j); quicksort(a, i, r); } Quicksort Delingsværdien v kan være værdien af et vilkårligt element blandt a[l:r], f.eks. a[(l+r)/2].

8 8 int partition(int a[], int l, int r) { int v = a[r]; int i = l-1, j = r; while (true) { while (a[++i] < v) ; while (a[--j] > v) if (j == l) break; if (i >= j) break; swap(a, i, j); } swap(a, i, r); return i; } Sedgewicks implementation Sætningen ‘ if (j == l) break ’ kan fjernes ved brug af “stopklods” (eng. sentinel), a[l-1] ≤ a[l..r]. Sedgewick anvender a[r] som delingsværdi. a[l:r-1] deles, hvorefter a[r] ombyttes med a[i].

9 9 int quicksort(int a[], int l, int r) { if (l < r) { int i = partition(a, l, r); quicksort(a, l, i-1); quicksort(a, i+1, r); } Metoden quicksort

10 10 Animering af Quicksort

11 11 Antal sammenligninger Lad C(N) betegne antallet af sammenligninger ved kald af quicksort med N elementer (N = r-l+1 ). Ved delingen foretages cirka N sammenligninger. Herefter sorteres den venstre del og den højre del hver for sig. I gennemsnit består hver del af cirka N/2 elementer, og får vi derfor rekursionsrelationen: C(N) = N + 2*C(N/2) for N ≥ 2, og C(1) = 0. som har løsningen C(N) = Nlog 2 N.

12 12 Mere præcise beregninger giver Quicksort bruger i gennemsnit cirka 2N lnN sammenligninger. hvor ln betegner den naturlige logaritme. Antal sammenligninger i gennemsnit 2N ln N ≈ 1.39 N log 2 N Det gennemsnitlige antal sammenligninger er altså kun 39% højere end antallet af sammenligninger i det bedste tilfælde.

13 13 Antal sammenligninger i værste tilfælde Det værste tilfælde optræder, når delingen for hvert N resulterer i en del med 1 element og en del med N-1 elementer. Vi få da C(N) = N + C(N-1), for N ≥ 2, og C(1) = 0. som har løsningen C(N) = N(N+1)/2. Det værste tilfælde optræder med Sedgewicks implementation, når filen er sorteret (eventuelt i omvendt orden). Valg af tilfældigt delingselement (eller “median af 3”) reducerer chancen for, at det værste tilfælde optræder.

14 14 Quicksort med median af 3 lmrr-1 void quicksort(int a[], int l, int r) { if (l < r) { if (a[l] > a[r]) swap(a, l, r); int m = (l+r)/2; if (m == l) return; if (a[l] > a[m]) swap(a, l, m); if (a[m] > a[r]) swap(a, m, r); swap(a, m, r-1); int i = partition(a, l+1, r-1); quicksort(a, l, i-1); quicksort(a, i+1, r); }

15 15 Kravet til ekstra plads er proportionalt med den maksimale stakdybde for de rekursive kald af quicksort. I værste fald kan stakdybden blive N. Nemlig når enhver deling bevirker, at den højre del består af 1 element. Kravet til stakplads kan mindskes (til log 2 N) ved altid først at sortere den mindste af de to dele: Pladskrav if (i-l > r-i) { quicksort(a, i+1, r); quicksort(a, l, i-1); } else { quicksort(a, l, i-1); quicksort(a, i+1, r); } Dog kun under forudsætning af, at der automatisk foretages elimination af halerekursion.

16 16 Quicksort er relativt langsom for små filer, bl.a. på grund af de rekursive kald. Rekursionen kan helt fjernes (ved brug af eksplicit stak). Fjernelse af rekursion void quicksort(int a[], int l, int r) { Stack s = new Stack(50); while (true) { while (l < r) { int i = partition(a, l, r); if (i-l > r-i) { s.push2(l, i-1); l = i+1; } else { s.push2(i+1, r); r = i-1; } } if (s.empty()) return; r = s.pop(); l = s.pop(); }

17 17 Benyt en simpel metode for små delfiler Langt mere effekt har anvendelse af ‘sortering ved indsættelse’ for “relativt små” delfiler. if (r-l <= M) insertion(a, l, r);else indsættes i stedet for if (l < r) i starten af quicksort, hvor M f.eks. er 10. Bedre er dog at vente med insertion -sorteringen: quicksort(a, 1, N); insertion(a, 1, N);

18 18 Animering af quicksort (ignorering af små delfiler)

19 19 Tid i sekunder: Metode N = 32000 64000 128000 256000 512000 1024000 quicksort1 0.03 0.05 0.09 0.19 0.39 0.85 quicksort2 0.03 0.05 0.09 0.20 0.42 0.90 quicksort3 0.03 0.05 0.09 0.18 0.39 0.85 quicksort4 0.03 0.05 0.09 0.17 0.36 0.76 shellsort 0.04 0.08 0.18 0.41 1.03 2.37 insertion 6.59 27.24 114.14 ≈ 8 min ≈ 32 min ≈ 2 timer quicksort1: Min version quicksort2: Sedgwicks version quicksort3: insertion -sort for små delfiler (M = 10). quicksort4: quicksort3 med median af 3 Empirisk undersøgelse af Quicksort (PowerBook G3, 400 MHz, Metrowerks)

20 20 Udvælgelse Problem: Find det k’te mindste element blandt en mængde af N elementer. Eksempel: Det 3. mindste tal blandt {3, 6, 5, 2, 8, 4} er 4. Løsningsmulighed 1: Sorter elementerne i stigende orden. Det k´te element i den sorterede rækkefølge er løsning på problemet. Kompleksitet: afhænger af sorteringsmetode - med quicksort: O(N log N).

21 21 Løsningsmulighed 2: Hvis k er lille, så anvend sortering ved udvælgelse, men stop, når de første k elementer er på plads. Kompleksitet: O(k N), idet N + (N-1) + … + (N - k + 1) ≈ k N Løsningsmulighed 3: Anvend en ”hob” (en datastruktur til repræsentation af prioritetskøer - mere herom senere). Kompleksitet: O(N log k) Kan vi gøre det bedre?

22 22 Udvælgelse ved brug af partition Metoden omordner a, så a[l:k-1] ≤ a[k] ≤ a[k+1:r]. void select(ItemType a[], int l, int r, int k) { if (l < r) { int i = partition(a, l, r); if (i > k) select(a, l, i-1, k); if (i < k) select(a, i+1, r, k); } Da der kun benyttes halerekursion, kan rekursionen let elimineres: void select(ItemType a[], int l, int r, int k) { while (l < r) { int i = partition(a, l, r); if (i >= k) r = i-1; if (i <= k) l = i+1; } OBS. Fejl i lærebogens kode på side 127!

23 23 O(N) i gennemsnit, idet N + N/2 + N/4 + … ≤ 2N. Det er muligt (men ikke helt let) at sørge for garanteret lineær køretid. Kompleksitet af select

24 24 void sort(int a[], int l, int r) { if (l < r) { // Del: Del a[l:r] i to delfiler, a[l:i] og a[j:r], hvor i ≥ j. // Hersk: sort(a, l, i); sort(a, j, r); // Kombiner:Sammensæt de to sorterede delfiler, så de // udgør en sortering af a[l:r]. } Sortering ved del-og-hersk Mergesort (sortering ved fletning): Del: i = (l+r)/2; j = i+1; Kombiner: Flet de to delfiler og placer resultatet i a[l:r]. Quicksort: Del: Vælg en værdi, v. Ombyt elementerne i a[l:r], således at a[l:i] ≤ v ≤ a[j:r] og i ≥ j. Kombiner : Intet.

25 25 Fletning k c: 1M+N ≤ i a: M1 ≤ ≤ j b: 1N ≤ ≤ for (i = j = k = 1; k <= M+N; k++) if (i > M) c[k] = b[j++]; else if (j > N) c[k] = a[i++]; else c[k] = a[i] < b[j] ? a[i++] : b[j++];

26 26 for (i = j = k = 1; k <= M+N; k++) c[k] = a[i] < b[j] ? a[i++] : b[j++]; Forenkling Løkken kan forenkles ved at benytte to ”stopklodser” : a[M+1] ≥ max( a[M],b[N]) b[N+1] ≥ max( a[M],b[N])

27 27 void mergesort(int a[], int l, int r) { if (l < r) { int m = (l+r)/2; mergesort(a, l, m); mergesort(a, m+1, r); merge(a, l, m, r); } mergesort

28 28 void merge(int a[], int l, int m, int r) { int i = l, j = m+1, k; for (k = l; k <= r; k++) if (i > m) b[k] = a[j++]; else if (j > r) b[k] = a[i++]; else b[k] = a[i] < a[j] ? a[i++] : a[j++]; for (k = l; k <= r; k++) a[k] = b[k]; } Fletning af a[l:m] med a[m+1:r] over i a[l:r] : Simpel fletning lmm+1r ≤≤ a:a: ≤ b:b: l r Fletning: ≤ a:a: l r Kopiering:

29 29 A S O R T I N G E X A M P L E A S O R A O R S I T G N G I N T A G I N O R S T E X A M A E M X L P E L P A E E L M P X A A E E G I L M N O P R S T X

30 30 void mergesort(int a[], int l, int r) { if (r > l) { int m = (l+r)/2, i, j, k; mergesort(a, l, m); mergesort(a, m+1, r); for (i = l; i <= m; i++) b[i] = a[i]; for (j = r; j > m; j--) b[m+1+r-j] = a[j]; for (k = l; k <= r; k++) a[k] = b[i] < b[j] ? b[i++] : b[j--]; } Sedgewicks udgave af mergesort Trick: Kopier a over i b, idet a[m+1..r] kopieres i omvendt orden. Herefter flettes b[l..m] (forlæns) med b[m+1..r]( baglæns), idet resultatet placeres i a. På denne måde fungerer det største element i de to delfiler som stopklods ved fletningen. lmm+1r ≤≥ b:b:

31 31 Animering af mergesort

32 32 Filstørrelserne Træstrukturer beskriver delfilernes størrelse: 1 1 1 1111111 1 1 1 11 1 2 2 2 2 22 2 2 4 4 4 4 88 16

33 33 Vurdering af sortering ved fletning Fordele: er ufølsom over for startorden i inddata kræver cirka N log 2 N antal sammenligninger for at sortere enhver fil C(N) = 2C(N/2) + N, C(1) = 0 er stabil kan benyttes til at sortere lister er velegnet til ekstern sortering Ulemper: kræver (i praksis) ekstra plads proportional med N

34 34 Tid i sekunder: Metode N = 32000 64000 128000 256000 512000 102400 mergesort 0.06 0.12 0.25 0.54 1.15 2.67 quicksort 0.03 0.05 0.09 0.17 0.36 0.76 shellsort 0.04 0.08 0.18 0.41 1.03 2.37 Empirisk undersøgelse af mergesort (Sedgewicks version)

35 35 Prioritetskøer En prioritetskø er en abstrakt datatype, der repræsenterer en endelig mængde af dataelementer forsynet med numeriske nøgler (prioriteter). Til typen er knyttet følgende 2 operationer: insert(v) : tilføj dataelementet v til mængden remove : fjern dataelementet med den højeste prioritet fra mængden En stak og en kø er specialtilfælde af en prioritetskø.

36 36 Anvendelser af prioritetskøer operativsystemer algoritmer til grafsøgning datakomprimeringsalgoritmer diskret simulering

37 37 class PQ { PQ(); PQ(int max); void insert(itemType v); itemType remove(); } Specifikation i Java Undertiden er det hensigtsmæssigt med yderligere operationer f.eks.: boolean isEmpty() : afgør om prioritetskøen er tom void join(PQ pq) : forener prioritetskøen med en anden prioritetskø ( pq ).

38 38 PQ pq = new PQ(M+1); for (k = 1; k <= M; k++) pq.insert(nextItem()); for (k = M+1; k <= N; k++) { pq.insert(nextItem()); pq.remove(); } for (k = 0; k < M; k++) result[k] = pq.remove(); Find de M mindste af N elementer. Typiske værdier: M = 1000, N = 1000000 Eksempel på klientprogram Omkostning afhænger af PQ-implementation: elementær: O(N M) hob: O(N log 2 M )

39 39 Implementation af PQ ved uordnet array class PQ { private itemType a[]; private int N; PQ(int max) { a = new itemType[max]; N = 0; } void insert(itemType v) { a[N++] = v; } itemType remove() { int i, max = 0; for (i = 1; i < N; i++) if (a[i] > a[max]) max = i; swap(a, max, N-1); return a[--N]; }

40 40 Implementation af PQ ved ordnet array itemType remove() { return a[--N]; } void insert(itemType v) { int i = N; while (i > 0 && a[i-1] > v) { a[i] = a[i-1]; i--; } a[i] = v; N++; } a holdes ordnet i stigende orden Andre elementære implementationer: uordnede lister ordnede lister

41 41 Sortering ved hjælp af prioritetskø Sortering af a[1:N] : PQ pq = new PQ(N); for (i = 1; i <= N; i++) pq.insert(a[i]); for (i = N; i >= 1; i--) a[i] = pq.remove(); Hvis prioritetskøen er implementeret som et uordnet array, svarer metoden til sortering ved udvælgelse. Hvis prioritetskøen er implementeret som et ordnet array, svarer algoritmen til sortering ved indsættelse.

42 42 En hob er et komplet binært træ, hvor nøglen i enhver knude er større end (eller lig med) sine børns nøgler. Hob komplet: (1) alle niveauer, eventuelt med undtagelse af det nederste, er fyldt ud med interne knuder; (2) på nederste niveau er de interne knuder helt til venstre Heraf fremgår: Den største nøgle findes i roden.

43 43 Eksempel på hob X T S M N O IAR E A G 1 2 3 4 89101112 567 En hob kan repræsenteres i et array (ikke behov for hægter): roden: a[1] sønner af roden: a[2] og a[3]... sønner af i : a[2*i] og a[2*i+1] far til i : a[i/2] i: 0 1 2 3 4 5 6 7 8 9 10 11 12 a: X T O G S M N A E R A I

44 44 X T S M N O IA R E A G P X T S ON P I A R E A G M Indsættelse af element i hob Indsæt elementet som det sidste. Oprethold hob-betingelsen ved fortsat at ombytte med faderen om nødvendigt.

45 45 Implementering af insert i Java void insert(itemType v) { a[++N] = v; upheap(N); } void upheap(int k) { itemType v = a[k]; while (k >= 1 && a[k/2] <= v) { a[k] = a[k/2]; k /= 2; } a[k] = v; }

46 46 Fjernelse af roden i hob Erstat roden med det sidste element. Opret hopbetingelsen ved fortsat at ombytte med den største af sønnerne om nødvendigt. X T S O N P IA R E A G M S R O N P IA M E A G T

47 47 void downheap(int k) { itemType v = a[k]; while (k <= N/2) { int i = 2*k; if (i a[i]) i++; if (v >= a[i]) break; a[k] = a[i]; k = i; } a[k] = v; } itemType remove() { itemType v = a[1]; a[1] = a[N--]; downheap(1); return v; } Implementering af remove i Java

48 48 Konstruktion af hob Problem: Givet et array a[1:N] af elementer i vilkårlig orden. Omordn arrayet, således at det udgør en hob. Top-til-bund-konstruktion: Induktionshypotese: Arrayet a[1:i] er en hob.

49 49 for (i = 2; i <= N; i++) upheap(i); Kompleksitet: O(  i=2..N  log(i)) = O(N log N)

50 50 Bund-til-top-konstruktion: Induktionshypotese: Alle træer repræsenteret i arrayet a[i+1:N] tilfredsstiller hob-betingelsen. a[N/2+1:N] tilfredsstiller hob-betingelsen (de er blade i træet). for (i = N/2; i >= 1; i--) downheap(i); Kompleksitet: O(  i=1..N/2  log(N/i)) = O(N)

51 51 heapsort i Java void heapsort(itemType a[], int N) { for (int i = N/2; i >= 1; i--) downheap(a, N, i); while (N > 1) { swap(a, 1, N); downheap(a, --N, 1); } Kompleksiteten af heapsort er O(NlogN). Ingen brug for ekstraplads.

52 52 Animering af heapsort (hob-konstruktions-fase)

53 53 Animering af heapsort (sorteringsfase)

54 54 Tid i sekunder: Metode N = 32000 64000 128000 256000 512000 102400 heapsort 0.03 0.07 0.16 0.32 0.94 2.10 mergesort 0.06 0.12 0.25 0.54 1.15 2.67 quicksort 0.03 0.05 0.09 0.17 0.36 0.76 shellsort 0.04 0.08 0.18 0.41 1.03 2.37 Empirisk undersøgelse af heapsort

55 55 Andre datastrukturer til implementering af en prioritetskø ptree pheap Van Emde-Boas priority queue pagoda leftist tree binary priority queue binary search tree binomial queue skew heap

56 56 public class SkewHeap { class Node { Node left, right; int value; Node(int v) { value = v; } } public void insert(int value) { root = merge(root, new Node(value)); } public int remove() { if (root == null) throw new RuntimeException(); Node oldRoot = root; root = merge(root.left, root.right); return oldRoot.value; } private Node root; private Node merge(Node r1, Node r2) {... } } class SkewHeap

57 57 Metoden merge private Node merge(Node r1, Node r2) { if (r1 == null) return r2; if (r2 == null) return r1; if (r1.value < r2.value) return merge(r2, r1); Node leftChild = r1.left; if (leftChild == null) r1.left = r2; else { r1.left = merge(r1.right, r2); r1.right = leftChild; } return r1; } r1 r2 L R R  T L r1 T

58 58 Uformelt bevis: Sortering er ækvivalent med bestemmelse af en permutation. Sortering kan derfor modelleres ved et beslutningstræ, hvor hver interne knude svarer til en sammenligning af to nøgler, mens hver eksterne knude svarer til en af de N! mulige permutationer. Højden i dette træ er mindst log 2 (N!). Af Stirlings formel fås log 2 (N!) ≈ Nlog 2 N - 1.44N. Kompleksiteten af sortering Enhver sorteringsalgoritme, der er baseret på nøglesammenligninger, kræver i værste tilfælde mindst cNlog 2 N sammenligninger for at sortere N elementer, hvor c er en konstant > 0.

59 59 Radixsortering En sorteringsmetode, hvor nøglerne betragtes som tal repræsenteret i et talsystem med givet grundtal (radix) M, f.eks. M = 10, og som baserer sig på klassificering ved hjælp af de individuelle cifre i tallene (altså uden nøglesammenligninger). Eksempel: Højre-mod-venstre radixsortering (straight radix sort). Lad der være givet en række 3-cifrede tal. Sorter først tallene med hensyn til det bagerste ciffer, dernæst med hensyn til det midterste, og til sidst med hensyn til det sidste. Hvis den anvendte sorteringsmetode er stabil, vil tallene være sorteret.

60 60 10456|01|02 |102 70425|11|04|104 81910|27|04|251 10279|23|08|298 82398|28|19|308 30859|29|34|496 65982|38|23|560 49684|38|43|592 25110|42|51|659 93470|46|59|704 56093|45|60|792 29898|49|82|819 79249|69|84|823 84330|87|92|843 98229|85|92|934 98481|94|96|982 59265|92|98|984

61 61 Kompleksiteten af straightradix Hvis ’sortering ved tælling’ benyttes til sortering af hvert ciffer er tidskompleksiteten O(kN), hvor k er det maksimale antal cifre i de tal, der skal sorteres. Metoden er med andre ord lineær i N. Den er dog O(NlogN), hvis alle tal, der skal sorteres er forskellige, idet k da mindst må være logN. Behovet for ekstra plads er O(N+M).

62 62 Tid i sekunder: Metode N = 32000 64000 128000 256000 512000 102400 straightradix 0.03 0.05 0.10 0.24 0.50 1.08 heapsort 0.03 0.07 0.16 0.32 0.94 2.10 mergesort 0.06 0.12 0.25 0.54 1.15 2.67 quicksort 0.03 0.05 0.09 0.17 0.36 0.76 shellsort 0.04 0.08 0.18 0.41 1.03 2.37 Empirisk undersøgelse af straightradix

63 63 Kriterier for valg af sorteringsmetode Størrelse af nøgler (sammenligninger) Størrelse af poster (flytninger/ombytninger) Størrelse af fil (elementær/avanceret metode) Nøgletype (sammenligninger/radix) Mange ens nøgler? Er filen næsten sorteret? Kræves stabilitet?

64 64 Læs kapitel 14 og 15 i lærebogen (side 193-229) Løs følgende opgaver 1. Opgave 9.4 og 9.9. 2. Opgave 11.3 og 11.6 3. Opgave 12.4 og 12.7. Ugeseddel 5 14. oktober - 20. oktober


Download ppt "1 Sortering II. 2 Plan Avancerede sorteringsmetoder: Metoder med kompleksitet O(n logn): - Quicksort (ekskurs: udvælgelse) - Sortering ved fletning ----------------------------------------------------------"

Lignende præsentationer


Annoncer fra Google