Objektorienterad programmering E Algoritmer Linjär sökning Binär sökning Tidsuppskattningar Föreläsning 9 Vad behöver en programmerare kunna? (Minst) ett programspråk; dess syntax och semantik, bibliotek och programmeringsstil. Standardlösningar till standardproblem; hur tidskrävande är vanliga problem (för datorn)? Hittills har vi fokuserat på den första punkten; vi ska nu börja titta litet på den andra. Vi kan bara skumma på ytan; här finns material till flera kurser (Datastrukturer, Algoritmer, Avancerade algoritmer,... ). Telefonboken, påminnelse (och litet tillägg), Entry.java public class Entry { private String name; private String number; public Entry(String name, String number) { this.name = name; this.number = number; public String getname() {return name; public String getnumber() {return number; public String tostring() { return name + "_" + number; Telefonboken, påminnelse (och litet tillägg), 2 Phonebook.java public interface PhoneBook extends Iterable<Entry> { public void put(string name, String phonenr); public String get(string name); SimplePhoneBook.java, början public class SimplePhoneBook implements PhoneBook { private Entry[] entries; private int count; public SimplePhoneBook(int size) { entries = new Entry[size]; count = 0; private String get(string name) { for (int i=0; i < count; i++) if (entries[i].getname().equals(name)) return entries[i].getnumber(); return null;
Resten av programmet Tidskomplexitet main-rutinen Här läses kommandon från användaren och anropas get och put i telefonboken för att söka och lägga till telefonnummer. Hur bra eller dåligt är detta? Hur stora telefonböcker kan programmet hantera? En persons privata vänner? Ett företags anställda och kontakter? Sveriges befolkning? För att bedöma tidsåtgång för att köra programmet kan vi tänka så här: Antag att telefonboken innehåller n par. Hur många jämförelser (med equals) mellan strängar kan behövas för att sätta in ett nytt par? för att hitta ett nummer för ett givet namn? I bägge fallen kan vi behöva titta på alla par, dvs n jämförelser behövs. Kan vi göra något bättre? Lösningen: håll telefonboken sorterad! i heltalsfält Precis som i telefonkatalogen bör vi lagra paren sorterade efter namn. Vi måste implementera om klassen. Problem att lösa: Hur gör man insättning för att hålla boken sorterad? Hur söker man i en sorterad bok? Hur jämför man strängar för att avgöra vilken som ska komma först i boken (i lexikografisk ordning)? Ett enklare problem Vi börjar med sökning och med ett förenklat problem: Givet ett sorterat fält a av heltal och ett heltal key, finn den position i a som innehåller key. Vi definierar public static int search(int[] a, int key); Resultatet ska vara positionen, dvs index i fältet a. Om key inte alls finns, ska resultatet bli -. Förvillkor När vi skriver search, antar vi att fältets element är sorterade i växande ordning. Om fältet inte är sorterat är funtionens resultat ospecificerat; det är ett fel av användaren av search att anropa funktionen i sådana fall.
Binär sökning public static int binarysearch(int[] a, int key) { int minindex = 0; int maxindex = a.length-; while (minindex <= maxindex) { int midindex = (minindex + maxindex)/2; if (a[midindex]==key) return midindex; else if (a[midindex] < key) minindex = midindex + ; else maxindex = midindex - ; return -; Mer ur Java API Klassen Arrays Klassen Arrays är ett funktionsbibliotek. Det innehåller ett antal användbara (statiska) funktioner som arbetar på fält, däribland binarysearch för många olika typer av fält. sort, som sorterar ett fält, också för många olika typer. Lexikografisk jämförelse: java.lang.comparable public int Comparable<T> { int compareto(t o); Klassen String implementerar Comparable<String>. s.compareto(s2) är <0 om s kommer före s2, =0 om strängarna är lika och >0 om s2 kommer före. Binär sökning i telefonboken? Vad behövs? Vi har ett fält vars element har typ Entry. Vad menas med att ett sådant fält sorterat? Hur jämför man två objekt av typen Entry? Entry, förbättring public class Entry implements Comparable<Entry> { public int compareto(entry o) { return name.compareto(o.getname()); Hur definierar man put så att fältet fortsätter att vara sorterat? Hur snabb är binär sökning? Om ett sorterat fält innehåller n element, hur många jämförelser mellan element (med compareto) kan behövas för att hitta ett givet element? Varje jämförelse halverar det intervall man har att söka i. Antalet jämförelser blir därför log 2 n. Exempel För miljon element behövs högst 20 jämförelser. Binär sökning är då 0000 gånger snabbare än linjär sökning. Idén med binär sökning är värd att känna till!
Mer ur Arrays Avslutande kommentarer om telefonboken aslist, som skapar en lista av ett fält. copyof, som gör en kopia av en del av ett fält. Exempel (som ni inte behöver kunna) I telefonboken kan vi därför definiera public Iterator<Entry> iterator() { List list = Arrays.asList(Arrays.copyOf(entries,count)); return list.iterator(); Titta i lect9code.zip Här finns en variant av telefonboksprogrammet, med följande förbättringar: Två implementationer av PhoneBook: SimplePhoneBook, som använder linjär sökning. BetterPhoneBook, som använder binär sökning. En förbättrad Main: Ett filnamn tas som kommandoradsargument. Telefonboken läses från och skrivs till filen i början resp slutet av programmet. Nytt kommando: lista alla par. Ny datafil: engelsk-svenskt lexikon (2000 ord). Hur sorterar man ett fält? Ett viktigt problem behövs i otaliga sammanhang. Det är viktigt att kunna sortera effektivt. Det finns många kända algoritmer för sortering (quicksort, mergesort, heapsort... ) Arrays.sort använder sig av quicksort eller mergesort beroende på elementens typ. Idé Vi vill sortera fältet a. Vi gör detta genom att sortera längre och längre initialdelar av a. I steg i antar vi att delfältet a[0].. a[i-] redan är sorterat och sorterar in a[i] på rätt plats: i=; a[0].. a[3] sorterad I dag betraktar vi en enkel (och i allmänhet inte så bra) metod: insättningssortering. Denna algoritm kan konkurrera om 3 8 2 9 fältet är kort (upp till 0 element). fältet är nästan sorterat (inget element är långt från sin rätta plats). i=; a[0].. a[3] sorterad 3 8 9
, kod public static void sort(int[] a) { for (int i=; i < a.length; i++) { // Assume a[0]..a[i-] is sorted int tmp = a[i]; int j = i-; while (j >=0 && tmp < a[j]) { a[j+] = a[j]; j--; a[j+] = tmp; // Now a[0]..a[i] is sorted Tidskomplexitet för insättningssortering Om fältet har n element, hur många jämförelser mellan tal kan behövas för att sortera det? Värsta fallet är när fältet är sorterat i fel ordning. Antalet jämförelser blir då jämförelser. Standardbeteckning n(n ) + 2 + 3 +... + (n ) = 2 Vi säger att insättningssortering har komplexitet O(n 2 ). När fältet blir dubbelt så långt tar det fyra gånger så lång tid att sortera.