Övning 3. Problemträd, breddenförst, djupetförst, hashning. Skriv ett program som läser personers namn och födelsedag från fil.

Relevanta dokument
Övning 3 - Tillämpad datalogi 2012

Övning 1 - Abstrakta datatyper

DD1320 Tillämpad datalogi. Lösning (skiss) till tenta 20 okt 2011

Övning 1. Abstrakta datatyper. 1. Stacken. class Stack: """A representation of a last-in-first-out (LIFO) stack of objects."""

Länkade listor, stackar och köer

Övning 2. (Länkade) Listor, noder

Grundläggande datalogi - Övning 1

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

DD1314 Programmeringsteknik

Fredag 10 juni 2016 kl 8 12

Datalogi, grundkurs 1

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

Föreläsning 10 Datalogi 1 DA2001. Utskrift på skärmen. Syntax. print( Hej ) Hur är det? Hej. print( Hej,end= ) print( Hur är det? ) HejHur är det?

Sätt att skriva ut binärträd

Föreläsningsanteckningar, Introduktion till datavetenskap HT S4 Datastrukturer. Tobias Wrigstad

Föreläsning 2 Programmeringsteknik DD1310. Programmering. Programspråk

Föreläsning 13 och 14: Binära träd

Grundläggande datalogi - Övning 2

1/15/2013. DD1310/DD1314/DA3009 Programmeringsteknik. Lärandemål... Vilka läser kursen? ...fler lärandemål VARFÖR? Föreläsning 1

DD1310/DD1314/DA3009 Programmeringsteknik LÄRANDEMÅL... Vilka läser kursen? ...FLER LÄRANDEMÅL. Föreläsning 1

Föreläsning 2 Programmeringsteknik och Matlab DD1312. Programspråk. Utskrift på skärmen

Tentamen i Introduktion till programmering

Grafer, traversering. Koffman & Wolfgang kapitel 10, avsnitt 4

Föreläsning 2 Programmeringsteknik och C DD1316. Programmering. Programspråk

Python. Vi har ofta behov av att behandla datastrukturer på ett enhetligt sätt så att vi kan göra samma sak i flera olika program.

Inom datalogin brukar man använda träd för att beskriva vissa typer av problem. Om man begränsar sig till träd där varje nod förgrenar sig högst två

Övning 6. Komprimering, kryptering, dokumentering & testning

Föreläsning 2 Programmeringsteknik DD1310. Programmering. Programspråk

Grundläggande datalogi - Övning 3

729G04 Programmering och diskret matematik

Sammanfattning. Listor. List-manipulering. Matris. /home/lindahlm/activity-phd/teaching/11dd1310/exercise3/exercise3.py September 13, 20111

Algoritmer, datastrukturer och komplexitet

Algoritmer, datastrukturer och komplexitet

Föreläsning 2 Programmeringsteknik och Matlab DD1312. Programspråk. Utskrift på skärmen

Grundläggande datalogi - Övning 4

Några inbyggda funktioner (med resultat!) Introduktion till programmering D0009E. Föreläsning 4: Villkor och rekursion. Modulus-operatorn.

Att skriva till och läsa från terminalfönstret

Föreläsning 6: Introduktion av listor

TDP002 - Imperativ programmering

Användarhandledning Version 1.2

Övning 6. Ali Tofigh 24 Oktober, 2006

Uppgifter teknik HT17 (uppdaterad v. 40)

Hur man programmerar. Exempel på problemlösning i Python

Introduktion till programmering SMD180. Föreläsning 2: Variabler, uttryck och satser

Kungl. Tekn. Högskolan Förel 1, bild 1 Föreläsning 1: Introduktion ffl Kursinnehåll ffl Javarepetition ffl Referenser ffl Nyckelordet static ffl Klass

Föreläsning 2 Programmeringsteknik och C DD1316

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

729G04 Programmering och diskret matematik. Föreläsning 7

Övningsuppgifter kapitel 8

Filer. DA2001 (Föreläsning 16) Datalogi 1 Hösten / 19

Föreläsning 8 Programmeringsteknik och Matlab DD1312. Klassmetod. Egen modul

Datalogi I, grundkurs med Java 10p, 2D4112, Fiktiv tentamen, svar och lösningar och extra kommentarer till vissa uppgifter 1a) Dividera förs

