Träd, traversering, insättning, borttagning

2013-02-07
TDDC30
Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 8
Jonas Lindgren, Institutionen för Datavetenskap, LiU
På denna föreläsning:
•
Träd
•
Traversering
•
Insättning, borttagning
•
Representation som länkad nod, array
1
Scenario
• Harry har fått i uppdrag att bringa ordning
och reda till ett företags chefstruktur med ett
nytt program
• Harry börjar med att skriva in alla anställda i
en enkellänkad lista, men det blir snabbt krångligt
• En ny datastruktur behövs!
2
1
2013-02-07
Scenario
• Resultatet:
VD Adam Adamsson
Utvecklingschef Bertil
Bengtsson
Säljchef Caesar
Cesarini
Ekonomichef David
Didriksson
Hackaren Harry
3
Träd
Definition:
• Ett träd är en riktad acyklisk graf
• Består av noder & bågar
• Finns enn väg till varje nod
Vanliga användningsområden:
• Representering av hierarki i:
• Företag
• Släktträd
• Filsystem(mappar/filer)
• Spara data för snabb sökning
4
2
2013-02-07
Träd(2)
Definition:
• Förälder: en nod vid en båges källa
• Syskon: noder med samma förälder
• Rot: en nod utan förälder
• Löv: en nod utan barn
• Gren/delträd: samling noder
med gemensam anfader
Rot
Förälder
Barn
Syskon
Gren
Löv
5
• Träd defineras rekursivt: Ett delträd är också ett träd, som kan
innehålla fler delträd, eller bara en nod (d.v.s. ett löv)
Träd(3)
Nodinformation:
• Grad: Antal barn noden har
• Djup: Avstånd från roten
• Höjd: Avstånd till lövet längst bort
Djup
0
• Trädets höjd = Rotens höjd
1
2
3
• Träd med noder av grad ≤ 2 : Binärt träd
Grad: 2
Djup: 1
Höjd:2
6
3
2013-02-07
ADT Träd
element()
Returnerar datat i rotnoden (för delträdet)
parent()
Returnerar föräldranoden (implementeras inte alltid)
children()
Returnerar en kollektion(t.ex. en lista) med nodens barn
isInternal()
Testar om noden är en inre nod d.v.s. om den har barn
isExternal(),
isLeaf()
Testar om noden är en yttre nod d.v.s. om den är ett löv
isRoot()
Returnerar sant om noden ej har någon förälder
isEmpty()
Testar om (del)trädet har några noder överhuvudtaget
Binära träd
left()
Returnerar det vänstra barnet
right()
Returnerar det högra barnet
hasLeft()
Testar om noden har ett vänsterbarn
hasRight()
Testar om noden har ett högerbarn
7
Traversering
• Traversering: ett systematiskt sätt att ”besöka”
alla noder i ett träd
• En träd-iterator implementerar någon form av
traverserings-algoritm
• Djupet-först
• Bredden-först
8
4
2013-02-07
Preordertraversering
Algoritm:
1. Besök mig
2. Besök vänstra delträdet
3. Besök högra delträdet
= Delträd
9
Inorderdertraversering
Algoritm:
1. Besök vänstra delträdet
2. Besök mig
3. Besök högra delträdet
= Delträd
10
5
2013-02-07
Postordertraversering
Algoritm:
1. Besök vänstra delträdet
2. Besök högra delträdet
3. Besök mig
= Delträd
11
Levelordertraversering
Algoritm:
1. Besök mig
2. Besök de till höger som har samma djup
3. Besök de som har djup + 1
Djup
0
1
2
3
12
6
2013-02-07
Några fler termer
• Fullt binärt träd:
Samtliga noder har noll eller två barn
• Perfekt träd:
Ett fullt träd med alla löv på samma djup
• Fullständigt binärt träd:
Ett perfekt träd med skillnaden att den får
sakna några av de högraste löven
13
Binärt sökträd
• En typ av binärt träd
• En struktur för snabb sökning
För varje nod gäller följande:
• Alla element till vänster
är mindre än nodens värde
• Alla element till höger
är större än nodens
värde
-
+
+
-
-
14
Givet att trädet är väl balanserat (ej fallet ovan) blir söktiden O(log(n))
7
2013-02-07
Addering i binärt sökträd
För varje nod som besöks:
• Existerar ej noden: Rätt plats funnen
• Är värdet mindre än nodens, följ
den vänstra grenen
• Är värdet större än nodens,
följ den högra grenen
-
+
+
-
-
-
15
Borttagning i binärt sökträd
Steg 1, 2, 3:
Mål: ta bort värdet 3
Strategi:
1. Sök ut rätt nod på liknande
sätt som vid adderingen
2. Sök reda på en ersättare:
1.
2.
1
-
4
1
-
2
7
+
+
-
6
-
9
8
5
4
-
3
2
Om bara ett barn finns, välj det
Annars välj noden längst till
vänster i det högra delträdet. Steg 4:
3. Koppla loss ersättaren,
ersätt den med dess högra
delträd om ett sådant finns
4. Sätt in ersättaren på dess
nya plats
-
3
-
-
+
6
7
+
8
9
16
5
8
2013-02-07
Borttagning i Binärt träd(2)
Det färdiga trädet efter borttagningen
-
-
-
2
1
4
-
7
+
+
6
9
8
5
17
Representation
• Träd brukar vanligtvis implementeras som länkade noder
Parent(optional)
data
left
right
18
9
2013-02-07
Representation(2)
Parent(optional)
data
left
right
• Då delträd också är träd lämpar sig strukturen
väl för rekursiva algoritmer
Exempel: preordertraversering
public void visitPreorder(TreeNode node){
node.visitMe();
visitPreorder(node.left());
visitPreorder(node.right());
}
Representation(3)
19
Parent(optional)
data
left
right
• Stackar och köer kan också användas för
traversering
Exempel: levelordertraversering
(börja med att lägga roten på en kö)
1. Hämta en nod från kön
2. Besök noden
3. Lägg vänster och höger barn i kön
4. Repetera så länge kön inte är tom
20
10
2013-02-07
Representation med fält
• Träd kan även implementeras med ett fält!
A
ADT
B
D
G
C
E
Representation
ABCDE F
G
H
F
H
Traverseringsregler för binärt träd:
Index för root
0
Index för vänster barn
2*i+1
Index för höger barn
2*i+2
Index för förälder
(i-1)/2 (avrunda nedåt)
21
Implementation som fält(2)
Egenskaper för fältrepresentation
• Slipper tre pekare per element
AB CD E F
G
H
• Mindre minne
• Traversera m.h.a. aritmetiska operationer (2*i + 1)
• Minne kan preallokeras (vanligtvis ett träddjup i taget)
• minnesutrymme som allokeras samtidigt tenderar att hamna
på samma plats i datorns minne S => Hög spatial lokalitet => snabbt
• Varje new är ett anrop till OS för att be om minne, tar tid
• Tenderar att bli svårare att implementera
• Ett dåligt balanserat träd ger ineffektivt minnesutnyttjande
22
11