1 Datastructuren Sorteren: alleen of niet alleen vergelijkingen College 5
2 Sorteeralgoritmen tot nu toe en een vraagje (n lg n) tijd in het slechtste en gemiddelde geval: merge sort, heap sort (n 2 ) tijd in het slechtste en gemiddelde geval: insertion sort, bubble sort (n lg n) tijd in het gemiddelde geval en (n 2 ) tijd in het slechtste geval: quicksort Maar … zou het ook sneller dan (n lg n) kunnen??? Datastructuren
3 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
4 De vraag Vraag: zouden er sorteeralgoritmen die minder dan (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
5 ONDERGRENZEN VOOR SORTEREN (Stelling) Een Datastructuren
6 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
7 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] 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
8 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 n lg n) tijd) Bewijs komt later, maar eerst … algoritmen die NIET vergelijkingsgebaseerd zijn…
9 COUNTING SORT Twee Datastructuren
10 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 (n lg n) grens doorbreken Counting sort aanname: alle inputs zijn kleine getallen
11 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
12 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] for i = 0 to k do C[i] = 0; for j = 1 to n do C[A[j]] ++; {Nu geeft C[j] het aantal elementen in A met waarde j} …
13 Counting Sort pseudocode (2) Counting-Sort(A,B,k) Neem een integer array C[0…k] for i = 0 to k do C[i] = 0; for j = 1 to n do 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 k do 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} …
14 Counting Sort Pseudocode (3) Counting-Sort(A,B,k) Neem een integer array C[0…k] for i = 0 to k do C[i] = 0; for j = 1 to n do C[A[j]] ++; for i = 1 to k do 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 n do 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]}
15 Counting Sort Pseudocode Stabiele versie Counting-Sort(A,B,k) Neem een integer array C[0…k] for i=0 to k do C[i] = 0; for j=1 to n do C[A[j]] ++; for i=1 to k do C[i] = C[i]+C[i – 1]; for j = n downto 1 do 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
16 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] for i=0 to k do C[i] = 0; for j=1 to n do C[w.X[j]] ++; for i=1 to k do C[i] = C[i]+C[i – 1]; for j = n downto 1 do B[C[w.X[j]]] = X[j]; C[w.X[j]] -- Datastructuren
17 RADIX SORT Drie Datastructuren
18 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
19 Voorbeeld: sorteren met getallen van 3 cijfers 457 586 386 486 123 879 525 737 007 Datastructuren
20 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
21 Radix-sort Pseudocode Radix-Sort(A,d) {A[1…n] heeft n elementen, elk een d-digit waarde} {We sorteren A lexicographisch, waarbij de 1 e digit het minst en de d e digit het meest significant is} for i=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 de i-1 minst significante digits kijken Datastructuren
22 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
23 Varianten 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 Datastructuren
24 Datastructuur met lijstjes Voor elke waarde i tussen 0 en k en elke digit j tussen 1 en d hebben we lijstjes elementen, zeg L j (i) en L’(i), eerst allemaal leeg Zet elk element a 1 a 2 …a d in lijst L d (a d ) for i = d-1 downto 1 do for j = 0 to k do Zet de elementen a 1 a 2 …a d uit lijst L i+1 (j) achteraan in lijst L i (a j ) en behandel de elementen in de volgorde zoals ze in de lijst L i+1 (j) voorkomen for j = 0 to k do Lever de elementen uit lijst L 1 (j) op in de volgorde zoals ze in deze lijst voorkomen
25 Meerdere digits tegelijk Stel we hebben n b-bit elementen, waarbij iedere digit 2 waarden kan aannemen. Stel r b. Dan kunnen deze met Radix-Sort in O((b/r)(n+2 r )) tijd worden gesorteerd. Neem r bits steeds als één digit en doe daarmee radix-sort Elke digit zit dus tussen de 0 en de 2 r -1 We hebben b/r digits (omhoog afgerond) Datastructuren
26 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 (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
27 BUCKET SORT Vier Datastructuren
28 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)
30 Voorbeeld n=10 0,12; 0,67; 0,15; 0,86; 0,47; 0,42; 0,07; 0,98; 0,89; 0,14 [0-0,1) [0,1-0,2) [0,2-0,3) [0,3-0,4) [0,4-0,5) [0,5-0,6) [0,6-0,7) [0,7-0,8) [0,8-0,9) [0,9-1) 0,12 0,67 0,15 0,86 0,470,42 0,07 0,98 0,89 0,14
31 Code Bucket-Sort(A) Maak een lijst B(i) voor elke i, 0 in-1, initieel leeg for j = 1 to n do Stop A[j] in lijst B[nA[j]] for i = 0 to n do Sorteer de lijst B(i), bijvoorbeeld met insertion sort Lever achterelkaar de gesorteerde lijsten B(0), B(1), B(2), …, B(n-1) op
32 Tijd van Bucket sort Bucket-Sort(A) Maak een lijst B(i) voor elke i, 0 in-1, initieel leeg for j = 1 to n do Stop A[j] in lijst B[nA[j]] for i = 0 to n do 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
33 Kosten van sorteren van lijstjes Als lijstje i n i elementen heeft, (n i 2 ) 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 (n) Datastructuren
34 Analyse Introduceer random variabelen X ij X ij = 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
35 E[n i 2 ] Datastructuren Ziet er moeilijker uit dan ‘t is...
36Datastructuren want Want getal A[j] heeft kans 1/n om in stuk j te komen
37Datastructuren Want als k j dan zijn deze variabelen onafhankelijk, immers A[k] en A[j] hangen niet vanelkaar af
38 En dan zijn we er En dus:
39 Wat niet behandeld is Hoe implementeer je die lijstjes? Dat is een volgend (relatief eenvoudig) onderwerp van het college Datastructuren!
40 ONDERGRENZEN VOOR SORTEREN Vijf Datastructuren
41 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] 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
42 Allemaal verschillende elementen We bewijzen: vergelijkingsgebaseerde algoritmen moeten op sommige inputs lg(n!) = (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
43 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 n lg n) tijd)
44 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 1 e element het kleinste is Rechts: als 2 e element het kleinste is Bij een blad... Tja … wat doen we daar? Datastructuren
45 Beslissingsboom voor Insertion Sort op 3 elementen Datastructuren INSERTION-SORT(A) for j = 2 to lengte(A) do key = A[j] i = j – 1; while i > 0 and A[i] > key do A[i+1] = A[i] i = i – 1; A[i+1] = key 1:2 2:3 1:3 2: In de bladeren staan voorbeelden van inputs die daar terecht komen
46 Bladeren gemarkeerd met een permutatie Datastructuren 1:2 2:3 1:3 2:3 {1,2,3} {1,3,2}{2,3,1} {2,1,3} {3,1,2}{3,2,1}
47 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
48 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
49 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
50 Diepte van beslisboom Als een binaire boom diepte r heeft, heeft de boom maximaal 2 r 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 2 r r-1 bladeren Een beslisboom voor sorteren van n elementen heeft minstens n! bladeren, dus heeft diepte minstens lg(n!) = (n lg n) lg(n!) < lg(n n ) = n lg n lg(n!) > lg((n/2) n/2 ) = (n lg n) Datastructuren
51 Stelling Stelling: Elk vergelijksgebaseerd algoritme gebruikt voor sommige inputs van lengte n (n lg n) vergelijkingen en dus (n lg n) tijd. Gevolg: heapsort en merge sort zijn “asympthotisch optimaal”. Datastructuren
52 CONCLUSIES Vijf Datastructuren
53 Sorteren Zonder gebruik te maken van speciale eigenschappen van input: (n lg n) Ondergrensbewijs: aantal vergelijkingen Met gebruik van speciale eigenschappen: Sneller, vaak O(n) Counting Sort Radix Sort Bucket Sort Maar natuurlijk alleen voor inputs die zulke eigenschappen hebben
54 Conclusies In de praktijk worden soms hybride methodes gebruikt Uiterst slimme methoden om heel weinig elementen zo snel mogelijk te sorteren Overstappen van ene sorteermethode naar andere ergens gedurende algoritme Voor implementatie van sommige van deze algoritmen (en voor heel veel andere toepassingen) hebben we lijsten nodig Later kijken we naar implementaties van lijsten en speciale versies: queues en stacks