Den klassiska programmodellen. Introduktion till programmering D0009E. Föreläsning 11: Filer och undantag. Filsystem. Interaktiva program.

Föreläsning 7: Prioritetskö, trappa heapsort, hashning

Namn: (Ifylles av student) Personnummer: (Ifylles av student) Tentamensdatum: Tid: Hjälpmedel: Inga hjälpmedel

Kodexempel från Programmering 2 Tobias Wrigstad, Ph.D.

Alla datorprogram har en sak gemensam; alla processerar indata för att producera något slags resultat, utdata.

Pythons standardbibliotek

Idag: Centrerad utskrift. Granskning. DD1311 Programmeringsteknik med PBL. Granskning Felhantering GUI. Föreläsning 15.

Datalogi för E Övning 3

Föreläsning 8 Datastrukturer (DAT037)

Övning 0. Python för den som kan MATLAB. Lättare att läsa färdig kod än att skriva själv Det krävs övning för att automatiskt få detaljerna rätt:

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Tentamen, Algoritmer och datastrukturer

TDDI16: Datastrukturer och algoritmer

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

Lösningar Datastrukturer TDA

Ordlistor, filhantering och ut på webben. Linda Mannila

Graphs (chapter 14) 1

Tentamen TEN1 HI

Detta dokument är ett exempel, cirka hälften av en tentamen för TDA545 Objektorienterad programvaruutveckling

Abstrakta datatyper Laboration 2 GruDat, DD1344

Besiktningsprotokollet

Språket Python - Del 1 Grundkurs i programmering med Python

Föreläsning 4. Kö Implementerad med array Implementerad med länkad lista Djup kontra bredd Bredden först mha kö

Några saker till och lite om snabbare sortering

DD1321, Tentamen i tillämpad programmering och datalogi Lördagen den 18 dexember 2010 kl 13 18

Tentamen i Algoritmer & Datastrukturer i Java

Strängar. TDDD64 Programmering i Python Föreläsning 4. Peter Dalenius Institutionen för datavetenskap

DAI2 (TIDAL) + I2 (TKIEK)

Tenta i Grundläggande programmering DD klockan

Tentamen Datastrukturer D DAT 035/INN960 (med mycket kortfattade lösningsförslag)

Introduktion till programmering SMD180. Föreläsning 7: Strängar

Introduktion till programmering SMD180. Föreläsning 4: Villkor och rekursion

Lösningsförslag till tentamen Datastrukturer, DAT037,

729G04 Programmering och diskret matematik

TDP002 - Imperativ programmering

EnKlass. Instans 3 av EnKlass. Instans 2 av EnKlass

TDDC74 Lab 02 Listor, sammansatta strukturer

Dataabstraktion. TDDD73 Funktionell och impterativ programmering i Python Föreläsning 12. Peter Dalenius Institutionen för datavetenskap

Tentamen , Introduktion till Java, dtaa98, dtea53

Mer grafik. Jan Erik Moström

Programmering grundkurs

729G04 Programmering och diskret matematik. Python 3: Loopar

Introduktion till Datalogi DD1339. Föreläsning 3 29 sept 2014

Tentamen i Algoritmer & Datastrukturer i Java

BINÄRA TRÄD. (X = pekarvärdet NULL): struct int_bt_node *pivot, *ny; X X X 12 X X 12 X X -3 X X

Övning 4. Hashning, sortering, prioritetskö, bästaförstsökning. Hitta på en perfekt hashfunktion för atomer. Hur stor blir hashtabellen?

Selektion och iteration

Transkript:

Per Sedholm DD1320 (tilda13) 2013-09-18 Övning 3 Problemträd, breddenförst, djupetförst, hashning Person (selektorer, kodformatering) Skriv ett program som läser personers namn och födelsedag från fil. Vi väljer att göra en klass för att representera personer. Huvudprogrammet kan då göra f = open("ovn3-e-01a.txt", "r") lst = [] for line in f: (date, name) = line.strip().split(none, 1) lst.append(person(name, date)) f.close() for p in lst: print(p) ## assume that Person has a str method Vilka metoder behöver klassen ha? De självklara är Speciella metoder init (konstruktor), str (sträng-representation) mfl. Notera skillnaden mellan str str ger en läsbar sträng-version av denna Person. Anropas av str(). repr repr ger en entydig sträng-representation av denna Person. Anropas av repr(); str(lista) kommer att anropa repr för varje element. Selektorer för att plocka ut egenskaper för Person:en Annat? metoder som har bieffekter, ex. skriver ut (ej returnerar) en sträng. class Person(object): """A record for a person""" def init (self, name, bday): """Represent a person with the given name and birthday""" self. name = name self. bday = bday def name(self): """Return this person s name""" return self. name def bday(self): """Return this person s birthday""" return self. bday def str (self): """Return a string version of this Person""" return "<" + self.name() + " (" + self.bday() + ")>" def showname(self): """Print this person s name""" print(self.name()) 1

