Sorterings- Algoritmer Algoritmer og Datastrukturer
Hva er sortering? Input: en sekvens av N nummer Output: reorganisering input-sekvensen slik at: Vi søker algoritmer som gjør dette på en korrekt og effektiv måte. a 1 < a 2 < a 3... < a n-1 < a n
Hvorfor sortering? Den største grunnen til at det er så viktig å kunne sortere et sett av elementer er at mange andre problem blir lettere å løse dersom elementene er sortert
Applikasjoner til sortering Søking: Binær søking finner ut om et element er i en ordliste i O(lg n) tid Å gjøre søking raskere er vel det viktigste bruksområdet til sortering Nærmeste nabo: Gitt n nummer, finn paret som er nærmest hverandre Med en gang nummerene er sortert, vil de nærmeste parene ligge ved siden av hverandre, slik at en O(n) linjær søking gjør jobben
Applikasjoner til sortering Element-Unikhet: Gitt et sett av n elementer, er de alle unike eller finnes der duplikater? Medianer og seleksjon: Hva er det k-te største elementet i en liste? Frekvens distrubisjoner: Gitt et sett av n elementer, hvilket element opptrer flest ganger i settet?
Hvordan kan vi sortere? Begrensinger til CPU Kan bare gjøre en operasjon av gangen, Siden en sammen- ligning er en operasjon, fører dette til at vi bare kan sammenligne to elementer samtidig når vi skal sortere Men kan gjøre denne sammenligningen veldig raskt.
Repetisjon Trær Sorterings-Algoritmer
Trestrukturer: Begreper R A BC D FG H Rot Søskennoder A’s barn (venstre) R’s subtre B og C’s Mor/Far-node Grener Noder Terminalnode, (endenode, løvnode) A’s barn (høyre)
Egenskap Binært-Søke-Tre Et binært søketre er organisert som et binærtre, og har følgende egenskap Operasjoner på et binært søketre, er derfor proposjonal med høyden på treet ≤≤ ≤ O(lg n)
Haug-Sortering Sorterings-Algoritmer
Hva er en Haug (Heap)? En haug er et komplett binærtre, der alle nivå er fylt opp, untatt eventuelt det siste, som er fylt opp fra venstre til høyre En haug brukes til blant annet Prioritetskøer og til Haugsortering (Heapsort)
Haug : Datastruktur Binærtre som er lagret i indekserbar variabel (array) ≥x≥x x ≤x≤x≤x i/2 i 2i 2i+1 Generelle far/barn relasjoner rot (Heap-egenskapen)
”Max-Heapify”: O(lg n) Subrutine som vedlikeholder Heap-egenskapen, ...dvs at barna til roten er mindre enn roten Max-Heapify(A,i) l = left(i) r = right(i) if l ≤ heap-size[A] and A[l] > A[i] then largest = l else largest = i if r ≤ heap-size[A] and A[r] > A[largest] then largest = r if largest ≠ i then exchange A[i] ↔ A[largest] Max-Heapify(A,largest) i
”Max-Heapify”: O(lg n) Subrutine som vedlikeholder Heap-egenskapen, ...dvs at barna til roten er mindre enn roten Max-Heapify(A,i) l = left(i) r = right(i) if l ≤ heap-size[A] and A[l] > A[i] then largest = l else largest = i if r ≤ heap-size[A] and A[r] > A[largest] then largest = r if largest ≠ i then exchange A[i] ↔ A[largest] Max-Heapify(A,largest) i
”Max-Heapify”: O(lg n) Subrutine som vedlikeholder Heap-egenskapen, ...dvs at barna til roten er mindre enn roten Max-Heapify(A,i) l = left(i) r = right(i) if l ≤ heap-size[A] and A[l] > A[i] then largest = l else largest = i if r ≤ heap-size[A] and A[r] > A[largest] then largest = r if largest ≠ i then exchange A[i] ↔ A[largest] Max-Heapify(A,largest) i
Build-Max-Heap : O(n) Lager en heap fra en (ikke-ordnet) array, i angir de indre nodene i heap’en Eksempel Build-Max-Heap(A) heap-size[A] = length[a] for i = [length[a]/2] downto 1 do heapify(A,i) i
Build-Max-Heap : O(n) Lager en heap fra en (ikke-ordnet) array, i angir de indre nodene i heap’en Eksempel Build-Max-Heap(A) heap-size[A] = length[a] for i = [length[a]/2] downto 1 do heapify(A,i) i
Build-Max-Heap : O(n) Lager en heap fra en (ikke-ordnet) array, i angir de indre nodene i heap’en Eksempel Build-Max-Heap(A) heap-size[A] = length[a] for i = [length[a]/2] downto 1 do heapify(A,i) i
Build-Max-Heap : O(n) Lager en heap fra en (ikke-ordnet) array, i angir de indre nodene i heap’en Eksempel Build-Max-Heap(A) heap-size[A] = length[a] for i = [length[a]/2] downto 1 do heapify(A,i)
Heapsort-Algoritmen Prosedyre for løsning Lag heap av tallene (i arrayet) For tall = [lengden til arrayet] ned til 2 Bytt første tall med array[tall] Reetabler treet for array[1...tall-1] Ferdig sortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1)
Heapsort : O(n*lg n) Kjøretid til heapsort Heapsort tar O(n*lg n) tid Siden kallet til Build-Max-Heap tar O(n) tid og Hver av de n-1 kallene til Heapify tar O(lg n) tid Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Eksempel
Heapsort : O(n*lg n) Eksempel (2) (1) i (2) Usortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Kapplinje Max-Heapify(A,1)
Heapsort : O(n*lg n) Eksempel (3) (2) i (3) Usortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Kapplinje Max-Heapify(A,1)
Heapsort : O(n*lg n) Eksempel (4) (3) i (4) Usortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Kapplinje Max-Heapify(A,1)
Heapsort : O(n*lg n) Eksempel (5) (4) i (5) Usortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Kapplinje Max-Heapify(A,1)
Heapsort : O(n*lg n) Eksempel (2) (5) i (3) Usortert Heapsort(A) for i = [length[a]] downto 2 do exchange A[1] ↔ A[i] heap-size[A] = heap-size[A]-1 Max-Heapify(A,1) Kapplinje Max-Heapify(A,1) Sortert : A
Prioritetskøer bruker Heap Haugsortering er en glimrende algoritme, men en god implementasjon av quicksort, slår den som regel i praksis Men selve heap-data-strukturen har et stort bruksområde. Den mest populære applikasjonen til en heap er å bruke den som en prioritetskø.
Prioritetskøer bruker Heap En prioritetskø er en datastruktur for å holde vedlike et sett av S elementer,...der hvert element har en assosiert verdi En har to typer prioritetskøer: En max-prioritets-kø En min-prioritets-kø
Prioritets-kø : Operasjoner Operasjoner til en max-prioritets-kø Insert(S,x), kjøretid O(lg n) setter et element x inn i settet S Setter en node inn i heapen Maximum(S), kjøretid O(1) returnerer elementet S med den største verdien Extract-Max(S), kjøretid O(lg n) Returnerer elementet S med den største verdien...og fjerner elementet fra heapen
Prioritets-kø : Operasjoner Operasjoner til en max-prioritets-kø Increase-Key(S,x,k), kjøretid O(lg n) Øker verdien til et element x til en ny verdi k,...som en antar er minst like stor som x Operasjoner til en min-prioritets-kø Insert(S,x), Minimum(S), Extract-Min(S), Decrease-Key(S,x,k)
Merge-Sortering Sorterings-Algoritmer
Hva er Merge-Sort? Merge-sortering (flette-sortering) er basert på ”splitt-og-hersk”-paradimet Splitt: del arrayet med n elementer i 2 deler med n/2 elementer Hersk: sorter de to halvdelene rekursivt ved kall til ”mergesort” Kombiner: flett sammen de to halvdelene for å produsere det sorterte arrayet
Merge-Sort : Algoritmen Merge-Sort(A,p,r) if p <r then q = [(p+r)/2] Merge-Sort(A,p,q) Merge-Sort(A,q+1,r) Merge(A,p,q,r) Dette gir oss rekurrensen: T(n) = 2T(n/2) + c*n) O(n*lg n) splitt hersk kombiner
hjelpe array minste AGLORHIMST Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. A
hjelpe array minste AGLORHIMST A Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. G
hjelpe array minste AGLORHIMST AG Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. H
hjelpe array minste AGLORHIMST AGH Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. I
hjelpe array minste AGLORHIMST AGHI Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. L
hjelpe array minste AGLORHIMST AGHIL Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. M
hjelpe array minste AGLORHIMST AGHILM Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. O
hjelpe array minste AGLORHIMST AGHILMO Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. R
hjelpe array Første halvdel ferdig minste AGLORHIMST AGHILMOR Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. S
hjelpe array Første halvdel ferdig minste AGLORHIMST AGHILMORS Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig. T
hjelpe array Første halvdel ferdig Andre halvdel ferdig AGLORHIMST AGHILMORST Merging Hold oversikt over det minste elementet i hver sortert halvdel. Sett inn det minste av de to elementene i det sorterte arrayet Gjenta dette til du er ferdig.
QuickSort Sorterings-Algoritmer
Hva er Quicksort? Quicksort er basert på ”splitt-og-hersk”- paradimet, slik som merge-sort. ...men inneholder i tillegg en viktig subrutine som heter partition Kjøretiden til quicksort er O(n 2 ) i verste tilfelle, men O(n*lg n) i gjennomsnitt
Idê bak partition Metode som deler arrayet slik at Elementet a[i] en deler arrayet i er på rett plass Det ikke er noen større elementer til ventre for i Det ikke er noen mindre elementer til høyre for i Deretter sorterer quicksort den venstre og høyre delen rekursivt
Partitioning Algoritme QUICKSORTISCOOL partitioned partition elementvenstre høyre ikke partitionert - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme Bytt meg partitionert partition elementvenstre høyre ikke partitionert QUICKSORTISCOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg QUICKSORTISCOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg QUICKSORTISCOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg QUICKSORTISCOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert CUICKSORTISQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme Bytt meg partitionert partition elementvenstre høyre ikke partitionert CUICKSORTISQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg CUICKSORTISQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg CUICKSORTISQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme Bytt meg partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert Bytt meg CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme Pekere krysser Bytt med partition element partitionert partition elementvenstre høyre ikke partitionert CIICKSORTUSQOOL - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Partitioning Algoritme partitionert partition elementvenstre høyre ikke partitionert partition er ferdig CIICKLORTUSQOOS - Velg partition element til å være det lengst til høyre - Scan fra venstre for et større element - Scan fra høyre for et mindre element - Bytt elementer - Gjenta til pekerne krysser - Bitt partition element med ”kryss-elementet”
Quicksort : Algoritmen Quicksort(A,p,r) if p <r then q = Partition(A,p,r) Quiksort(A,p,q-1) Quicksort(A,q+1,r) Partition(A,p,r) x = A[r] i = p-1 for j = p to r-1 do if A[j] ≤ x then i = i+1 exchange A[i] ↔ A[j] return i+1
Kjøre-Eksempel Kombinerer sett sammen de sorterte subarrayene 695 Vi få da et sortert array Kjøre-eksempel Usortert array
”Worst case Partition” 12n 2n 1 n 2 2n n-1 n T(n) = T(n-1) + O(n) - n O(n 2 ) Dårlig pga svært skjeve splittinger; en region med bare ett element og den andre regionen (subarray) inneholder resten av elementene. O(n 2 ) hvis input-array allereder er sortert
”Best-Case Partiton” 1 n n/2 O(n 1,4 lg n) O(n*lg n) Alternerer mellom gode og dårlige delinger Gjennomsnittlig dybde I binærtre = 1,4 lg n Konstanten er mindre enn For noen annen sorteringsrutine
”Average Case Partition” 1 n n/2 T(n) = 2T(n/2) + O(n) O(n*lg n)
Hva er Quicksort? Den er i praktiske tilfeller som oftes den beste sorterings-algoritmen Den er veldig effektiv i gjennomsnitt. Den antatte kjøretiden er O(n*ln n)...der konstantfaktoren er veldig liten Den sorterer dessuten ”in place”,...der ingen spesielle input lokker frem worst-case-oppførsel Den fungerer også godt i omgivelser med virtuelle minne
Tellesortering Sorterings-Algoritmer
Telle-Sortering (Counting-Sort) Sorteringsrutinen antar at hvert av de n- elementene, som skal sorteres, er heltall mellom 1 og k, der k er et heltall Ide: For hvert element x skal antall elementer mindre enn x finnes. Informasjonen brukes til å plassere x direkte i det sorterte arrayet
Plassforbruk Tellesortering Sorteringsrutinen krever stor plass da 3 array brukes Array A[1..n] som skal sorteres Array B[1..n] er sortert resultat Array C[1..k] er temporært arbeidslager Algoritmen sorterer i linjær tid O(n), k = O(n)
Eksempel B C j = B C j = B C j = B B j = A Array som skal sorteres j B Antall 4’ere i A C Antall elementer ≤ 3
Eksempel A Array som skal sorteres B Antall 4’ere i A B C j = B C j = B C j = B C j = C Antall elementer ≤ 3 SORTERT
Radix-Sort Sorterings-Algoritmer
Radix-sort Radix-sort er ulik andre sorteringsmetder, ettersom den tar hensyn til strukturen til nøklene som skal sorteres. Element: {t d, t d-1 … t 1 } Minst tellende siffer Mest tellende siffer
Radix-sort Sorterer bits fra høyre til venstre Radix-Sort(A,d) for i=1 to d do use a stable sort to sort array A on digit i
Analyse Radix-Sort Kjøretiden avhenger av hvilken sorteringsrutine som blir brukt Couting-sort: (dn + kd) Nar d er konstant og k = O(n) → O(n) Krever ekstra lagerplass Quicksort : (n*log n) Når d er konstant Krever ikke ekstra lagerplass