Tilpro Övning 3 På programmet idag: Genomgång av Hemtalet samt rättning Begreppet Stabil sortering Hur man kodar olika sorteringsvilkor Inkapsling av data Länkade listor Användning av stackar och köer Översiktligt om prefix notation
Sätt att skriva ut binärträd Inorder...skriv vänsterträd, skriv noden, skriv högerträd. Preorder...skriv noden, skriv vänsterträd, skriv högerträd. Postorder...skriv vänsterträd, skriv högerträd, skriv noden. Om man vill spara ett träd och sedan återskapa det gäller det att hålla tungan rätt i mun. Beroende på om noderna som lagras läggs i en kö eller stack bör preorder eller postorder användas. Väljer man fel får man ett mycket anorlunda träd.
Att återskapa träd Preorder nedstoppat i en kö ger samma träd tillbaka. Postorder nedstoppat i en stack ger samma träd tillbaka. Inorder ger en lång tarm om man inte sätter in mitten rekursivt...eller så sätter man in dem i en slumpvis ordning så får man approximativt balanserat träd.
Stabila sorteringar Det finns en stor mängd algoritmer för sorteringar. En viktig sorts klassificering är om sorteringsalgoritmen är stabil. Detta innebär att ordningen mellan element med samma sorteringsvärde behålls vid sortering. Du kan då sortera först på namn och sedan datum och veta att namnordningen inom varje datum fortfarande är sorterad. Detta är ofta i praktiken mycket önskvärt. Pythons inbyggda sortering är i äldre versioner av python ostabil, nu för tiden är den stabil.
Exempel på algoritmer från föreläsningen Stabila: Instättningssortering Bubelsortering Räknesortering (Distrubution sort) Mergesort Ostabila: Urvalssortering Damerna först Quicksort
Hur kodar man olika sorteringsvilkor? #Listor har en inbygd metod som sorterar listan. Vi #kan tala om för sort hur den ska sortera. def mine_cmp(x,y): if x[1]<y[1]: return -1 elif x[1]==y[1]: return 0 else: return +1 a=[[ Adam,24 ],[ Klas, 19],[ Pa,27 ]] a.sort(mine_cmp)
Olika sätt att anropa saker? #Av historiska skäl finns det ofta flera sätt att # komma åt samma sak i python. a= Tilpro Övning a.strip() #går via variabeln för att hitta funktionen import string string.strip(a) #det behövs en parameter till metoden # för att den ska kunna veta vad den ska verka på from string import * strip(a) #har vi importerat på detta sätt blir det vi #importerat tillgängligt utan att vi säger var det # kommer ifrån. Kan bli mycket förvirrande...
Inkapsling av data Vi behöver ofta lagra data mellan funktionsanropen. Att göra saker till globalt går. I praktiken skapar vi dock oss ofta problem på detta sätt. Har datat blivit korrupt är det väldigt jobbigt att spåra upp vilken av metoderna som ändrar det som orsakar problemet. Det konkreta problemet är alltså att det blir svårt att designa programmet säkert och testa detta om många metoder manipulerar datat oberoende av varandra.
En given metod sköter inmatningen Om vi designar smart kan vi få till det så att en enda funktion sköter all tolkning av indata och lägger in det i datastrukturen. Blir det fel i alla fall så går det snabbt att kontrollera att alla anrop till funktionen som sköter tolkningen är korrekta. Verkar alla rätt så får vi detalj granska vad tolkningsmetoden gör. Om funktionen följer med själva datat (och kan nås med punkt i namnet ) så brukar man kalla det för en metod. Skillnaden mellan funktioner och metoder är helt hypotetisk. I praktiken gör de samma sak.
Objektorientering Tekniker från så kallad objektorientering programmering låter oss lösa problemet. Allmänt är objektorientering ett väldigt hypat ord. Det är bra idéer som ligger bakom, men folk tenderar att tro att objektorientering löser allt. Något som definitivt inte är sant. I denna kurs kommer vi bara lära ut grunderna i objektorientering, det som behövs för labbarna. Vill man veta mer ska man läsa fortsättningskursen Program Utvecklings Teknik (Prutt)
Objekt orientering == allt är klasser Vill vi skapa en egen datatyp skriver vi en så kallad klass. Klasser är som vanliga program...fast de går att använda som datatyper när vi importerat dem. Speciellt för klasser är att alla metoderna har en extra inparameter som heter self. Denna används för att få tag i klassens egna data. Det behövs även en speciell metod som heter init () Denna anropar vi när vi vill skapa ett exemplar av klassen i minnet. Normalt skickar man med data in som parameter så att man kan tilldela dem till variablerna (vilka kallas attribut för att förvirra icke insatta).
En klass som lagrar bråktal #coding: iso-8859-1 class Fraction: numerator=none denominator=none #Metod som skapar exemplar av klassen def init (self, numerator, denominator=1): #anger man ingen andra parameter sätter python den till 1 self.numerator = int(numerator) self.denominator = int(denominator) #Metod för att kunna skriva ut Fraction med print def str (self): return str(self.numerator) + / + str(self.denominator)
Fraction (forts) #multiplicera två bråktal och returnera resultatet def multi(self, other): return Fraction(self.numerator*other.numerator, self.denominator*other.denominator) #addera två bråktal och returnera resultatet def add(self,other): return Fraction(self.numerator * other.denominator + self.denominator * other.numerator, self.denominator * other.denominator)
Fraction (forts2) def compare_fractions(self, other): #a/b > c/d => ad > bc #Har ingen aning varför intarna behöver göras om till int #upptäckte att sort tolkade dem som sekveser utan det diff = int(self.numerator) * int(other.denominator) - int(other.numerator) * int(self.denominator) return diff def main(): #Testa att det verkar fungera test=fraction(1,2) test2=fraction(1,3) print test.multi(test2) print test.add(test2) print test2.compare_fractions(test) if name == main : main()
Använda Fractions i annat program #coding: iso-8859-1 from Fraction import Fraction def main(): lista=[] for iter in range(3): text=raw_input( Skriv ett bråktal: ) temp=text.split( / ) lista.append(fraction(temp[0],temp[1])) print Sorterar bråktalen lista.sort(fraction.compare_fractions) for i in lista: print i if name == main : main()
Länkade listor Länkade listor låter oss med minimalt jobb lätt lägga till saker inne i listan förutsatt att vi hittat vilken plats vi ska lägga in på eftersom vi bara flyttar en referens. Vill man hitta 4:de posten måste man följa massor av next pekare innan man är framme. Har vi pekare till det första objektet vid namn pek kan vi hitta det andra genom skriva pek.next Vill vi ytterligare ett steg skriver vi pek.next.next Normalt gör man pekar jonglerandet inne i en klass metod. Data Data Data Data None next next next next
Vad är länkade listor, köer och stackar bra till? Poängen med dessa är att väldigt många datoralgoritmer går att skriva på ett förenklat vis om vi använder oss av abstrakta köer och abstrakta stackar. Ett ypperligt exempel på detta är lab 5 i kursen som heter Salighet. Det kommer också sannolikt dyka upp på tentan. Länkade listor i sin tur är inte så abstrakta...men de låter oss på ett enkelt vis skriva köer och stackar oberoende vilket programmeringsspråk vi använder. Koden blir alltså väldigt lika oavsett vilket språk man använder. Det kan dock ofta gå att skriva snabbare variant om man gör på annat vis.
Vad är egentligen skillnaden mellan köer och stackar? Både en kö och stack hämtar från samma ände av den länkade listan. Skillnaden ligger i att stacken lägger till poster på samma ställe som den tar ut medan kön lägger till dem i andra änden. Stackar har indirekt effekten att det som läggs i dem returneras i omvänd ordning.
Minnesbild för den rekursiva datastrukturen Stack Top Stack ListNode data next Fraction Fraction ListNode data next ListNode data next Fraction None
Minnesbild för den rekursiva datastrukturen Kö First Last Kö ListNode data next Fraction Fraction ListNode data next ListNode data next Fraction None
Minnesbild för den rekursiva datatstruktruren binärträd root data BinNode Fraction data BinNode Left Right data BinNode Fraction Left Fraction Right Left Right data BinNode Fraction Left Right None
Syntax för beräkningar av tal expression ::= factor factor '+' factor factor '-' factor factor ::= term term '*' term term '/' term term ::= NUMBER '(' expression ')'
Syntaxträd för 5 * 6 + 7 expression factor + factor term * term term 5 6 7 Överfört till prefix notation är detta: +7*5 6 (ganska klurigt att koda en infix till prefix översättare)
Prefix notation: +7*5 6 Tryck in elementen i en stack för att utföra beräkningen Stack top 6 5 * 7 + Hämtar två tal från stacken, dvs 5 och 6 och operatorn som är * och utför operationen. Får resultatet 30 som trycks tillbaka på stacken Stack top 7 + top Stack 30 Hämtar två tal från stacken dvs 30 och 7 och operatorn som är + och utför operationen. Får resultatet 37. Eftersom stacken är tom är vi färdiga. 7 +