Hvorfor sortering og søking? Man bør ha orden i dataene umulig å leve uten i informasjonssamfunnet vi blir fort lei av å lete poleksempel internett alt er søking og sortering alternativer til sortering og søking binære trær søketrær 15 personer Søking og sortering 1 1 3 4 7 7 9 11 1 2 5 5 6 9 10 Dette er et sett lysark for en forelesning. Mange sider er ukommentert og ufullstendige. Mange spørsmål er ubesvarte og det kan forekomme feil. Settet er tildels uegnet til selvstudium uten notater fra forelesningen. 12 12 13 15 11 15 16 17 Stein Michael Storleer 29. april 2008 Ark 3 av 24 Stein Michael Storleer 29. april 2008 Ark 1 av 24 Binære søketrær Ordnet innsetting forbereder for mer effektiv søking og sortering Jasmina Søking og sortering Hvorfor sortere og søke? Binære søketrær Søking i array Lineær søking Rekursjon: Binærsøk Objekter som har navn som kommer alfabetisk foran (mindre enn) "" Objekter hvor navn er større enn "" Sortering i array Flettesortering (eng. merge) Boblesortering Innstikksortering Rekursjon: Quicksort Stein Michael Storleer 29. april 2008 Ark 4 av 24 Stein Michael Storleer 29. april 2008 Ark 2 av 24
Henrik Andreas Christian Slik blir treet hvis person objektene settes inn i alfabetisk rekkefølge. Darjan Gry Henrik Resten i stigende orden Andreas Christian Gry Darjan Henrik Andreas Susanne Jim Vivi Pål Christian Darjan Jan Torjus Tor Gry Simen Stian Nguyen Philip Siv Jan Jim Nguyen Pål Philip Susanne Vivi Torjus Tor Simen Stian Slik blir treet hvis navnene kommer slik lista over er (fra øverst og nedover) Siv Stein Michael Storleer 29. april 2008 Ark 7 av 24 Stein Michael Storleer 29. april 2008 Ark 5 av 24 Søking Finnes det et objekt i «samlingen» av objekter som tilfredsstiller en bestemt egenskap? Finne ett (eller ingen) objekter Andreas Christian Darjan Gry Henrik Jan Jim Nguyen Philip Pål Simen Siv Stian Susanne Tor Torjus Vivi Hvis flere objekter imøtekommer søkekravet, holder det å finne ett Fra sortert liste (øverst) til binært søketre Vi velger en datastruktur slik at gjenfinning kan gjøres ved «oppslag». Eks. hashmap. Hvis vi har lagret personobjekter i en hashmap etter fødselsnr og skal finne en person med et bestemt navn, hva må vi gjøre da? Raskt å finne objekter i et binært søketre når vi leter på samme kriterium som treet er bygget opp etter (compareto()). Christian Andreas Darjan Gry Henrik Jan Jim Nguyen Philip Pål Siv Simen Stian Susanne Tor Torjus Vivi Tankeeksempel: folkeregister i Kina. Stein Michael Storleer 29. april 2008 Ark 8 av 24 Stein Michael Storleer 29. april 2008 Ark 6 av 24
Binærsøk i et sortert array A[ ] I et heltallsarray A[ ] med n elementer skal vi finne en indeks (objektet) hvor verdien er k. A[ ] er sortert slik at A[i 1] A[i], mao. i stigende orden fra 0 og oppover: Søking (forts.) Generelt: Har vi en samling med n objekter som er uordnet, kan vi risikere å måtte undersøke alle n når vi søker ett objekt (med en bestemt egenskap). Forskjellig grad av orden forkorter letetida. A[0] A[1] A[2] A[3] A[n 2] A[n 1] Spesielt (klassisk): Søking etter objekter i en array A[ ]. Hva bør vi gjøre hvis k < A[0] eller k > A[n 1]? Hvis A[0] k A[n 1] har vi følgende idé for algoritme: Sjekk om k er større enn, mindre enn, eller lik elementet midt i arrayen. Hvis ikke lik, «kast» den halvdelen som k ikke kan være i. Uordnet blir det som å lete i det generelle tilfellet. Hvis objektene i arrayet er sortert etter egenskapen vi søker på, kan vi søke langt mer effektivt (færre sammenligninger). I programeksemplene nedenfor bruker vi en array, int a[n] som kanskje inneholder en verdi som vi søker. Stein Michael Storleer 29. april 2008 Ark 11 av 24 Stein Michael Storleer 29. april 2008 Ark 9 av 24 Javametode for å lete etter et element i en sortert array: 1 int binarsok ( int [ ] a, int fra, int til, int k) { 2 int midten; boolean funnet = false ; 3 while ( funnet == false ) { 4 if ( fra > t i l ) { 5 return 1; 6 } else { 7 midten = ( fra + t i l ) / 2; 8 if (k == a[midten ] ) { 9 return midten; 10 } else if (k < a[midten ] ) 11 t i l = midten 1; 12 else fra = midten+1; 13 } 14 } 15 } Lineær søking For å lete etter et element i en usortert array: 1 int linearsok ( int [ ] a, int k) { 2 boolean funnet = false ; 3 int indeks = 0; 4 while ( indeks < a. length &&! funnet ) { 5 if (a[ indeks ] == k) { 6 funnet = true ; 7 } else { 8 indeks++; 9 } 10 } 11 if ( funnet ) { 12 return indeks ; 13 } else { 14 return 1; 15 } 16 } Stein Michael Storleer 29. april 2008 Ark 12 av 24 Stein Michael Storleer 29. april 2008 Ark 10 av 24
Flettesortering Generell idé: Del arrayen opp i delarrayer, slik at hver delarray er sortert (et array med ett element er sortert). Flett sammen to og to arrayer til større sorterte delarrayer til det er et array igjen. 1 1 1 2 1 3 4 7 7 9 11 12 12 13 1 1 2 5 5 6 9 10 11 15 16 17 3 4 5 5 6 7 7 10 11 11 12 12 13 15 16 17 1 1 1 2 3 4 5 5 6 7 7 9 9 10 11 11 12 12 9 9 Javametode for å lete etter et element i en sortert array: 1 int binarsok ( int [ ] a, int fra, int til, int k) { 2 int midten; 3 if ( fra > t i l ) { 4 return 1; 5 } else { 6 midten = ( fra + t i l ) / 2; 7 if (k == a[midten ] ) { 8 return midten; 9 } else if (k < a[midten ] ) { 10 return binarsok (a, fra, midten 1, k ) ; 11 } else { // k > a[midten ] 12 return binarsok (a, midten+1, til, k ) ; 13 } 14 } 15 } Stein Michael Storleer 29. april 2008 Ark 15 av 24 Stein Michael Storleer 29. april 2008 Ark 13 av 24 Innstikksortering Generell idé: Plukk ett og ett element fra listen og sett det inn på rett plass (sortert) i en ny liste. Hvis lista er et array: ❶ Finn første element fra venstre som er mindre enn det til venstre for seg ta dette ut. ❷ Elementene til venstre for dette skyves mot høyre inntil det uttatte elementet passer inn. ❸ Gjenta 1 2 inntil det siste elementet (helt til høyre) er behandlet. Sortering av liste (array) Forutsetter at vi kan rangere elementene: Gitt to elementer: Programmet må kunne teste om det ene elementet er lik, mindre enn eller større enn det andre. Bruk av binærtre Programmeringsidé: Sett objektene inn i et binært søketre. Etter at alle er satt inn, ta dem ut og sett dem inn i arrayet i sortert orden. (krever at objektene har to pekervariabler; må evt. utvide objektene med dette) Boblesortering Generell idé: Gå igjennom arrayet og for hver gang man finner to elementer ved siden av hverandre som ligger feil i forhold til sorteringskriteriet, bytt dem. Gjenta gjennomgangen til ingen bytter blir gjort. Stein Michael Storleer 29. april 2008 Ark 16 av 24 Stein Michael Storleer 29. april 2008 Ark 14 av 24
Forfining av programskissen for quicksort ❶ Hvis antall elementer som skal sorteres er 0 eller 1, returner. ❷ Plukk et ( middels stort ) element fra mengden som skal sorteres. Dette kalles pivot-elementet. ❸ Del resten av elementene i to: De som er mindre enn pivot-elementet. De som er større enn pivot-elementet. ❹ Sorter disse delmengdene hver for seg (ved hjelp av quicksort). ❺ Returner sorteringen av de små elementene, etterfulgt av pivot-elementet, etterfulgt av sorteringen av de store elementene. I programeksemplet nedenfor har vi byttet ut heltallsarrayet med et tegnarray char[] a. 1 void innstikksortering ( char [ ] a) { 2 for ( int k = 0; k < a. length 1; k++) { 3 if (a[k + 1] < a[k ] ) { // a[k + 1] står på f e i l plass 4 char tmp = a[k + 1]; 5 int i = k; 6 while ( i >= 0 && a[ i ] > tmp) { // a[ i ] > tmp, flytt t i l høyre 7 a[ i + 1] = a[ i ] ; 8 i ; 9 } 10 a[ i +1] = tmp; // sett tmp på rett plass 11 } 12 } 13 } Stein Michael Storleer 29. april 2008 Ark 19 av 24 Stein Michael Storleer 29. april 2008 Ark 17 av 24 Quicksort, programidé 1a) Del arrayen i to deler, slik at alle elementer i den ene delen er mindre enn alle elementer i den andre delen. Hvilken sorteringsagoritme bør vi velge? For små arrayer med N 20 er quicksort mindre effektiv enn innstikksortering. 1b) Velg en verdi som finnes i arrayen og bytt to og to elementer ved å starte fra de to endene slik at den ene delen inneholder verdiene som er mindre enn den valgte verdien, den andre delen inneholder verdiene som er større. På grunn av de rekursive kallene vil dette være et vanlig tilfelle! Løsning: Bruk en avskjæring mellom 5 og 20 (vanligvis 10) slik at arraysegmenter mindre enn dette sorteres ved hjelp av innstikksortering. 2) Vi har da tre deler, først en del med elementer mindre enn eller lik den valgte verdi, så ett element med den valgte verdi, til slutt en del med elementer større enn eller lik den valgte verdi. 3) Sorter de to delene rekursivt (ved å starte fra 1). Hvis de to delene blir riktig sortert, vil da hele arrayen være sortert. Ved å søge for at begge delarrayer er kortere enn den vi har er vi sikret at de rekursive kallene går mot basistilfellet. Basistilfellet er en array av lengde 1 eller 0, da trenger vi ikke sortere og det blir ingen rekursive kall. Stein Michael Storleer 29. april 2008 Ark 20 av 24 Stein Michael Storleer 29. april 2008 Ark 18 av 24
Implementasjon av midtenavtre() 1 char midtenavtre(char [ ] a, int fra, int t i l ) { 2 int midten = ( fra + t i l ) / 2; Partisjoneringsstrategi Dette blir lett feil hvis man ikke er nøyaktig! 3 4 if (a[midten] < a[ fra ] ) { 5 bytt (a, fra, midten ) ; 6 } 7 if (a[ t i l ] < a[ fra ] ) { 8 bytt (a, fra, t i l ) ; 9 } 10 if (a[ t i l ] < a[midten ] ) { 11 bytt (a, midten, t i l ) ; 12 } 13 // Skjul pivot elementet nest lengst t i l høyre 14 bytt (a, midten, til 1); 15 return a[ til 1]; 16 } ❶ Få pivot-elementet vekk ved å bytte det med det siste elementet. ❷ La i starte på det første elementet, og j på det nest-siste. ❸ Så lenge i er til venstre for j: 1 Flytt i mot høyre så lenge elementet i peker på er mindre enn pivot-elementet. 2 Flytt j mot venstre så lenge a[j] er større enn pivot-elementet. 3 i peker nå på et stort element og j på et lite. Hvis i er til venstre for j, byttes disse elementene. ❹ Bytt pivot-elementet med elementet i posisjon i. Stein Michael Storleer 29. april 2008 Ark 23 av 24 Stein Michael Storleer 29. april 2008 Ark 21 av 24 Hovedmetoden i quicksort 1 void quicksort (char [ ] a, int fra, int t i l ) { 2 3 /* Hvis fra er nær t i l, sorter direkte /* og returner ( b a s i s tilfellet ). Hvis ikke : */ 4 int pivotindeks ; 5 char pivot = midtenavtre(a, fra, t i l ) ; 6 int i = fra ; int j = t i l 1; 7 while ( true ) { 8 while (a[++ i ] < pivot ) { } 9 while ( a[ j ] > pivot ) { } 10 if ( i < j ) bytt (a, i, j ) ; 11 else break; 12 } 13 pivotindeks = i ; 14 bytt (a, pivotindeks, til 1); 15 quicksort ( a, fra, pivotindeks 1); 16 quicksort (a, pivotindeks+1, t i l ) ; 17 } Hvordan velge pivot-elementet? Ideelt: Et pivot-element som deler mengden i to like store halvdeler. I praksis: Velger pivot-elementet så tilfeldig som mulig. Vi skal bruke midten-av-tre partisjonering: Se på det første, midterste og siste elementet. Velg det mellomste av disse som pivot. Implementasjonen vil også sortere disse tre elementene, samt skjule pivot-elementet. Stein Michael Storleer 29. april 2008 Ark 24 av 24 Stein Michael Storleer 29. april 2008 Ark 22 av 24