Med två referenser i varje objekt kan man bygga träd, till exempel
ett som beskriver en symfoniorkesters
sammansättning.
class Node:
def __init__(self, value):
self.value = value
self.down = None
self.right = None
All systematisk uppdelning kan beskrivas med liknande träd,
till exempel ett bokverks uppdelning i delar, kapitel,
sektioner osv. Man kan också tänka sej det som ett
släktträd och då kallas ofta down-referensen för
firstChild och rightreferensen för nextSibling.
Det räcker med två referenser i varje nod, oavsett hur stora barnaskarorna är.
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
Man når trädet genom variabeln root som pekar på
den översta noden (datalogiska träd har roten uppåt). Rotnodens
vänsterpekare pekar på ett mindre binärträd och högerpekaren på
ett annat mindre binärträd.
Antalet nivåer i trädet avgör hur många noder det kan innehålla. Ett fullt träd med k nivåer innehåller 2k - 1 noder. Exempel: k=3 i vår bild ger högst 7 noder (det finns plats för två till under 9999). Man kan också säga att ett balanserat träd med n noder har cirka log n nivåer.
def finns(p,value):
while True:
if p == None:
return False
if value == p.value:
return True
if value<p.value:
p = p.left
if value>p.value:
p = p.right
top pekar på den
översta noden.
def antal(p):
if p == None:
return 0
else:
return 1 + antal(p.next)
Anropet antal(top) ger nu rätt svar!
def antal(p):
if p == None:
return 0
else:
return 1 + antal(p.left) + antal(p.right)
Anropet antal(root) ger nu rätt svar!
finns(p,value) returnera True ifall ordet
finns i det delträd där p är rot.
def finns(p,value):
if p == None:
return False
if value == p.value:
return True
if value<p.value:
return finns(p.left,value)
if value>p.value:
return finns(p.right,value)
Den här funktionen kan du använda i labb 3!
Om man ska skriva ut alla talen i trädet vill man oftast göra det i
så kallad inordning (eng. inorder), dvs från vänster
till höger.
Fråga: Hur skriver man ut trädet i inordning?
Rekursivt svar: Först skriver man ut vänsterträdet,
sedan rottalet, sist högerträdet.
...men ett tomt träd skriver man inte alls.
Följande funktion gör att write(root) skriver ut
1 17 666 4711 9999 för vårt träd.
#Inordning
def inorder(p):
if p != None:
inorder(p.left)
print(p.value)
inorder(p.right)
Om man kastar om dom tre sista satserna får man ändå ut alla talen
på skärmen men i andra ordningar. Preordning (eng.
preorder) innebär att rottalet skrivs först, sedan vänsterträdet
och sist högerträdet.
I vårt exempel blir ordningen
4711 17 1 666 9999.
Om vi återgår till orkesterträdet kan vi se att preordning faktiskt ger vettigare utskrift. Så här blir koden i det fallet.
#Preordning
def preorder(p):
if p != None:
print(p.value)
preorder(p.down)
preorder(p.right)
Utskriften blir då den naturliga. Om vi för tydlighets skull
använder indragning av orden på lägre nivå blir utskriften
Orkester
Blås
Trä
Bleck
Stråk
Vi
Va
Vc
Kb
Slag
(Hur gör man för att få dessa indragningar?)
Slutligen kan man skriva ut i postordning (eng. postorder) och det innebär att vänsterträdet skrivs först, sedan högerträdet och sist roten. Det ger 1 666 17 9999 4711 i vårt exempel.