540 likes | 684 Views
Datastructuren Sorteren: alleen of niet alleen vergelijkingen. College 5. Sorteeralgoritmen tot nu toe en een vraagje. Q ( n lg n ) tijd in het slechtste en gemiddelde geval: merge sort, heap sort Q ( n 2 ) tijd in het slechtste en gemiddelde geval: insertion sort, bubble sort
E N D
DatastructurenSorteren: alleen of niet alleen vergelijkingen College 5
Sorteeralgoritmen tot nu toeen een vraagje • Q(n lg n) tijd in het slechtste en gemiddelde geval: merge sort, heap sort • Q(n2) tijd in het slechtste en gemiddelde geval: insertion sort, bubble sort • Q(n lg n) tijd in het gemiddelde geval en Q(n2) tijd in het slechtste geval: quicksort • Maar … zou het ook sneller dan Q(n lg n) kunnen??? Datastructuren
Vandaag en een volgende keer • Sorteermethoden die niet vergelijkings-gebaseerd zijn (en dan ook soms sneller) • Counting sort • Radix sort • Bucket sort • Ondergrens voor vergelijkings-gebaseerd sorteren (comparison sorts) • Eerst alleen de stelling; bewijs komt later Datastructuren
De vraag • Vraag: zouden er sorteeralgoritmen die minder dan Q(n lg n) tijd gebruiken? • O(n), O(n lg lg n), O(n Ö (lg n)) ? • Het antwoord is JA en NEE • JA – als we extra aannamen kunnen maken over de input en die gebruiken • NEE – als we dat niet kunnen Datastructuren
Een ONDERGRENZEN VOOR SORTEREN (Stelling) Datastructuren
Vergelijkingsgebaseerde algoritmen 1 • Bubble sort, Merge sort, Heapsort, Quicksort, Insertion sort (en nog een paar meer) • Kunnen gebruikt worden voor het sorteren van ELKE soort data waar een volledige ordening op bestaat • Bijvoorbeeld: integers, strings, objecten zoals dingesen, … • Want: ze hebben alleen een vergelijking tussen de elementen nodig Datastructuren
Vergelijkingsgebaseerd sorteeralgoritme • In een vergelijkingsgebaseerd sorteeralgoritme(comparison sort) zijn de enige operaties die op de data worden uitgevoerd: • Vergelijkingen:A[i] < A[j]; A[i] > A[j]; A[i] ³ A[j]; A[i] £ A[j]; A[i]==A[j] • Verplaatsingen • De data worden verder niet bekeken om extra informatie er uit te halen waar we de loop van het programma mee beïnvloeden Datastructuren
De stelling Stelling Voor ELK vergelijkingsgebaseerd algoritme A: er is een constante c, zodat voor elke n er een input met n elementen is waar A cn lg n vergelijkingen uitvoert (en dus kost A W(n lg n) tijd) Bewijs komt later, maar eerst … algoritmen die NIET vergelijkingsgebaseerd zijn…
Countingsort Twee Datastructuren
Gebruik maken van andere operaties dan vergelijkingen • Soms weten we meer van de input, en kunnen we gebruik maken van andere operaties en dan de W(n lg n) grens doorbreken • Counting sort aanname: alle inputs zijn kleine getallen
Counting sort 1 • Stel alle inputs zijn getallen tussen de 0 en de k (inclusief) voor een integer k • Stel k = O(n) • We kunnen nu in O(n) tijd de getallen sorteren: • Tel voor elk van de getallen 0 t/m k hoe vaak het getal in de input voorkomt • Tel daarna voor elke input hoeveel kleinere inputs er zijn • Dat vertelt waar ie komen moet (met even wat aandacht als inputs hetzelfde kunnen zijn) Datastructuren
Counting Sort pseudocode (1) Counting-Sort(A,B,k) • {A[1…n] is de input-array van n integers; het antwoord komt in B; k is de maximale waarde van een element in A} • Neem een integer array C[0…k] • fori = 0 tokdo • C[i] = 0; • forj = 1 to ndo • C[A[j]] ++; • {Nu geeft C[j] het aantal elementen in A met waarde j} • …
Counting Sort pseudocode (2) Counting-Sort(A,B,k) • Neem een integer array C[0…k] • fori = 0 tokdo C[i] = 0; • forj = 1 to ndo C[A[j]] ++; • {Nu geeft C[i] het aantal elementen in A met waarde i, voor alle i, 0 £i £ k} • for i = 1 to kdo • C[i] = C[i] + C[i – 1]; • {Nu geeft C[i] het aantal elementen in A met waarde maximaal i, voor alle i, 0 £i £ k} • …
Counting Sort Pseudocode (3) Counting-Sort(A,B,k) • Neem een integer array C[0…k] • fori = 0 tokdo C[i] = 0; • forj = 1 to ndo C[A[j]] ++; • for i = 1 to kdo C[i] = C[i] + C[i – 1]; • {Nu geeft C[i] het aantal elementen in A met waarde maximaal i, voor alle i, 0 £i £ k} • for j = 1 to ndo • B[C[A[j]]] = A[j]; {Zet A[j] op de goede plek} • C[A[j]] -- ; {Zorg voor de plekken van andere elementen met dezelfde waarde A[j]}
Counting Sort PseudocodeStabiele versie Counting-Sort(A,B,k) • Neem een integer array C[0…k] • fori=0 tokdo C[i] = 0; • forj=1 to ndo C[A[j]] ++; • for i=1 to kdo • C[i] = C[i]+C[i – 1]; • for j = n downto 1do • B[C[A[j]]] = A[j]; • C[A[j]] -- • Deze versie zet de elementen in volgorde van n naar 1 in B • Enige voordeel: “stabiel”: als twee elementen hetzelfde zijn verandert hun onderlinge volgorde niet • Nuttig als er objecten aan de elementen zitten • Wordt gebruikt bij ons volgende sorteeralgoritme
Counting Sort met objecten met waarde • Stel, we hebben een array van objecten X[1..n]. Elk object X[i] heeft een waarde w.X[i] die tussen de 0 en de k ligt • Dit sorteer je weer met counting sort, helemaal op dezelfde manier • Merk op: stabiel • Als i<j en w.X[i] = w.X[j] dan komt X[i] op een eerdere positie in B dan X[j] Counting-Sort-Obj(X,B,k) • Neem een integer array C[0…k] • fori=0 tokdo C[i] = 0; • forj=1 to ndo • C[w.X[j]] ++; • for i=1 to kdo • C[i] = C[i]+C[i – 1]; • for j = n downto 1do • B[C[w.X[j]]] = X[j]; • C[w.X[j]] -- Datastructuren
Drie Radix sort Datastructuren
Radix sort • Redelijk aantal toepassingen: • Sorteren van verzamelingen strings / woorden • Sorteren van decimale getallen die niet al te lang zijn • Graaf-algoritmen • …. • Soort herhaald stabiele counting sort • Kan ook anders (bijv. met lijsten, komt later) worden geimplementeerd ipv counting sort Datastructuren
Voorbeeld: sorteren met getallen van 3 cijfers • 457 • 586 • 386 • 486 • 123 • 879 • 525 • 737 • 007 0 1 2 3 4 5 6 7 8 9 Datastructuren
Radix sort • Onze input bestaat uit d-digit getallen • Of varianten • We sorteren iedere keer op één van de digits, en dan is daarna alles gesorteerd • Belangrijk is dat we steeds stabiel sorteren Datastructuren
Radix-sort Pseudocode Radix-Sort(A,d) • {A[1…n] heeft n elementen, elk een d-digit waarde} • {We sorteren A lexicographisch, waarbij de 1e digit het minst en de de digit het meest significant is} • fori=1 to d do • (*) • Sorteer A met een stabiele sorteermethode, alleen kijkend naar digit i, bijvoorbeeld met counting sort • Correctheid: bij (*) geldt dat elementen correct gesorteerd zijn als we alleen naar dei-1 minst significante digits kijken Datastructuren
Stelling • Stel we hebben n elementen, ieder met d digits, waarbij iedere digit k waarden kan aannemen. Dan kunnen deze met Radix-Sort in O(d(n+k)) tijd worden gesorteerd. • We doen d keer een Counting Sort die O(n+k) tijd kosten elk Datastructuren
Varianten 0 • Als we woorden sorteren: nummer de letters (bijv. A=1, B=2, …, ) en doe dan met de vertaling naar getallen een radix-sort • Andere datastructuur met array van lijstjes werkt ook goed 540 980 1 2 3 513 433 4 5 6 006 7 8 9 Datastructuren
Datastructuur met lijstjes • Voor elke waarde i tussen 0 en k en elke digit j tussen 1 en d hebben we lijstjes elementen, zeg Lj(i) en L’(i), eerst allemaal leeg • Zet elk element a1a2…ad in lijst Ld(ad) • for i = d-1downto1 do • for j = 0 to kdo • Zet de elementen a1a2…ad uit lijst Li+1(j) achteraan in lijst Li(aj) en behandel de elementen in de volgorde zoals ze in de lijst Li+1(j) voorkomen • for j = 0 to kdo • Lever de elementenuit lijst L1(j) op in de volgorde zoals ze in deze lijst voorkomen
Meerdere digits tegelijk • Stel we hebben nb-bit elementen, waarbij iedere digit 2 waarden kan aannemen. Stel r £ b. Dan kunnen deze met Radix-Sort in O((b/r)(n+2r)) tijd worden gesorteerd. • Neem r bits steeds als één digit en doe daarmee radix-sort • Elke digit zit dus tussen de 0 en de 2r-1 • We hebben b/r digits (omhoog afgerond) Datastructuren
Vergelijking • Als we O(lg n)-bit getallen hebben kan je r= lg n (of in de buurt) nemen • Geeft O(n) sorteren • Vergelijkings-gebaseerde algoritmen kosten W(n lg n) • … maar de constante in de O kan beter zijn • En hardware-overwegingen kunnen rol spelen, zoals cache-hits, geheugen, met name als we veel data hebben Datastructuren
Vier BucketSort Datastructuren
Bucket sort • Stel we willen n getallen tussen de 0 en 1 sorteren, en we weten dat ze “eerlijk” verdeeld zijn (getrokken met uniforme distributie) • Idee: we verdelen het interval [0,1) in n gelijke stukken: [0, 1/n), [1/n, 2/n), [2/n, 3/n), … [(n-1)/n, 1) • Voor elk stuk nemen we een lijstje • Stop elk van de getallen in het lijstje waar het hoort • Sorteer dan elk lijstje apart Datastructuren
n Emmers voor intervallen [i/n, (i+1)/n) 0.3-0.4 0-0.1 0.1-0.2 0.2-0.3 0.4-0.5 0.5-0.6 0.6-0.7 0.7-0.8 0.8-0.9 0.9-1
Voorbeeld [0-0,1) 0,07 • n=10 • 0,12; 0,67; 0,15; 0,86; 0,47; 0,42; 0,07; 0,98; 0,89; 0,14 [0,1-0,2) 0,12 0,15 0,14 [0,2-0,3) [0,3-0,4) [0,4-0,5) 0,47 0,42 [0,5-0,6) [0,6-0,7) 0,67 [0,7-0,8) [0,8-0,9) 0,86 0,89 [0,9-1) 0,98
Code Bucket-Sort(A) • Maak een lijst B(i) voor elke i, 0 £ i£ n-1, initieel leeg • for j = 1 to ndo • Stop A[j] in lijst B[ënA[j]û] • for i = 0to ndo • Sorteer de lijst B(i), bijvoorbeeld met insertion sort • Lever achterelkaar de gesorteerde lijsten B(0), B(1), B(2), …, B(n-1) op
Tijd van Bucket sort Bucket-Sort(A) • Maak een lijst B(i) voor elke i, 0 £ i£ n-1, initieel leeg • for j = 1 to ndo • Stop A[j] in lijst B[ënA[j]û] • for i = 0to ndo • Sorteer de lijst B(i), bijvoorbeeld met insertion sort • Lever achterelkaar de gesorteerde lijsten B(0), B(1), B(2), …, B(n-1) op • Alles behalve het sorteren van de kleine lijstjes kost O(n) tijd • Dus, we moeten vooral afschatten hoeveel die ene sorteerstap kost
Kosten van sorteren van lijstjes • Als lijstje ini elementen heeft, Q(ni2) tijd voor dat lijstje • Wat is de verwachtte waarde van • Berekeningen tonen aan: minder dan 2n • Alleen als we tijd overhouden in college; anders: zie boek • Dus verwachtte tijd van Bucket Sort is Q(n) Datastructuren
Analyse • Introduceer random variabelen Xij • Xij = 1 als A[j] in bucket i terecht komt, anders 0 • Omdat we aannemen dat de waardes uniform gekozen zijn is dit een random variabele, en ze zijn allemaal onafhankelijk • Dus is ook random variabele Datastructuren
E[ni2] Ziet ermoeilijkeruit dan ‘t is... Datastructuren
want Want getal A[j] heeft kans 1/n om in stuk j te komen Datastructuren
Want als k¹j dan zijn dezevariabelen onafhankelijk, immersA[k] en A[j] hangen niet vanelkaar af Datastructuren
En dan zijn we er En dus:
Wat niet behandeld is • Hoe implementeer je die lijstjes? • Dat is een volgend (relatief eenvoudig) onderwerp van het college Datastructuren!
Ondergrenzen Voor Sorteren Vijf Datastructuren
Vergelijkingsgebaseerd sorteeralgoritme(herhaling) • In een vergelijkingsgebaseerd sorteeralgoritme(comparison sort) zijn de enige operaties die op de data worden uitgevoerd: • Vergelijkingen:A[i] < A[j]; A[i] > A[j]; A[i] ³ A[j]; A[i] £ A[j]; A[i]==A[j] • Verplaatsingen • De data worden verder niet bekeken om extra informatie er uit te halen waar we de loop van het programma mee beïnvloeden Datastructuren
Allemaal verschillende elementen • We bewijzen: vergelijkingsgebaseerde algoritmen moeten op sommige inputs lg(n!) = Q(n lg n) vergelijkingen doen • We nemen in het bewijs aan dat alle elementen in de array (van lengte n) verschillend zijn • Algoritme moet immers dan ook correct werken Datastructuren
De stelling Stelling Voor ELK vergelijkingsgebaseerd algoritme A: er is een constante c, zodat voor elke n er een input met n elementen is waar A cn lg n vergelijkingen uitvoert (en dus kost A W(n lg n) tijd)
Model van algoritme:Beslissingsboom • Binaire boom, met • Elke knoop heeft twee of nul kinderen • Elke interne knoop is gelabeld met een vergelijkingstest: welke twee (verschillende) elementen (uit oorspronkelijk array) worden met elkaar vergeleken? • Links: als 1e element het kleinste is • Rechts: als 2e element het kleinste is • Bij een blad ... Tja … wat doen we daar? Datastructuren
Beslissingsboom voor Insertion Sort op 3 elementen 1:2 INSERTION-SORT(A) for j = 2 to lengte(A) do key = A[j] i = j – 1; whilei > 0 and A[i] > keydo A[i+1] = A[i] i = i – 1; A[i+1] = key 1:3 2:3 546 1:3 2:3 456 645 654 465 564 In de bladeren staan voorbeeldenvan inputs die daar terecht komen Datastructuren
Bladeren gemarkeerd met een permutatie 1:2 1:3 2:3 {2,1,3} 1:3 2:3 {1,2,3} {3,1,2} {3,2,1} {1,3,2} {2,3,1} Datastructuren
Over beslissingsbomen • Als twee inputs dezelfde ordening hebben, komen ze in hetzelfde blad • Bijvoorbeeld: (4,6,5) of (10, 30, 20) of (2, 47, 42) • Er kunnen testen zich herhalen (bijvoorbeeld in bubble sort) • Er kunnen bladeren zijn waar je nooit terecht kan komen (komt ook in bubble sort voor) • Niet zo belangrijk hoe je precies test (i<j of j<i) etc. • Markeer bladeren met de permutaties die daar terecht komen
Hooguit één permutatie in een blad • Als twee inputs in hetzelfde blad terecht komen, worden dezelfde data-bewegingen uitgevoerd • De inputs worden op dezelfde manier gepermuteerd! • Prima, als we dezelfde sortering op de inputs hebben (als {4,6,5}, {1,3,2} of {12, 49, 25}) • Niet prima, als de inputs anders gesorteerd zijn: want dan is minstens één antwoord fout • In elk blad van de boom staat hooguit één permutatie van {1,2,3,…,n} Datastructuren
Diepte van beslisbomen versus vergelijksgebaseerd sorteren Elke permutatie moet voorkomen in een blad van de beslisboom Elk blad van de beslisboom heeft hooguit 1 permutatie Als er een permutatie in een blad met diepte r zit moeten voor die permutatie r vergelijkingen worden uitgevoerd Er zijn n! permutaties Diepte van een boom met n! bladeren is ondergrens voor vergelijkingsgebaseerd sorteren
Diepte van beslisboom • Als een binaire boom diepte r heeft, heeft de boom maximaal 2r bladeren • Bewijs met inductie naar r. Triviaal als r=0; als r>0, dan wortel heeft twee kinderen met bomen met diepte r-1, dus 2r-1 + 2r-1 bladeren • Een beslisboom voor sorteren van n elementen heeft minstens n! bladeren, dus heeft diepte minstens lg(n!) = Q(n lg n) • lg(n!) < lg(nn) = n lg n • lg(n!) > lg((n/2)n/2) = W(n lg n) Datastructuren