Lägg märke till att Klassen har en kommentar Varje metod (inklusive init-metoden) har en kommentar Dessa är inte kod-kommentarer. Privata attribut (och metoder) börjar med. Funktionskommentarer skrivs (helst) med docstring-konventioner, så att man kan auto-generera dokumentation. Kodkommentarer är till för den som läser koden, se exempel i slutversionen nedan. Indata; resultat: 8/1 Graham Chapman <Graham Chapman (8/1)> 29/3 Eric Idle <Eric Idle (29/3)> 11/22 Terry Gilliam <Terry Gilliam (11/22)> 1/2 Terry Jones <Terry Jones (1/2)> 27/10 John Cleese <John Cleese (27/10)> 5/5 Michael Palin <Michael Palin (5/5)> Men nu blev det fel. Terry Gilliam (som är amerikan) skriver ju MM/DD, medan de övriga (britter) skriver DD/MM. Det är nog bättre att byta format i filen men ger det fortfarande samma utskrifter? (Gilliam undantaget)? Ja, vi skrev ju selektorer! Byt till 1941-01-08 Graham Chapman 1943-03-29 Eric Idle 1940-11-22 Terry Gilliam 1942-02-01 Terry Jones 1939-10-27 John Cleese 1943-05-05 Michael Palin def bday(self): """Return this person s birthday""" (y, m, d) = self. bday.split("-") m = m.lstrip("0") d = d.lstrip("0") return d + "/" + m Metoden (selektorn) uppfyller samma yttre gränssnitt, så huvudprogrammet kan använda exakt samma kod, och få samma resultat. Det finns dock ett par saker man kan vilja ändra. Best practice är att skriva Efternamn, Förnamn eftersom det är lättare att plocka isär. Har man flera olika fält vill man oftast ha annat än mellanslag för att skilja dem t.ex. : (kolon). 1941-01-08:Chapman, Graham Arthur 1943-03-29:Idle, Eric 1940-11-22:Gilliam, Terence Vance "Terry" 1942-02-01:Jones, Terence Graham Parry "Terry" 1939-10-27:Cleese, John Marwood 1943-05-05:Palin, Michael Edward Det gör att huvudprogrammet måste använda (date, name) = line.strip().split(":") Vi kan sedan split:a namn-delen för att hitta för- resp. efternamn, och även plocka fram tilltalsnamnet. 2

