1 Enkle datastrukturer, trær, traversering og rekursjon Magnus Moan (Undertegnede) algdat@idi.ntnu.no Enkle datastrukturer, trær, traversering og rekursjon
2 Dagens plan Praktisk Enkle datastrukturer Stack Kø (queue) Trær og binære søketrær Traversering Dybde-først-søk Bredde-først-søk Tips til øving 2: Ratatosk LF til øving 1: Sprengstoff
3 Stack Implementerer Last-In-First-Out (LIFO) To hovedoperasjoner: push(x), legger elementet x på toppen av stacken pop(), tar ut øverste element Kan også lese øverste element ute å fjerne det
4 Stack i Python Kan bruke list til å implementere stack list.append(x) implementerer push(x) list.pop() implementerer pop list[-1] leser toppen
5 Kø (queue) Implementerer First-In-First-Out (FIFO) Tenk på som en vanlig kø To hovedoperasjoner: enqueue(x) - legge et element bakerst i køen dequeue() - ta ut det første elementet i køen
6 Kø i Python Kan bruke list til å implementere stack list.append(x) implementerer enqueue(x) list.pop(0) implementerer dequeue() Denne implementasjonen er treg da den må flytte samtlige element i listen
7 Kø i Python Bruk heller collections.deque Gir støtte for rask innsetting og fjerning i begge ender Deque.append(x) implementerer enqueue(x) Deque.popleft() implementerer dequeue()
8 Traversering av binære trær Postorder traversering Traverser først over alle barna Så gjør noe med noden Preorder traversering Gjør noe med noden Traverser over alle barna Inorder traversering (kun for binære trær) Gjør noe med venstre barn Gjør noe med denne noden Gjør noe med høyre barn
9 Trær I Algdat: «Connected, asyclic graph» Består av noder Noder består av: Data, kan være hva som helst Pekere til barn Eventuelt pekere til søsken Noder uten barn: Løvnoder Node uten foreldre: Rot Binære trær: Maks to barn per node
10 Rekursjon En metode som kaller seg selv OBS: Ikke ha for mange rekursive kall
11 Binære søketrær Data sammenliknbart, f.eks. integers All data i venstre subtre mindre enn roten All data i høyre subtre større enn roten Søk, sletting og innsetting svært effektivt når høyden er logaritmisk
12 Søk i binære søketrær Vil finne element x i søketreet For hver node: Sammenlign node.data med x Hvis x = node.data Ferdig, finnes! Hvis x < node.data Hvis node.left = None Ferdig, finnes ikke! Ellers Let i node.left Tilsvarende hvis x > node.data
13 Innsetting og sletting i søketrær Innsetting: Søk etter elementet i treet Hvis det ikke finnes Sett det inn der det burde finnes Hvis det finnes Ferdig, med mindre du ønsker duplikater Sletting: Mer omfattende Sletting av løvnoder er enkelt Sletting av interne noder er mer komplisert Implementasjon av dette taes senere
14 Traversering av generelle trær I algdat: Bredde-først-søk og dypde-først-søk Dybde i et tre: Antall kanter fra rot til aktuell node
15 BFS Benytter datastrukturen queue Sjekker alle «søsken» før den går videre Brukes til å finne korteste vei når alle kanter har lik vekt Brukes blant annet for å løse maks flyt problemer
16 BFS 1 procedure BFS(G, v): 2 create a queue Q 3 enqueue v onto Q 4 mark v 5 while Q is not empty: 6 t Q.dequeue() 7 if t is what we are looking for: 8 return t 9 for all edges e in G.adjacentEdges(t) do 10 u G.adjacentVertex(t,e) 11 if u is not marked: 12 mark u 13 enqueue u onto Q 14 return none
17 DFS Benytter datastrukturen stack Sjekker alle barn rekursivt før den går videre Relativt kjappere enn BFS om du vet noden ligger dypt i treet
18 DFS 1 procedure DFS(G,v): 2 mark v as discovered 3 if v is what we are looking for: 4 return v 5 for all edges e in G.adjacentEdges(v) do 6 w G.adjacentVertex(v,e) 7 if vertex w is not discovered then 8 recursively call DFS(G,w) 9 label v as explored
19 Kanttyper Tree edge Peker på et barn Forward edge Peker på en ferdigprosessert etterkommer som ikke er et barn Back edge Peker på en ikke ferdigprosessert forfader Cross edge Peker på et annet subtre Om det ikke er noen av de andre er det sannsynligvis en cross
20 MERK: DFS og BFS er generelle algoritmer og skal kunne brukes på alle grafer. For denne øvingen er det derimot tilstrekkelig å implementere en forenklet utgave
21 Ukas praksis: Redd Ratatosk! Skal implementere BFS og DFS for søk i tre Returner dybden Ratatosk befinner seg på
22 Ukas rammeverk class Node: barn = None ratatosk = None nestebarn = None # bare til bruk i DFS def init (self): self.barn = [] self.ratatosk = False self.nestebarn = 0
23 Ukas rammeverk def dfs(rot): # SKRIV DIN KODE HER def bfs(rot): # SKRIV DIN KODE HER
24 Ukas rammeverk funksjon = stdin.readline().strip() antall_noder = int(stdin.readline()) noder = [] for i in range(antall_noder): noder.append(node()) start_node = noder[int(stdin.readline())] ratatosk_node = noder[int(stdin.readline())] ratatosk_node.ratatosk = True for linje in stdin: tall = linje.split() temp_node = noder[int(tall.pop(0))] for barn_nr in tall: temp_node.barn.append(noder[int(barn_nr)])
25 Ukas rammeverk if funksjon == 'dfs': print dfs(start_node) elif funksjon == 'bfs': print bfs(start_node) elif funksjon == 'velg': print 'Velg'
26 Ukas input Linje 1: Angir hvilken metode som blir kalt, 'BFS', 'DFS' eller 'Velg' Linje 2: Angir antall noder i treet Linje 3: Angir hvilken node som er roten Linje 4: Angir hvilken node Ratatosk befinner seg i Resten: Nodene og deres barn/etterkommere
27 Spørsmål?
28 Forrige ukes øving: Sprengstoff def spor(kubbe): # START IKKE-UTDELT KODE maks = -1 while kubbe!= None: if kubbe.vekt > maks: maks = kubbe.vekt kubbe = kubbe.neste return maks # SLUTT IKKE-UTDELT KODE