Hans Fr. Nordhaug (Ola Bø)
description
Transcript of Hans Fr. Nordhaug (Ola Bø)
INF 295 Algoritmer og datastrukturer
Forelesning 21 Merge, Quick og Bøtte, Radix
og ekstern sortering
Hans Fr. Nordhaug(Ola Bø)
Mergesort
Bygger på sammensmelting av sorterte lister Hver av de sorterte listene kan lages ved å sammensmelte
sorterte lister som kan bygges ved å sammensmelte sorterte lister ....
Mergesort kjører i O(NlogN) worst case Antall sammenlikninger er nesten optimal Rekursiv algoritme Kjøretid
Merge av to lister er lineær Analysen bygger på at T(N)=2*T(N/2)+N
Plassbehov – Trenger en ekstra temporær array
Mergesort rekursiv rutine
Mergesort merge-rutine
Mergesort driver
Quicksort
Raskeste kjente sorteringsalgoritme i praksis Gjennomsnittlig kjøretid O(NlogN) O(N2) worst case – men kan gjøres svært
usannsynlig Har rykte for å være vanskelig å
implementere Algoritmen er en rekursiv splitt og hersk
algoritme
Algoritme
1. Hvis antall elementer er 0 eller 1 returner2. Plukk et vilkårlig element v i S. Elementet
kalles pivot3. Partisjoner de resterende elementene i S i to
disjunkte mengder - S1: elementene som er mindre enn eller lik v S2: elementene som er større enn eller lik v
4. Returner quicksort( S1), fulgt av Pivot, fulgt av quicksort(S2)
Quicksort-algoritme
Hvordan plukke ut pivot-elementet? Ideelt det midterste elementet for å få en effektiv
algoritme Splitt og hersk som mergesort
Ingen garanti for like store delproblemer Likevel raskere enn mergesort i praksis Hvorfor?
Alt foregår effektivt og i arrayen som skal sorteres Krever i motsetning til merge ingen ekstra array
Å velge Pivot-element til Quicksort Algoritmen fungerer uansett hvordan pivot velges
Men den fungerer dårlig hvis vi stadig bruker en pivot som er langt fra midten
Hva om vi bruker første element som pivot? Svært dårlig på materiale som er (nesten) sortert
Gir kvadratisk tid på å gjøre (nesten) ingen ting. Nesten sortert er ganske vanlig. Hvorfor? Bokas konklusjon: An absolutely horrible idea
Bruke den største av de to første? Nei Ta et tilfeldig element
Tilfeldig tallgenerering er for dyrt Det beste valget er medianen av tabellen
Median er for dyrt Velger medianen av første, siste og midtre element!
Partisjoneringsstrategi
Partisjonering: Flytte alle elementer som er større enn Pivoten til høyre for Pivot Flytte alle elementer som er mindre enn Pivoten til venstre for Pivot
Mange mulige strategier. Krever omtanke. Løsning:
Flytt Pivot til slutten. Sett peker til hver ende Flytt pekerne til du finner elementer som skal flyttes Bytt elementene, flytt pekerne videre til du finner nye
elementer som skal flyttes osv Når de to pekerne har passert hverandre er du ferdig Bytt Pivot med siste posisjon for venstrepeker
Hva gjør vi med elementer som er lik Pivot?
Små Arrayer
Quicksort er mindre effektiv enn innsettings-sortering for N<20
Etterson Quicksort er rekursiv, vil det bli mange slike korte arrayer å sortere
Strategi: Kutt Quicksort og gå over til Insettingssortering når delarrayen er liten nok
Cutoff mellom 5 og 20 går bra.
Et eksempel på Quick-sort
Pivotgenerering gjøres på stedet Positive sideeffekter:
Plasserer første, siste og pivot i riktig partisjon Pivot flyttes til siste-1 Pekerne kan dermed starte i første+1 og siste-2 første og siste blir dermed sentinel (skiltvakter) som
sikrer at pekerne vil stoppe innenfor arrayen Mulig optimalisering av bytting Indre loop er svært effektiv:
increment, sammenlikn, jump
Quick-sort Finne Pivot
Quick-sort
Bøttesortering
Fungerer når vi har mer opplysninger om materialet som skal sorteres
Eksempel: Sortering av naturlige tall med gitt øvre grense
Idé Opprett en array int[] antall=new int[øvre grense] For hvert element inkrementerer vi tilsvarende
antall For hver i mellom 0 og øvre grense, skriv ut i så
mange ganger som antall[i] tilsier
Bøttesortering
Bøttesortering
Kan også sortere mer kompliserte elementer enn heltall, bare vi sorterer på noe som svarer til heltall
Hvis tallområdet blir for stort er Radix-sort et alternativ
Kan være betydelig raskere enn Quick-sort Ikke sammenlikningsbasert Kan ikke brukes som generell algoritme Kan ha mange anvendelser i praksis
Ikke uvanlig å ha små heltall som input
Radix-sortering
Når det blir for mange bøtter - f.eks delnummere 12334098993356719
Sortere i bøtter på "siffer" for "siffer" Minst signifikante siffer først "Siffer" kan være desimalt siffer - gir 10 bøtter Ikke nødvendigvis effektivt - det blir mye flytting Mer effektivt å bruke mange bits i hvert "siffer"
Radix er grunntallet i et tallsystem
Radix-sortering
Resultater
Sorteringsalgoritmer450 MHz Pentium
Sortering av 10 000 tilfeldige tall mellom 0 og 100 000Tidsforbruk bubblesort:9010 msTidsforbruk insertionsort:3950 ms
Tidtaking har usikkerhet > 60 ms - klokka tikker bare 18,2 ganger per sekund!!Tidsforbruk heapsort:60 msTidsforbruk shellsort:50 msTidsforbruk mergeSort:60 msTidsforbruk quicksort:50 msTidsforbruk bucketsort:0 ms
ResultaterSortering av 1000 000 tilfeldige tall mellom 0 og 10 000 000Avanserte sammenlikningsbaserte algoritmerTidsforbruk heapsort:11040 msTidsforbruk shellsort:20210 msTidsforbruk HibbardShellsort:19010 msTidsforbruk SedgewickShellsort:11640 msTidsforbruk mergeSort:7360 msTidsforbruk quicksort:5110 msTidsforbruk javas sort (quicksort):6650 ms
Algoritmer med direkte plasseringTidsforbruk bucketsort:2300 msBucketsort med 1 000 000 bøtterTidsforbruk radixSort med bibliotekslister:12250 msTidsforbruk radixSort med skreddersydde lister:3790 msRadixsort med 65 526 bøtter
Ekstern sortering
Mange tilfeller med for mye data til sortering i indre lager
Nye algoritmer er nødvendig Elementer som ikke er naboer vil ta tid å
aksessere Diskaksess tar tid Tape er spesielt krevende på grunn av
sekvensiell aksess Skal vi sortere med tape, trengs minst tre
tapelesere - ellers er vi i trøbbel
Ekstern sortering
Grunnleggende algoritme: MergeSort 4 taper Ta1, Ta2, Tb1, Tb2. Data på Ta1 Algoritme
1. Gjenta: Fyll memory fra Ta1 og sorter internt M tall i gangen. Skriv til Tb1 og Tb2 vekselvis. Hver operasjon kalles en run. Rewind
2. Flett data for en run fra Tb1 og en run fra Tb2, skriv flettede data til Ta1 og Ta2 vekselvis. Hver operasjon kalles en run- og er dobbelt så lang som forrige run. Tilbakespol alle taper og gjenta (med rollene for Ta og Tb byttet om) til det bare er en run. Da er det ferdig sortert.
Antall omganger er log(N/M)
Ekstern sortering - eksempel
Ta1 81 94 11 96 12 35 17 99 28 58 41 75 15
Ta2
Tb1
Tb2
Ta1
Ta2
Tb1 11 81 94 17 28 99 15
Tb2 12 35 96 41 58 75
Ekstern sortering - eksempel
Ta1 11 12 35 81 94 96 15
Ta2 17 28 99 41 58 75
Tb1
Tb2
Ta1
Ta2
Tb1 11 12 17 28 35 51 58 75 81 94 96 99
Tb2 15
Ekstern sortering - eksempel
Ta1 11 12 15 17 28 35 41 58 75 81 94 96 99
Ta2
Tb1
Tb2
I dette eksemplet kunne altså maskinen lese inn tre tall i intern minne - resten måtte skje på tape.
Krever ca log(13/3) omganger.
Multiway merge
Har vi flere tapestasjoner, kan vi merge fra flere taper på en gang.
Tar hele tiden minste element fra en av de k tapene og leser neste post på tapen.
Binær heap gir rask henting av minste element
Polyphase merge
Gjøre k-veis fletting med k+1 taper istedenfor 2k.
Strategien er enkel – fordel runs ujevnt, og rewind når det kortest er ferdig.
Problemet er antall omganger. Valg fordeling etter (k) Fibonacci.
Konstruksjon av runs
Rett frem – les M elementer og sorter disse intern, gjenta.
Men hver gang et tall skrives tilbake til tape blir det en ledig plass internt – bruk denne vha av Replacement selection (RS).
Nytt tall velges fra minne med deleteMin (binær heap). Fyll inn et nytt tall fra tape i internt minne hver gang – enten i køen eller i ”dead space”. Bygg ny heap når køen er tom.
Oppsummering
Bruk vanlig innstikk på små array, ellers shellsort eller quicksort.
I spesielle tilfeller kan bøtte eller radix søk brukes.
Sorteringsalgoritmer kan kategoriseres. Ekstern sortering er vanligvis basert på
fletting.