Ska man hålla på och räkna med datum så vill man använda färdiga bibliotek, som inte bara tar hänsyn till skottår på rätt sätt, eller alla bysantinska regler för tidszoner, utan även till egenheter som: Följs 2:a sept 1752 av 3:e sept, eller 14:e sept? (Storbrittannien bytte från juliansk till gregoriansk kalender) Vad hände 30:e feb 1712? (Sverige bytte fram och tillbaka mellan juliansk och gregoriansk kalender. Det blev mycket krångligt.... ) Vi använder därför date.datetime. from datetime import date class Person(object): """A record for a person""" def init (self, name, bday): """Represent a person with the given name and birthday""" (last, first) = name.split(", ") if " in first: called = first[first.find( " )+1:first.rfind( " )] elif " " in first: ## This is not often correct, but works here called = first[0:first.find(" ")] else: called = first self. first = first self. last = last self. name = called + " " + last (y, m, d) = bday.split("-") self. bday = date(int(y), int(m), int(d)) def name(self): """Return this person s name""" return self. name def bday(self): """Return this person s birthday""" return self. bday.strftime("%d/%m") def this_years_birthday(self): """Return the weekday of this person s birthday in the current year""" today = date.today() bd = date(today.year, self. bday.month, self. bday.day) ## date.weekday() is a number, this gives the full name return bd.strftime("%a") def str (self): """Return a string version of this Person""" return "<" + self.name() + " (" + self.bday() + ")>" f = open("ovn3-e-01c.txt", "r") lst = [] for line in f: (d, n) = line.strip().split(":") lst.append(person(n, d)) f.close() #for p in lst: # print(p.name() + ":", p.this_years_birthday()) print("\n".join(map(str, lst))) print("\n".join(map(lambda p: p.name() + ": " + p.this_years_birthday(), lst))) 3

4. Taltävling Under sommaren har det gått en tävling i radio där det gäller att så snabbt som möjligt hitta ett tal som uppfyller två villkor. Första villkoret, som gäller hela tävlingen, är att siffrorna i talet måste vara strikt stigande (23578 är OK men inte 235578 eller 23587). Andra villkoret är nytt för varje dag och kan t ex vara att talet ska vara ett primtal, jämnt delbart med 599 eller en tvåpotens. Beskriv utförligt en breddenförst- eller djupetförstsökning (effektivare metod ger fler poäng) som hittar det minsta talet som uppfyller villkoren. Vilka klasser och metoder behövs? Antag att vi endast har fyrsiffriga tal. Hur söker man igenom dem? 1. Utgå från startläge, elementet e 2. Skapa barn-element, e 1, e 2, e 3,..., men filtrera bort dum-barn. 3. Lägg varje barn i en kö (BFS) eller stack (DFS). 4. Plocka nästa element ifrån kön/stacken, återgå till (1). Djupetförst söker igenom alla tal som börjar med 1. Med godtyckligt många siffror i talen blir det ganska många... För att lösa uppgiften vill man varje gång man går från noden n till dess barn filtrera bort dåliga barn de som inte uppfyller villkoren. Att se siffror som strängar är oeffektivt (måste konvertera för att se ifall de är delbara etc), men annars är det svårt att veta att siffrorna är strikt stigande. 4

Breddenförst, djupetförst Påverkar bredden- eller djupetförst vilken ordning man får ut elementen? Ja! Se på trädet nedan: M 1 M 1 A 2 E 3 I 4 A 2 E 7 I 8 N 5 W 6 L 7 X 8 N 3 W 6 L 9 X 12 E 9 Y 10 D 11 K 12 E 4 Y 5 D 10 K 11 Wordlist = [ "MA", "ME", "MI", "MAN", "MAW", "MIL", "MIX", "MANE", "MANY", "MILD", "MILK" ] Alphabet = "".join([chr(c) for c in range(ord( A ), ord( Z ))]) def recursequeue(word, s): for c in Alphabet: child = word + c if child in Wordlist: s.put(child) print("queue (breadth-first)") s = Queue() s.put("m") while not s.isempty(): e = s.get() print(e, end= ) recursequeue(e, s) print(".") # Queue (breadth-first) # M MA ME MI MAN MAW MIL MIX MANE MANY MILD MILK. def recursestack(word, s): for c in Alphabet[::-1]: child = word + c if child in Wordlist: s.push(child) print("stack (depth-first)") s = Stack() s.push("m") while not s.isempty(): e = s.pop() print(e, end= ) recursestack(e, s) print(".") # Stack (depth-first) # M MA MAN MANE MANY MAW ME MI MIL MILD MILK MIX. 5

1. Strykord Ordet orkan är ett strykord eftersom man kan stryka sista bokstaven om och om igen och bara få riktiga ord. orkan orka ork or o Uppgiften är att finna det längsta strykordet i svenska språket. Ordlistan finns på fil. Rita problemträdet och jämför olika tänkbara algoritmer. Börja med tomt ord, skapa sedan barn genom att lägga på en bokstav och kolla ifall det ordet finns. Vi vill ha uttömmande sökning, så breddenförst är inte nödvändigt. Vi använder därför en rekursiv djupetförst-sökning. Orden läggs i en dict kan använda binärträd eller något smartare som sparar minne. I Ubuntus svenska ordlista är enda enbokstavs-orden i, å och ö ; enligt SAOL är varje bokstav ett ord. Vi kommer dock att hitta: i id il in is ida ila idag idar isa ilar... idars isad isade isades där det längsta ordet kommer att ändras som: i -> id -> ida -> idag == idar -> idars == idens == idets == ilars == ilats == isade -> isades... 6

class Swedish(object): words = "/usr/share/dict/swedish" def init (self): self. swe = {} words = open(swedish. words, mode= r, encoding= iso-8859-1 ) for w in words: wu = w.strip().lower() self. swe[wu] = True words.close() def exists(self, w): return w in self. swe longest = swedish = Swedish() # Note: we convert all known words to lower-case alphabet = "".join([chr(c) for c in range(ord( a ), ord( z ))]) + "åäö" def find_removable(word): """Recursive depth-first search""" global longest if len(word) > len(longest): longest = word for c in alphabet: if swedish.exists(word + c): find_removable(word + c) find_removable("") print("longest removable word:", longest) # Longest removable word: åtalades Fotnot: Detta program kommer inte att gå från armé armen, eftersom det inte ser é och e som samma bokstav. (Vi bygger aldrig på é, è, ë, ê,....) Egentligen skulle vi vilja ta hänsyn till bokstäver med diakritiska tecken som trema (umlaut), tilde, etc. Men i Unicode så kan bokstaven Å representeras som: U+00C5 (Latin capital letter A with ring above) U+0041 U+030A (Latin capital letter A, Combining ring above) som dessutom ser ut precis som U+212B (Angstrom sign) så en lösning skulle behöva kunna hantera alla fall. används t.ex. i Mac OS X:s filnamn Finns metoder för detta, modulen unicodedata innehåller funktioner för att normalisera genom canonical decomposition och canonical composition. 7

2. Sjuor till hundra Det gäller att skriva talet 100 med enbart sjuor och dom fyra räknesätten, till exempel så här: 7 +7 /7 *7 *7 =98 Det var ett gott försök som inte nådde ända fram. För att man ska få använda / måste divisionen gå jämnt ut. Rita problemträdet och diskutera bästa algoritm för att avgöra OM problemet är lösbart. Om man dessutom vill veta hur lösningen ser ut krävs en mer komplicerad datastruktur. Beskriv den och skissa ett program. Vi vill hitta kortaste sättet att komma fram till hundra. Som gjort för breddenförst, där man använder en kö med heltal för att stoppa i alla tal man får från n (division omm. n 0 (mod 7)): n n + 7 n 7 n 7 n/7 (n + 7) + 7 (n + 7) 7 q = Queue() N = 7 def makesons(num): global N if num == 100: print("target reached") return False q.put(num + N) q.put(num - N) q.put(num * N) # NB: 0*7 == 0... if num % 7 == 0: q.put(int(num / N)) return True m = True q.put(0) while not q.isempty() and m: e = q.get() m = makesons(e) Notera dock att vi kommer att testa samma tal många ggr: 0 {7, 7, 0, 0} 7 {14, 0, 49, 1} 7 {0, 14, 49,...} Vi kommer även att ha med många mycket stora/små tal: $ python ovn3-02.py > ovn3-02.out $ wc -l ovn3-02.out 5188 $ uniq ovn3-02.out wc -l 4869 ## 319 duplicates $ sort -nu ovn3-02.out -117649, -33614, -19208,..., 0..24, 27, 28,..., 33614, 36015, 50421, 117649 8

För att få ut kedjan måste varje nod minnas sin far, dvs varifrån den kommer. Det lättaste är att returnera den noden istf. False från makesons (istf. True returnerar man None), men det går även att använda ett Exception. class Node(object): def init (self, num = 0, father = None, op =? ): self.num = num self.father = father self.op = op q = Queue() N = 7 def makesons(father): global N if father.num == 100: print("target reached") raise StopIteration(father) q.put(node(father.num + N, father, + )) q.put(node(father.num - N, father, - )) q.put(node(father.num * N, father, * )) # NB: 0*7 == 0... if father.num % 7 == 0: q.put(node(father.num / N, father, / )) def writechain(p): if p!= None: writechain(p.father) print(p.op, N, ->, p.num) try: q.put(node()) while not q.isempty(): e = q.get() #print(e) makesons(e) except StopIteration as si: print("«breaking iterations»") writechain(si.args[0]) #? 7 -> 0 # + 7 -> 7 # + 7 -> 14 # * 7 -> 98 # * 7 -> 686 # + 7 -> 693 # + 7 -> 700 # / 7 -> 100 9