Inf 1020 Algoritmer og datastrukturer Et av de mest sentrale grunnkursene i informatikkutdanningen... og et av de vanskeligste! De fleste 3000-kursene i informatikk bygger på Inf1020 Kurset hever programmering fra et håndtverk til et universitetsfag! Et arbeidskrevende modningsfag! Dere bør bruke tid på å løse oppgaver gjennom hele semesteret. Det gis 3 obliger. Den første gis i begynnelsen av september og skal besvares individuelt. De to neste gis i siste halvdel av semesteret og kan gjøres i grupper på 2 (eller alene). Sjekk fagets hjemmeside regelmessig. Forelesningsplanen kan bli endret underveis! Forelesninger og øvinger viser hva av pensum/læreboka som vi legger vekt på til eksamen Ark 1 av 31 Forelesning 16.8.2004
Hva er en algoritme? Vanlig sammenligning: Oppskrift Input Algoritme Output Knuth : I tillegg til å være et endelig sett med regler som gir en sekvens av operasjoner for å løse en bestemt type problem, har en algoritme fem viktige kjennetegn: 1. Endelighet. 2. Definerthet. 3. Input. 4. Output. 5. Effektivitet. Donald E. Knuth: The Art of Computer Programming. Volume 1/Fundamental Algorithms. Forelesning 16.8.2004 Ark 2 av 31
Analyse av tidsforbruk Hvor mye øker kjøretiden når vi øker størrelsen på input? To typer analyse: Gjennomsnittlig tidsforbruk (average-case) Verste tilfelle (worst-case) Alternative metoder: Kode algoritmen og ta tiden for ulike størrelser på input. Finne en enkel funksjon som vokser på samme måte som eksekveringstiden til programmet. Forelesning 16.8.2004 Ark 3 av 31
Eksempel: Oppslag i telefonkatalog Input: Telefonkatalog med n navn, et navn P på personen vi vil ringe til. Output: Nummeret til P (hvis det står i katalogen). Algoritme 1 Let gjennom katalogen fra begynnelsen og sammenlign hvert navn med P. Tidsforbruk: I verste tilfelle må vi lete igjennom hele katalogen med n navn. Dette angir vi med O(n). Algoritme 2 (binær-søking) Sammenlign P med det midterste navnet i katalogen og finn hvilken halvdel P eventuelt står i. Let videre i denne halvdelen på samme måte. Tidsforbruk: For hver sammenligning halverer vi den delen av katalogen vi må lete i. Dette angir vi med O(log n). Forelesning 16.8.2004 Ark 4 av 31
Logaritmer Logaritmer har et grunntall X, for eksempel X = 2 eller X = 10. Vi bruker stort sett X = 2. Logaritmen til et tall B er det tallet A vi må opphøye grunntallet X i for å få B, det vil si: X A = B A = log X B Eksempler: 2 1 = 2 1 = log 2 2 2 2 = 4 2 = log 2 4 2 3 = 8 3 = log 2 8 2 4 = 16 4 = log 2 16 2 10 = 1 024 10 = log 2 1 024 2 20 = 1 048 576 20 = log 2 1 048 576 Forelesning 16.8.2004 Ark 5 av 31
O-notasjon Generelt er vi ikke interessert i nøyaktig hvor mye tid et program bruker, men heller prøve å angi i hvilken størrelsesorden løsningen ligger. Definisjon La T(n) være kjøretiden til programmet. T(n) =O(f(n)) hvis det finnes positive konstanter c og n 0 slik at T(n) c f (n) når n > n 0. O( f (n)) er da en øvre grense for kjøretiden. Problemet er å finne en f (n) som er minst mulig. O-notasjon er en veldig grov måte å angi tidsforbruk på, og vi forkorter så mye som mulig. Merk at konstanter allerede ligger i definisjonen. Forelesning 16.8.2004 Ark 6 av 31
Vanlige funksjoner for O( ) Funksjon Navn 1 Konstant log n Logaritmisk n Lineær nlogn n 2 Kvadratisk n 3 Kubisk 2 n,n! Eksponensiell Med input n = 10 5 og 10 6 operasjoner pr. sekund får vi flg. eksekveringstider: Funksjon Navn 1 10 6 sek. log n 1, 2 10 5 sek. n 0,1 sek. nlogn 1,2 sek. n 2 2,8 timer n 3 31,7 år 2 n mer enn et århundre Forelesning 16.8.2004 Ark 7 av 31
Eksempler: n/2, n, 2n er alle O(n). n 2 + n + 1 regnes som O(n 2 ). log 2 n,oglog 10 n skilles bare av en konstant, begge angis med O(log n). Enkel beregning av tid Enkel setning: x=y+z; Enkel for-løkke: for (int i = 0; i < n; i++) { brukt[i] = false; Forelesning 16.8.2004 Ark 8 av 31
Nestede for-løkker: for (int i = 0; i < n; i++) { for (int k = 0; k < n; k++) { avstand[i][k] = 0; Sekvens av setninger: x=y+z; for (int i = 0; i < n; i++) { brukt[i] = false; Betinget setning: if (n < 0) { System.out.println( Ingen elementer ); else{ for (int i = 0; i < n; i++) { sum+=i; Forelesning 16.8.2004 Ark 9 av 31
Abstrakte datatyper En abstrakt datatype (ADT) er definert ved en mengde operasjoner og en spesifikasjon av hva disse operasjonene gjør. Dermed skilles definisjonen av operasjonene i ADTen fra implementasjonsdetaljer. I Java er det naturlig å spesifisere en ADT som et interface og realisere dem som klasser som implementerer interfacet (NB! Læreboka gjør ikke dette!) (class ExImplem implements ExADT {... Semantikken til operasjonene i en ADT kan ofte tegnes En god ADT støttes opp av gode intuisjoner og har informative navn Gode valg av ADTer gjør en kode lett å lese og lett og forstå. Dette er kjennetegn ved god design! Å tenke i form av ADTer er en god tilnærming til programmering! Programming is the art of abstraction Forelesning 16.8.2004 Ark 10 av 31
Standard ADTer Noen ADTer er så vanlige at de har blitt standard innen databehandling. De er generelle og brukes i nesten alle programmer av en viss kompleksitet. I informatikk-faget er det basalkunnskap å kjenne til definisjonen av dem, standard implementasjoner og viktige eksempler på bruk. I kurset lærer vi de viktigste av disse fundamentale ADTene. For hver ADT skal vi se på: Betydningensemantikken) Operasjonene (grensesnittet) Forskjellige implementasjoner Tidsforbruket til operasjonene Eksempler på bruk Idag: lister, køer og stakker. Vi ser på både statiske og dynamiske implementasjoner og bruker O-notasjon til å angi deres kompleksitet. Forelesning 16.8.2004 Ark 11 av 31
ADT Liste ADTen liste modellerer det de fleste forbinder med begrepet liste, nemlig en liste av elementer: A 1, A 2,...,A n. Vi kan lage mange forskjellige ADTer for lister avhengig av hvilket grensesnitt vi definerer for den. Grensesnittet (dvs ADTen) definerer hvilke operasjoner vi kan utføre på lister, men sier ingenting om hvordan disse operasjonene blir utført. Legg merke til at det å finne ut en effektiv koding av operasjonene er en helt annen oppgave enn det å bruke dem! Forelesning 16.8.2004 Ark 12 av 31
Mulig grensesnitt for lister public interface ListeInterface { /* Sette inn et element på en gitt plass */ void insert(object x, int posisjon); /* Slette et gitt element fra listen */ void remove(object x); /* Sjekke om et element finnes i listen */ boolean find(object x); /* Få tak i elementet på en angitt plass */ Object findkth(int k); /* Skrive ut alle elementene i listen */ void printlist(); /* Sjekke om listen er tom */ boolean isempty(); /* Tømme (nullstille) listen */ void makeempty(); Forelesning 16.8.2004 Ark 13 av 31
I grensesnittet på forrige foil styres utskriften av listen fra listen selv. En mer generell løsning er å styre denne fra klassen som bruker listen (hvorfor?). Dette kan gjøres ved å bruke en iteratorklasse, f.eks. Java interface Enumeration med metodene public Boolean hasmoreelements() public Object nextelement() Vi kan da utvide ADT Liste med en metode public Enumeration elementer() Liste l = new KlasseSomImplementererListe();... Enumeration e=new l.elementer(); while ( e.hasmoreelements() ) { Object o=l.nextelement(); // Handling med o, f.eks. Sysem.out.println(o); Forelesning 16.8.2004 Ark 14 av 31
Array-implementasjon A1 A2 A3 A4 An insert: O(n). For eksempel vil innsetting først i listen føre til at vi må flytte alle de n-1 andre elementene ett hakk oppover i arrayen. remove: O(n) (tilsvarende som over). find: O(n) så bra som man kan forvente. findkth: O(1) positivt! printlist: O(n). isempty: O(1). makeempty: O(1). Problem: Arrayer kan ikke vokse dynamisk etter behov størrelsen må bestemmes når de opprettes. Ved overflow må vi enten lage en ny array og kopiere innholdet (en O(n)-operasjon) eller terminere programmet. Forelesning 16.8.2004 Ark 15 av 31
Pekerkjede-implementasjon A1 A2 A3 A4 Fjerning av element A3: A1 A2 A3 A4 Innsetting av element X: A1 A2 A3 A4 X class Node { Object element; Node neste; public Node(Object x, Node n) { element = x; neste = n; Forelesning 16.8.2004 Ark 16 av 31
insert: O(1) dersom vi allerede har funnet stedet der elementet skal settes inn. remove: O(1) (tilsvarende som for insert). find: O(n). findkth: O(n) må gå gjennom k-1 elementer for å komme til element k. printlist: O(n). isempty: O(1). makeempty: O(1). Dersom vi inkluderer tiden vi bruker på å finne riktig sted, blir innsetting og sletting O(n), men med svært liten konstant. MERK: Innsetting og sletting blir veldig raske i gjennomsnitt dersom vi som oftest setter inn først/tidlig i listen. Forelesning 16.8.2004 Ark 17 av 31
Alternative pekerkjede-implementasjoner Pekerkjede med hode: Hode A1 A2 A3 A4 Toveis pekerkjede: A1 A2 A3 A4 Sirkulær pekerkjede (med hode): Hode A1 A2 A3 A4 Toveis pekerkjede med hode og hale, toveis sirkulær pekerkjede... Variant: sortert liste Find blir fortsatt O(n) hvis vi bruker pekerkjede, men O(log n) hvis vi bruker array og binærsøk. Forelesning 16.8.2004 Ark 18 av 31
Stakker ADTen stakk modellerer det vi tenker på som en stabel av et eller annet, for eksempel tallerkner. Dette er en variant av lister, men i en stakk har vi bare lov til å sette inn og slette elementer fra en bestemt ende av listen. Inn Ut Eksempler: Metodekall i Java Enkle kalkulatorer En full buss Forelesning 16.8.2004 Ark 19 av 31
Stakk-grensesnitt public interface Stakk { /* Legge et element på toppen av stakken */ void push(object x); /* Fjerne et element fra toppen av stakken */ void pop(); /* Returnere elementet på toppen av stakken */ Object top(); /* Sjekke om stakken er tom */ boolean isempty(); Ofte vil pop også returnere elementet som fjernes. En stakk er det samme som en LIFO-liste ( Last In First Out ). Forelesning 16.8.2004 Ark 20 av 31
Array-implementasjon 4 3 2 1 0 A4 A3 A2 A1 S stakktopp Brukes ofte hvis antall elementer på stakken alltid er begrenset. public void push(object x) { stakktopp++; S[stakkTopp] = x; public void pop() { stakktopp--; public Object top() { return S[stakktopp]; I tillegg: eventuell feilhåndtering. Forelesning 16.8.2004 Ark 21 av 31
Pekerkjede-implementasjon Datastruktur, push og pop Datastrukturen ser slik ut: S A4 A3 A2 A1 Innsetting og sletting vil (normalt) alltid skje på begynnelsen av listen: S A4 A3 A2 A1 X S A4 A3 A2 A1 Forelesning 16.8.2004 Ark 22 av 31
Implementasjon i Java public class PekerStakk implements Stakk { private class Node { Object element; Node neste = null; private Node topp = null; public PekerStakk() { topp = null; public void push(object x) { Node ny = new Node; ny.element = x; ny.neste = topp; topp = ny; public void pop() { if (topp!= null) topp = topp.neste; public Object top() { if (topp!= null) return topp.element; else return null; public Boolean isempty() { return topp == null; Forelesning 16.8.2004 Ark 23 av 31
Stakkoperasjonene - tidsforbruk Uansett hvor mange elementer vi har på stakken, er vi garantert konstant tidsforbruk, det vil si O(1) for alle operasjonene. Dette gjelder uansett om implementasjonen bruker en array eller en pekerkjede. Bedre er det ikke mulig å få det, derfor er stakken en veldig populær ADT. Samtidig kan mange naturlige problemer løses ved hjelp av en stakk. Typisk bruksmønster er mange stakk-operasjoner, men få elementer på stakken om gangen. På mange maskiner kan disse oversettes til kun to-tre instruksjoner i maskinkode. Forelesning 16.8.2004 Ark 24 av 31
Eksempel: Beregning av postfiks uttrykk På de fleste kalkulatorer skriver man inn regneuttrykkene på såkalt infiks form, med operatorene mellom argumentene: 4+2=6 3+5*2=13 (3 + 5) * 2 =16 Et alternativ er å skrive uttrykkene på postfiks form, der operatorene står etter argumentene. Med denne notasjonen slipper man å bruke parenteser: 42+=6 352*+=13 35+2*=16 Forelesning 16.8.2004 Ark 25 av 31
Ved hjelp av en stakk er det lett å beregne et postfiks uttrykk på følgende måte: For hvert symbol i input: Hvis symbolet er et tall, legges det på stakken. Hvis symbolet er en operator, popper vi to tall fra stakken, anvender operatoren på disse to tallene og dytter svaret tilbake på stakken. Hvis input var et ekte postfiks uttrykk, vil nå svaret ligge som det eneste elementet på stakken. Eksempel: 6523+8* +3+* Forelesning 16.8.2004 Ark 26 av 31
Køer ADTen kø modellerer stort sett det vi tenker på som en kø. En kø er en variant av en liste, men hvor vi setter inn elementer i den ene enden og tar ut elementer fra den andre enden: Inn Ut Bak Foran Mulig interface: public interface Koe { /* Legge til et element sist i køen (enqueue) */ void settinn(object x); /* Fjerne elementet først i køen (dequeue) */ Object taut(); /* Sjekke om køen er tom */ boolean isempty(); Dette kalles også en FIFO-liste ( First in First Out ). Forelesning 16.8.2004 Ark 27 av 31
Kø: Pekerkjede-implementasjon Vi har en enkel pekerkjede der vi har en ekstrapeker til siste element: 4 3 9 6??? Hva bør være foran og bak i denne køen???? Hva blir tidsforbruket? Forelesning 16.8.2004 Ark 28 av 31
Kø: Array-implementasjon 5 7 3 9 Vi har to heltallsvariable som peker på første og siste element i køen. Hvis køen lever lenge og det er mange inn/ut-operasjoner, kan vi nå enden av arrayen selv om det bare er noen få elementer i køen! Løsning: Bruk en såkalt sirkulær array, hvor pekerne flyttes tilbake til begynnelsen etter at de har nådd enden av arrayen. Det kan bli litt fiklete kode, men operasjonene er veldig tidseffektive. Forelesning 16.8.2004 Ark 29 av 31
Eksempel: Palindromer Palindromer er ord/uttrykk/setninger som er like forlengs og baklengs. Kjente eksempler: Otto ABBA Radar Svensk: Ni talar bra latin Dansk: En af dem der red med fane Engelsk: If I had a Hi-fi Hvordan sjekke om en gitt tekst-streng er et palindrom? Forelesning 16.8.2004 Ark 30 av 31
Mulig løsning 1. Les tekst-strengen inn i både en stakk og en (FIFO-)kø. 2. Sammenlign innholdet i stakken og køen tegn for tegn. public void sjekkpalindrom(string setning, Stakk s, Koe q) { while (! setning.equals("")) { char bokstav = setning.charat(0); setning = setning.substring(1); if (! Character.isWhitespace(bokstav)) { q.settinn(new Character(bokstav)); s.push(new Character(bokstav)); while (! q.isempty()) { if (!q.taut().equals(s.top()) ) { System.out.println("Dette er ikke et palindrom."); System.exit(1); s.pop(); System.out.println("Gratulerer, dette er et palindrom"); Forelesning 16.8.2004 Ark 31 av 31