300 likes | 490 Views
Alg. Dat. Øvingsforelesning Magnus Haug magnhaug@idi.ntnu.no. Oversikt. Grafer Litt om terminologi Representasjon av grafer Bredde først søk (BFS) Dybde først søk (DFS) Hashing Hashfunksjoner, hashtabeller Kollisjonshåndtering Øving 2: Redd Ratatosk Øving 3: Kobra lærer å stave.
E N D
Alg. Dat Øvingsforelesning Magnus Haug magnhaug@idi.ntnu.no
Oversikt • Grafer • Litt om terminologi • Representasjon av grafer • Bredde først søk (BFS) • Dybde først søk (DFS) • Hashing • Hashfunksjoner, hashtabeller • Kollisjonshåndtering • Øving 2: Redd Ratatosk • Øving 3: Kobra lærer å stave
Terminologi: Grafer • Node • Kant • Nabo • Sykel • Rettet graf • DAGs • Trær
Generelle grafer vs. trær • Grafer kan ha sykler • Kan oppdage grå eller svarte noder på nytt • Vi må huske hvilke noder vi har sett • Her blir ”farging” nyttig
Representasjon av grafer • En graf defineres ofte som to mengder • G = (V, E). V er alle nodene, E er alle kantene • Nabolister • Hver node i grafen har en liste over sine naboer • Raskest hvis det er få kanter (”sparse graph”) • Nabomatrise • Én stor matrise holder alle nabo-relasjoner • Raskest hvis det er mange kanter (”dense graph”)
Bredde først søk (BFS) • Har en kø over oppdagede (grå) elementer • Vi har et mengde/liste av besøkte noder • Begynn med å legge startnoden i kø • Så lenge det finnes elementer i køen: • Plukk ut en node x fra starten av køen • Legg alle naboer som ikke er besøkte eller oppdagede inn i køen (vi oppdager/gråfarger dem) • Legg x inn i besøkt-settet (farge den sort)
Kode for BFS def bfs(root): queue = Queue() queue.put(root) while len(queue) > 0: node = queue.get() #gjør noe fancy med noden her node.colour = Black for adj in node.adjacent: if adj.colour == White: adj.colour = Grey queue.add(adj)
Bruk av BFS • Enkel måte å traversere en sammenhengende graf • Finne korteste vei fra en node til alle andre, i en uvektet graf • Kan sjekke om en graf er bipartitt • Kjøretid: O(V + E) • Alle noder(V) må besøkes, og alle kanter(E) må sjekkes
Dybde først søk (DFS) • Enklest å implementere rekursivt • Se s. 541 i Cormen for utdyping • Rekursjon har sine svakheter • For mange rekursive kall kan gi programkrasj • Rekursive kall går tregere enn det behøver
Kode for Rekursiv DFS def dfs(node): node.colour = Grey for adj in node.adjacent: if adj.colour == White: dfs(adj) #gjør noe fancy med noden her node.colour = Black
Dybde først søk (DFS) • Iterativ (”Ikke-rekursiv”) variant: • Simulerer rekursjon ved å bruke en stack • Fordel: Raskere, tryggere • Ulempe: Litt mindre intuitiv implementasjon • Åsmund har laget notater om dette • Fagsidene -> Notater -> 2006 -> ”Korrekt DFS” • Alle bør lese dette notatet og prøve å forstå det
Bruk av DFS • Løse oppgaver med én løsning, f.eks. labyrinter • Strongly connected components (neste gang) • Topologisk sortering (neste gang) • Kjøretid: O(V + E) • Alle noder(V) må besøkes, og alle kanter(E) må sjekkes
Hashing og hashtabeller Problemet vi søker en løsning på: Man har et lite/moderat antall elementer, i et stort verdiområde. Hvordan lagre og søke etter disse effektivt? Eks: Telefonnummer og navn på ansatte. Direkte-adressering vil kreve altfor stor plass.
Hvordan løser hashing dette? • Hashing er en måte å konvertere verdier fra et stort utfallsrom til et som er mye mindre. • Hashing gir et form for fingeravtrykk av en verdi. • Vi kan bruke dette til å lagre og hente data effektivt fra en liten og kompakt tabell
Hashtabeller: Fordelene • Oppslag i O(1) tid • Innsetting i O(1) tid • Sletting i O(1) tid O(1) betyr ”konstant tid” Dvs. at hastigheten på operasjonene er ikke avhengig av antall elementer i tabellen • NB! Dette er average-case, ikke worst case
Hashtabeller • En tabell hvor vi får en hash av dataene til å beskrive hvor vi lagrer dem.
Hashing • Hashfunksjon: • h(k) = x • h er hashfunksjonen vi har valgt oss • k er hashnøkkelen, hele eller deler av dataene • x er hashen av nøkkelen, dvs. posisjonen der vi plasserer dataene i en hashtabell
Valg av hashfunksjon • Mål: transformere potensielt store data til en indeks i en tabell • Påkrevd egenskap: Deterministisk • Ønsket egenskap: Uniform fordeling • Ønsket egenskap: Kjapp å utføre
Valg av hashfunksjon Noen eksempler på enkle, gode funksjoner: • Divisjonsmetoden (”modulo-metoden”) • h(k) = k mod m • Multiplikasjonsmetoden • h(k) = m (k A mod 1)
Valg av hashfunksjon Noen eksempler på dårlige hashfunksjoner: • En konstant funksjon: • h(k) = 20 • Java 1.1 (før 1998): • java.lang.String.hashCode() benyttet kun de første 16 bokstavene i en string til å generere hashen.
Håndtering av kollisjoner • Kjeding (”chaining”) • Lagrer en lenket liste i hver hash-bøtte • Hvis vi får mange kollisjoner tar det tid å lete etter elementene • Fordel: Enkelt å implementere • Ulempe: Kan bli tregt, og kan bli en del overhead
Håndtering av kollisjoner • Lineær søking • Hvis det er en kollisjon, prøv neste plass i tabellen • Ulempe: ”Primary clustering” – yter enda dårligere enn kjeding hvis man har mange kollisjoner
Håndtering av kollisjoner • Kvadratisk søking • Hvis det er en kollisjon, prøv å hoppe videre slik: • For hopp i: • Posisjon = (h(k) + c1*i + c2*i2) mod m • Fordel: Yter bedre enn de to forrige • Ulempe: ”Secondary clustering” – kan fremdeles bli problemer hvis mange elementer hasher til samme posisjon
Håndtering av kollisjoner • Dobbel hashing • Bruker 2 hashfunksjoner, h1(k) og h2(k) • Prøv først plass h1(k) i tabellen • Hvis det oppstår kollisjon, prøv å hoppe h2(k) posisjoner videre helt til vi når en åpen plass • Fordel: Enkel og kjapp å implementere
Bruksområder for hashing • Hash tables • Lagre og finne igjen data effektivt – brukes mye! • Bloom filter • Stavekontroll, søkemotorer, osv • Ikke pensum, fremdeles verdt å nevne
Øving 2: Redd Ratatosk • Hvorfor vil BFS være bedre enn DFS her? • Ratatosk har lik sjanse til å være på hvert nivå • Færre noder per nivå nært roten av treet • BFS sjekker da først de mest sannsynlige nodene • Løsningsforslag ligger ute • BFS bruker kø • DFS bruker stakk
Øving 2: Redd Ratatosk • Tweak-løsning • Vi vet allerede hvilken node Ratatosk er i • Trenger ikke å lese all input, og konstruere tre • Husk koblinger ”barn->forelder”, fremfor andre veien • La Ratatosk ”klatre ned” treet ved å følge koblingene • Denne spesifikke løsningen er ikke eksamensrelevant
Øving 3: Kobra lærer å stave • def bygg(ordliste): • Skal bygge et tre ut fra ei liste av (ord, posisjon) • Skal returnere rot-noden • def posisjoner(ord, indeks, node): • Skal returnere ei liste av posisjoner der ”ord” matcher • Hvis man møter spørsmålstegn, må man sjekke alle subtrær rekursivt, ved å spesifisere indeks og node i nye kall til posisjoner