Objektorienterad programmering E Algoritmer Sökning Linjär sökning Binär sökning Tidsuppskattningar Sortering Insättningssortering 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,... ). Ett exempel Två gränssnitt Telefonboken Vi vill skriva ett program för att lagra och slå telefonnummer för våra kontakter. Programmet ska ha ett textbaserat gränssnitt. Telefonbokens innehåll läses från fil, varefter man med enkla kommandon kan ge ett namn och begära telefonnummer. lägga till ett nytt par namn/telefonnummer. lista hela telefonbokens innehåll. avsluta programmet. Programmet demokörs på föreläsningen. Programmets design Programmet består av ett objekt book som lagrar data (par namn/telefonnummer) samt en main-rutin, som läser och analyserar användarens kommandon, anropar metoder i book samt skriver ut resultat. Vilka metoder behöver book tillhandahålla? Interfacet PhoneBook public interface PhoneBook extends Iterable<Entry> { public void put(string name, String number); public String get(string name); Interfacet Entry public interface Entry { public String getname(); public String getnumber();
main-rutinen prompt och readfile public static void main(string [] args) { PhoneBook book = new???; readfile(args[0], book); Scanner in = new Scanner(System.in); prompt(); while (in.hasnext()) { docommand(in, book); in.nextline(); prompt(); public static void prompt() { System.out.print("> "); public static void readfile(string file, PhoneBook book) { try { Scanner in = new Scanner(new File(file)); while (in.hasnext()) book.put(in.next(),in.next()); catch (IOException e) { System.out.println("Couldn t open file; book empty"); prompt och readfile public static void docommand(scanner in, PhoneBook book) { String cmd = in.next(); if ("put".equals(cmd)) { else if ("get".equals(cmd)) { else if ("list".equals(cmd)) { else if ("quit".equals(cmd)) { else { System.out.println("Command " + cmd + " unknown"); Att implementera Entry public class MyEntry implements Entry { String name; String phonenr; MyEntry(String name, String phonenr) { this.name = name; this.phonenr = phonenr; public String getname() {return name; public String getnumber() {return phonenr; Kommentar Klassen MyEntry kan med fördel i stället definieras som private static i den klass som implementerar PhoneBook.
Att implementera PhoneBook Tidskomplexitet En enkel implementation Vi börjar med en enkel implementation där Entry-objekten lagras i ett fält. För att definiera en iterator kommer vi att använda en biblioteksmetod som vi inte talat om och som ni inte förväntas känna till. 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? Nyckeln: håll telefonboken sorterad! Sökning 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 -1. 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-1; while (minindex <= maxindex) { int midindex = (minindex + maxindex)/2; if (a[midindex]==key) return midindex; else if (a[midindex] < key) minindex = midindex + 1; else maxindex = midindex - 1; return -1; 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. aslist, som skapar en listvy av ett fält. Lexikografisk jämförelse public class Comparable<T> { int compareto(t o); Klassen String implementerar Comparable<String>. s1.compareto(s2) är <0 om s1 kommer före s2, =0 om strängarna är lika och >0 om s2 kommer före. Hur snabb är binär sökning? Hur sorterar man ett fält? 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 ett söka i. Antalet jämförelser blir därför log 2 n. Exempel För 1 miljon element behövs högst 20 jämförelser. Binär sökning är 50000 gånger snabbare än linjär sökning. Idén med binär sökning är värd att känna till. Ett viktigt problem Sortering 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... ) Insättningssortering I dag betraktar vi en enkel (och i allmänhet inte så bra) metod: insättningssortering. Denna algoritm kan konkurrera om fältet är kort (upp till 10 element). fältet är nästan sorterat (inget element är långt från sin rätta plats).
Insättningssortering Insättningssortering, kod 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-1] redan är sorterat och sorterar in a[i] på rätt plats: sätt in tmp i=4; a[0].. a[3] sorterad 1 2 3 6 8 4 9 4 5 6 5 1 flytta upp stora element tmp=2 (flytta undan a[i]) public static void sort(int[] a) { for (int i=1; i < a.length; i++) { // Assume a[0]..a[i-1] is sorted int tmp = a[i]; int j = i-1; while (j >=0 && tmp < a[j]) { a[j+1] = a[j]; j ; a[j+1] = 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 1) 1 + 2 + 3 +... + (n 1) = 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.