Bäume

Werbung
Bäume
Prof. Dr. Christian Böhm
in Zusammenarbeit mit
Gefei Zhang
http://www.dbs.ifi.lmu.de/Lehre/NFInfoSW
WS 07/08
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Ziele
ƒ Standardimplementierungen für Bäume kennen lernen
C. Böhm: Bäume
2
3
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Bäume (abstrakt)
ƒ
Bäume sind hierarchische
Strukturen.
ƒ
Bäume bestehen aus
ƒ
Knoten und
ƒ
Teilbäumen.
Der oberste Knoten heißt
Wurzel.
ƒ
ƒ
ƒ
WurzelKnoten
Knoten
Bei Binärbäumen hat jeder
Knoten zwei Unterbäume:
ƒ
den linken Unterbaum,
ƒ
den rechten Unterbaum.
In den Knoten kann
Information gespeichert
werden.
C. Böhm: Bäume
Rechter Teilbaum
Linker Teilbaum
4
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Implementierung von Knoten
class Node
{ Node left;
int key; Object value
Node right; …
}
ƒ
Ein Knoten wird implementiert als
Objekt mit zwei Zeigern.
ƒ
Außerdem wird in jedem Knoten
ein Schlüssel und ein Wert
gespeichert.
: Node
7
left
o
key value
right
: Node
3
left
o1
key value
C. Böhm: Bäume
: Node
9
right
left
o2
key value
right
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
5
Implementierung von Bäumen
ƒ
public class BinTree
{
Node anchor; . . .
}
class Node
{
Node left;
int key; Object value;
Node right;
Ein Baum wird implementiert durch einen
Zeiger auf ein Geflecht von Knoten:
ƒ
Die Klasse BinTree hat wie List
einen Anker, der auf Node zeigt.
ƒ
Die Klasse Node ist eine Hilfsklasse
für die Klasse BinTree.
// Konstruktor
Node(Node b1, int k, Object o, Node b2)
{ left = b1; key = k; value = o; right = b2;
}
. . .
}
C. Böhm: Bäume
class BinTree 6
{ Node anchor;…
}
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Ein Beispiel für eine Instanz von BinTree
ƒ
: BinTree
Eine Bauminstanz zeigt auf eine Nodeinstanz
anchor
: Node
7
left
o
key value
right
: Node
3
left
o1
key value
C. Böhm: Bäume
: Node
9
right
left
o2
key value
right
7
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Operationen auf BinTree
ƒ
Konstruktoren
ƒ
BinTree()
ƒ
ƒ
BinTree(B1, k, o, B2)
neuer BinTree mit
ƒ
ƒ
ƒ
ƒ
linkem Teilbaum B1
rechtem Teilbaum B2
Inhalt der Wurzel: k,o
B2
Prädikat isEmpty
ƒ
ƒ
der leere Baum
Testen, ob ein BinTree leer ist
Selektoren
ƒ
Falls der BinTree nicht leer ist, liefert
ƒ
getLeft() den linken Teilbaum
ƒ
getRight() den rechten Teilbaum
ƒ
getKey() den Schlüssel der Wurzel
ƒ
getValue()den Inhalt der Wurzel
C. Böhm: Bäume
B1
8
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
BinTree in UML
boolean
BinTree
int
Object
BinTree
+ BinTree
anchor
isEmpty()
getLeft()
getKey()
getValue()
getRight()
0..1
C. Böhm: Bäume
Node
left
int key
Object value
int getKey()
Object getValue()
Node getLeft()
Node getRight()
void setKey(int k)
void setValue(Object o)
void setLeft(Node l)
void setRight(Node l)
0..1
right
0..1
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
9
Implementierung in Java
Die Implementierung von BinTree verläuft analog zu Listen:
ƒ BinTree repräsentiert Binärbäume über einem Integer-Schlüssel und Werten vom
Typ Object.
ƒ
BinTree selbst speichert nur einen Verweis auf die Wurzel des Baumes.
ƒ
Die eigentliche Funktionalität wird von der Klasse Node realisiert;
ƒ Um Funktionen auf BinTree zu definieren, verwenden wir folgende
Fallunterscheidung:
ƒ leerer Baum:
Berechnung des Resultats direkt in BinTree
ƒ nicht-leerer Baum: Weitergeben (“delegieren”) der Funktion an Node
C. Böhm: Bäume
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
10
Implementierung BinTree: isEmpty & Zugriff auf linken Teilbaum
public class BinTree
{
private Node anchor;
ƒ
Implementierung verläuft analog zu
Listen
BinTree(){};
// der leere Baum
BinTree(BinTree b1, int k, Object o, BinTree b2)
{
anchor = new Node(b1.anchor, k, o, b2.anchor);
}
boolean isEmpty(){return anchor==null;}
BinTree getLeft() throws NoSuchElementException
{
if (anchor == null) throw new NoSuchElementException();
else
{
BinTree l = new BinTree();
l.anchor = anchor.getLeft();
return l;
}
}
. . .
C. Böhm: Bäume
11
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Anzahl der Knoten
Prinzipieller Ablauf der (rekursiven) Berechnung von t.sumNodes():
1.
Berechne die Anzahl der Knoten suml
7
des linken Teilbaums;
2.
Berechne die Anzahl der Knoten sumr
des rechten Teilbaums;
3.
10
5
Gesamtanzahl der Knoten:
1 + suml + sumr .
12
6
3
suml = 3
sumr = 2
Ergebnis = 1 + suml +sumr = 6
C. Böhm: Bäume
12
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Anzahl der Knoten (Implementierung)
t:
Keller
...
z
...
:BinTree
t.anchor
:Node
key=7
Halde
C. Böhm: Bäume
:Node
:Node
key=5
key=10
:Node
:Node
:Node
key=3
key=6
key=12
13
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Anzahl der Knoten (Implementierung)
t:
t.sumNodes():
1.
2.
3.
4.
Wenn t nicht leer, delegiere die
Aufgabe an Node durch
Aufruf von anchor.sumNodes();
Sei suml = Anzahl Knoten
des linken Kindknotens;
Sei sumr = Anzahl Knoten
des rechten Kindknotens;
Ergebnis: 1 + suml +sumr
...
z
...
:BinTree
t.anchor
:Node
key=7
:Node
:Node
key=5
key=10
:Node
:Node
:Node
key=3
key=6
key=12
suml = 3
C. Böhm: Bäume
Ergebnis = 1 + suml +sumr = 6
sumr = 2
14
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Implementierung BinTree: Anzahl der Knoten
public class BinTree
{ . . .
int sumNodes()
{
if (anchor == null) return 0;
else return anchor.sumNodes();
}
. . .
}
Wenn der Baum leer ist,
gibt es keinen Knoten; d.h.
Anzahl = 0
Delegieren der Aufgabe an
sumNodes() (aus der
Klasse Node)
class Node
{ . . .
int sumNodes()
{
int suml = 0, sumr = 0;
if (left != null) suml = left.sumNodes();
if (right != null) sumr = right.sumNodes();
return 1 + suml + sumr;
}
. . .
}
C. Böhm: Bäume
15
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Geordnete Binärbäume
ƒ Ein Binärbaum b heißt geordnet, wenn folgendes für alle nichtleeren Teilbäume t von
b gilt:
Der Schlüssel von t ist
ƒ größer (oder gleich) als alle Schlüssel des linken Teilbaums von t und
ƒ kleiner (oder gleich) als alle Schlüssel des rechten Teilbaums von t
7
>
<
10
5
>
>
3
C. Böhm: Bäume
9
<
12
16
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Geordnete Binärbäume
ƒ Beispiel: Geordnet sind:
7
(abstrakte Darstellung)
Der leere Baum und
der Baum t:
t =
8
5
12
6
3
ƒ Nicht geordnet ist
7
der Baum t1:
t1 =
3
C. Böhm: Bäume
8
5
9
12
17
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Suche im geordneten Binärbaum
Prinzipieller Ablauf der Berechnung von t.find(6):
1.
2.
Vergleiche 6 mit dem Wert der Wurzel;
7
Da 6<7, gehe zum linken Kindknoten;
6<7
8
5
3
C. Böhm: Bäume
6
12
18
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Suche im geordneten Binärbaum
Prinzipieller Ablauf der Berechnung von t.find(6):
1.
Vergleiche 6 mit dem Wert der Wurzel;
2.
Da 6<7, gehe zum linken Kindknoten;
3.
Vergleiche 6 mit dem Wert dieses Knotens;
4.
Da 6>5, gehe zum rechten Kindknoten
7
6<7
5
8
6>5
dieses Knotens;
3
C. Böhm: Bäume
6
12
19
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Suche im geordneten Binärbaum
Prinzipieller Ablauf der Berechnung von t.find(6):
1.
Vergleiche 6 mit dem Wert der Wurzel;
2.
Da 6<7, gehe zum linken Kindknoten;
3.
Vergleiche 6 mit dem Wert dieses Knotens;
4.
Da 6>5, gehe zum rechten Kindknoten
7
6<7
5
8
6>5
dieses Knotens;
5.
Vergleiche 6 mit dem Wert
dieses Knotens;
6.
Da 6==6, gebe Ergebnis true zurück.
C. Böhm: Bäume
3
6
12
6==6
return true;
20
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Suche im geordneten Binärbaum (Implementierung)
z
t
t.find(6):
1.
2.
3.
Suche zunächst in BinTree.
Wenn t nicht leer, delegiere die
Aufgabe an Node durch
Aufruf von anchor.find(6);
Verfahre wie auf den vorgehenden Folien.
:BinTree
t.anchor
:Node
6<7
key=7
:Node
:Node
key=5
key=10
6>5
:Node
:Node
key=3
key=6
:Node
6==6
return true
C. Böhm: Bäume
key=12
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
21
Suche im geordneten Binärbaum
public class BinTree
Gibt true zurück, wenn key im
{. . .
Baum; sonst wird false
public boolean find(int key)
zurückgegeben
{ if (anchor == null) return false;
else return anchor.find(key);
}
. . .
}
class Node
{ . . .
boolean find (int key)
{ Node current = this;
while(current.key != key)
// solange nicht gefunden,
{ if (key < current.key)
// gehe nach links?
current = current.left;
else
// sonst gehe nach rechts
current = current.right;
if(current == null) return false; //nicht gefunden!
}
return true;
//gefunden; gib true zurück
}
C. Böhm: Bäume
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
22
Suche im geordneten Binärbaum
public class BinTree
Gibt value zurück, wenn key
{. . .
im Baum; sonst wird null
public Object findValue(int key)
zurückgegeben
{ if (anchor == null) return null;
else return anchor.findValue(key);
}
}
class Node
{ . . .
Object findValue(int key)
{ Node current = this;
while(current.key != key)
// solange nicht gefunden,
{ if(key < current.key)
// gehe nach links?
current = current.left;
else
// sonst gehe nach rechts
current = current.right;
if(current == null) return null; //nicht gefunden!
}
return current.value;
//gefunden; gib value zurück
}
C. Böhm: Bäume
23
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum
ƒ Beim Einfügen in einen geordneten Binärbaum wird rekursiv die “richtige” Stelle
gesucht, so dass wieder eine geordneter Binärbaum entsteht.
ƒ Beispiel: t.insert(8) ergibt:
(Zur Vereinfachung der Darstellung wird hier nur ein Schlüssel und kein Wert eingefügt.)
7
7
t=
t=
t.insert(8)
10
5
3
C. Böhm: Bäume
6
10
5
12
3
6
8
12
24
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
t.insert(8)
:BinTree
t
z
. . .
:Node
key=7
this
z
id
8
:Node
:Node
key=5
key=10
:Node
:Node
:Node
key=3
key=6
key=12
Aufruf von t.insert(id):
C. Böhm: Bäume
25
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
t.insert(8)
:BinTree
t
z
. . .
:Node
key=7
this
z
id
8
:Node
:Node
key=5
key=10
:Node
:Node
:Node
key=3
key=6
key=12
Delegieren der Aufgabe durch
Aufruf von anchor.insert(id):
C. Böhm: Bäume
26
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insertKey(8):
:BinTree
t
z
. . .
:Node
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
:Node
:Node
:Node
key=3
key=6
key=12
Delegieren
der
Aufgabe
durch
Delegieren
der
Aufgabe
durch
Aufruf
von
anchor.insertKey(id):
Aufruf von anchor.insertKey(id):
Durchlauf durch das Node-Geflecht mit
zwei Hilfsvariablen current und parent
C. Böhm: Bäume
27
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insert(8):
:BinTree
z
. . .
t
:Node
Falls id > current.key,
Setze
gehe nach
rechts:
current
= this;
if(id > current.key)
= current;
currentparent
= current.right;
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
parent
z
z
:Node
:Node
:Node
key=3
key=6
key=12
Delegieren der Aufgabe durch
Aufruf von anchor.insert(id):
Durchlauf durch das Node-Geflecht mit
zwei Hilfsvariablen current und parent
C. Böhm: Bäume
28
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insert(8):
:BinTree
current
:Node
. . .
Und
setze:
Falls
id > current.key,
parent
= current;
gehe nach
rechts:
if(id > current.key)
current = current.right;
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
parent
z
z
C. Böhm: Bäume
:Node
:Node
:Node
key=3
key=6
key=12
29
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insert(8):
:BinTree
current
:Node
. . .
Falls
id < current.key,
Und setze:
parent
current;
gehe
nach= links:
if(id < current.key)
current = current.left;
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
parent
z
z
C. Böhm: Bäume
:Node
:Node
:Node
key=3
key=6
key=12
30
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insert(8):
:BinTree
current
:Node
. . .
Wenn current= null, füge neuen Knoten ein:
if(current
Falls id==< null)
current.key,
{ parent.left
gehe nach links:
= new< Node(null,id,null);
if(id
current.key)
return
this;= current.left;
current
}
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
null
parent
z
C. Böhm: Bäume
:Node
:Node
:Node
key=3
key=6
key=12
31
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insert(8):
:BinTree
current
:Node
. . .
Wenn current= null, füge neuen Knoten ein:
if(current == null)
{ parent.left
= new Node(null,id,null);
return this;
}
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
null
parent
z
C. Böhm: Bäume
:Node
:Node
:Node
:Node
key=3
key=6
key=10
key=12
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfügen in geordneten Binärbaum
Fügt einen neuen Knoten mit
Schlüssel id an der richtigen
Stelle im geordneten Baum ein
public void insert(int id, Object o)
{
if(anchor==null)
// falls kein Knoten im anchor
anchor = new Node(null, id, o, null);
// neuer Knoten
else anchor = anchor.insert(id, o);
}
wobei insert in class Node folgendermaßen definiert wird:
C. Böhm: Bäume
32
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
33
Einfügen in geordneten Binärbaum (Implementierung)
Fügt einen neuen
Node insert(int id, Object o)
Knoten passend ein
{
Node current = this;
// starte bei this
Achtung:id darf nicht
Node parent;
im Baum vorkommen!
while(true)
// terminiert intern
{
parent = current;
if(id < current.key) // gehe nach links?
{ current = current.left;
if(current == null) // am Ende füge links ein
{
parent.left = new Node(null, id, o, null);
return this;
}
} // end if go left
else
// falls id > current.key, gehe nach rechts
{ current = current.right;
if(current == null) // am Ende füge rechts ein
{
parent.right = new Node(null, id, o, null);
return this;
}
} // end else go right
} // end while
}
C. Böhm: Bäume
34
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Rekursion auf Binärbäumen
ƒ
Binärbäume sind induktiv definiert
ƒ
ƒ
ƒ
Operationen f auf Binärbäumen können rekursiv definiert
werden
ƒ
ƒ
ƒ
Falls isEmpty(B): 0
Ansonsten
getLeft().sumNodes1()+getRight().sumNodes1()+1
Beispiel: exist(int k)
ƒ
ƒ
8
2
Falls isEmpty(B): gibt f(B) direkt an
Ansonsten beschreibe wie sich der Wert von f aus f(B1),
1
f(B2) und id,o ergibt.
Beispiel: sumNodes1()
ƒ
ƒ
ƒ
BinTree(B1, k,o, B2)
Der Leere Baum ist ein Binärbaum
Sind B1 und B2 Binärbäume, id ein Schlüssel und o ein Objekt,
dann ist der Baum mit Wurzel id und o, linkem Teilbaum B1 und
7
rechtem Teilbaum B2 ein Binärbaum
(ist k vorhanden ?)
Falls isEmpty(B) : false
Ansonsten: getLeft().exists(k)
|| getKey()==k ||getRight().exists(k)
C. Böhm: Bäume
9
4
3
5
sumNodes: 8
35
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Einfache Baumoperationen
public class XBinTree extends BinTree
{ . . .
public int sumNodes1()
{
if(isEmpty()) return 0;
else return
((XBinTree)getLeft()).sumNodes1() +
((XBinTree)getRight()).sumNodes1() +1;
}
ƒ
isEmpty(), left(),
right() werden aus der
Oberklasse geerbt
ƒ
left() liefert einen
BinTree
ƒ
sumNodes1() ist nur in der
Unterklasse definiert - für
XBinTree
ƒ
public boolean exists(int k)
{
if(isEmpty()) return false;
else return
((XBinTree)getLeft()).exists(k)
|| getKey()==k
|| ((XBinTree)getRight()).exists(k);
}
. . .
}
C. Böhm: Bäume
Wir brauchen casts um die
BinTrees in XBinTreeS zu
verwandeln
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 07/08
Zusammenfassung
ƒ Binäre Bäume werden in Java implementiert:
ƒ als Verallgemeinerung der einfach verketteten Listen mit zwei
Nachfolgerverweisen
ƒ Eine Operation auf binären Bäume mit Knoten wird definiert:
ƒ durch Weitergeben der Operation an die Knotenklasse oder
ƒ durch Fallunterscheidung bzgl. des leeren Baums und rekursiven Aufruf
der Selektoren getLeft() und getRight() von BinTree.
C. Böhm: Bäume
36
Herunterladen