Bäume - Programmierung und Softwaretechnik (PST)

Werbung
2
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Ziele
ƒ Standardimplementierungen für Bäume kennen lernen
Bäume
Martin Wirsing
in Zusammenarbeit mit
Michael Barth, Philipp Meier und Gefei Zhang
02/05
M. Wirsing: Bäume
3
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Implementierung von Knoten
Bäume (abstrakt)
ƒ
Bäume sind hierarchische
Strukturen.
ƒ
Bäume bestehen aus
ƒ
Knoten und
ƒ
Teilbäumen.
Der oberste Knoten heißt
Wurzel.
ƒ
ƒ
ƒ
4
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
WurzelKnoten
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
Bei Binärbäumen hat jeder
Knoten zwei Unterbäume:
ƒ
den linken Unterbaum,
ƒ
den rechten Unterbaum.
left
Rechter Teilbaum
In den Knoten kann
Information gespeichert
werden.
right
: Node
3
Linker Teilbaum
left
M. Wirsing: Bäume
o
key value
: Node
o1
key value
9
right
left
o2
key value
right
M. Wirsing: Bäume
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
5
Implementierung von Bäumen
ƒ
public class BinTree
{
Node anchor; . . .
}
class Node
{
Node left;
int key; Object value;
Node right;
class BinTree 6
{ Node anchor;…
}
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Ein Beispiel für eine Instanz von BinTree
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.
ƒ
: BinTree
Eine Bauminstanz zeigt auf eine Nodeinstanz
anchor
: Node
7
// Konstruktor
Node(Node b1, int k, Object o, Node b2)
{ left = b1; key = k; value = o; right = b2;
}
left
o
key value
right
: Node
. . .
}
3
M. Wirsing: Bäume
M. Wirsing: Bäume
left
: Node
o1
key value
9
right
left
o2
key value
right
7
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
BinTree in UML
Operationen auf BinTree
ƒ
8
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Konstruktoren
ƒ
BinTree()
ƒ
ƒ
der leere Baum
BinTree(B1, k,o, B2)
neuer BinTree mit
ƒ
ƒ
ƒ
linkem Teilbaum B1
rechtem Teilbaum B2
Inhalt der Wurzel: k,o
ƒ
Prädikat isEmpty
ƒ
Selektoren
ƒ
Testen, ob ein BinTree leer ist
ƒ
boolean
BinTree
int
Object
BinTree
B2
+ BinTree
anchor
isEmpty()
getLeft()
getKey()
getValue()
getRight()
0..1
left, right
Object value
0..1
int getKey()
Object getValue()
Node getLeft()
Node getRight()
void setKey(int k)
void setValue(Object o)
void setLeft(Node l)
void setRight(Node l)
B1
getLeft, getRight, getKey
Falls der BinTree nicht leer ist, liefert
ƒ
getLeft() den linken Teilbaum
ƒ
getRight() den rechten Teilbaum
ƒ
getKey() den Inhalt der Wurzel
M. Wirsing: Bäume
Node
int key
M. Wirsing: Bäume
9
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
10
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Implementierung in Java
Implementierung BinTree: isEmpty & Zugriff auf linken Teilbaum
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;
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;}
ƒ Um Funktionen auf BinTree zu definieren, verwenden wir folgende
Fallunterscheidung:
ƒ leerer Baum:
BinTree getLeft() throws NoSuchElementException
{
if (anchor == null) throw new NoSuchElementException();
else
{
BinTree l = new BinTree();
l.anchor = anchor.getLeft();
return l;
}
}
Berechnung des Resultats direkt in BinTree
ƒ nicht-leerer Baum: Weitergeben (“delegieren”) der Funktion an Node
. . .
M. Wirsing: Bäume
M. Wirsing: Bäume
11
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Anzahl der Knoten
Anzahl der Knoten (Implementierung)
Prinzipieller Ablauf der (rekursiven) Berechnung von t.sumNodes():
1.
Berechne die Anzahl der Knoten suml
t:
Keller
...
z
...
7
des linken Teilbaums;
2.
:BinTree
t.anchor
Berechne die Anzahl der Knoten sumr
des rechten Teilbaums;
3.
12
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
:Node
10
5
key=7
Gesamtanzahl der Knoten:
1 + suml +sumr .
12
6
3
suml = 3
Halde
:Node
key=5
key=10
sumr = 2
Ergebnis = 1 + suml +sumr = 6
M. Wirsing: Bäume
:Node
M. Wirsing: Bäume
:Node
:Node
:Node
key=3
key=6
key=12
13
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
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
Implementierung BinTree: Anzahl der Knoten
...
z
...
Wenn der Baum leer ist,
gibt es keinen Knoten; d.h.
Anzahl = 0
int sumNodes()
{
if (anchor == null) return 0;
else return anchor.sumNodes();
}
:BinTree
t.anchor
where
:Node
:Node
key=5
key=10
Delegieren der Aufgabe an
class Node
sumNodes() (aus der
{ . . .
Klasse Node)
int sumNodes()
{
int suml = 0, sumr = 0;
if (left != null) suml = left.sumNodes();
if (right != null) sumr = right.sumNodes();
return 1 + suml + sumr;
}
. . .
:Node
key=7
:Node
:Node
:Node
key=3
key=6
key=12
sumr = 2
suml = 3
Ergebnis = 1 + suml +sumr = 6
M. Wirsing: Bäume
14
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
M. Wirsing: Bäume
15
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
16
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Geordnete Binärbäume
Geordnete Binärbäume
ƒ Ein Binärbaum b heißt geordnet, wenn folgendes für alle nichtleeren Teilbäume t von
b gilt:
ƒ Beispiel: Geordnet sind:
7
(abstrakte Darstellung)
Der leere Baum und
Der Schlüssel von t ist
t =
der Baum t:
8
5
ƒ 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
12
6
3
ƒ Nicht geordnet ist
7
der Baum t1:
t1 =
8
5
M. Wirsing: Bäume
12
9
3
M. Wirsing: Bäume
17
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Suche im geordneten Binärbaum
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;
18
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Prinzipieller Ablauf der Berechnung von t.find(6):
7
6<7
8
5
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
M. Wirsing: Bäume
6
12
3
M. Wirsing: Bäume
6
12
19
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Suche im geordneten Binärbaum
Suche im geordneten Binärbaum (Implementierung)
z
t
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.
t.find(6):
7
1.
2.
6<7
Da 6>5, gehe zum rechten Kindknoten
5
20
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
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.
8
3.
6>5
:BinTree
t.anchor
:Node
6<7
key=7
dieses Knotens;
5.
Vergleiche 6 mit dem Wert
dieses Knotens;
6.
:Node
12
6==6
return true;
6
3
:Node
key=5
key=10
6>5
Da 6==6, gebe Ergebnis true zurück.
:Node
:Node
key=3
key=6
:Node
key=12
6==6
return true
M. Wirsing: Bäume
M. Wirsing: Bäume
21
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Suche im geordneten Binärbaum
Suche im geordneten Binärbaum
Gibt true zurück, wenn key im
Baum; sonst wird false
zurückgegeben
public Object find(int key)
{ if (anchor == null) return false;
else return anchor.find(key);
}
wobei
22
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
public Object findValue(int key)
{ if (anchor == null) return null;
else return anchor.find(key);
}
wobei
Gibt value zurück, wenn key
im Baum; sonst wird null
zurückgegeben
class Node
{ . . .
Object 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
}
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
}
M. Wirsing: Bäume
M. Wirsing: Bäume
23
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfügen in geordneten Binärbaum
Einfügen in geordneten Binärbaum (Implementierung)
t.insert(8)
ƒ Beim Einfügen in einen geordneten Binärbaum wird rekursiv die “richtige” Stelle
gesucht, so dass wieder eine geordneter Binärbaum entsteht.
:BinTree
t
ƒ Beispiel: t.insert(8) ergibt:
(Zur Vereinfachung der Darstellung wird hier nur ein Schlüssel und kein Wert eingefügt.)
7
7
t=
z
. . .
:Node
key=7
this
z
id
8
t=
t.insert(8)
10
5
3
6
10
5
12
3
6
24
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
8
:Node
:Node
key=5
key=10
:Node
:Node
:Node
key=3
key=6
key=12
12
Aufruf von t.insertKey(id):
M. Wirsing: Bäume
M. Wirsing: Bäume
25
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfügen in geordneten Binärbaum (Implementierung)
Einfügen in geordneten Binärbaum (Implementierung)
t.insert(8)
anchor.insertKey(8):
:BinTree
t
z
. . .
this
z
id
8
:BinTree
t
z
. . .
this
z
8
:Node
:Node
key=5
key=10
:Node
:Node
key=7
key=7
:Node
:Node
id
key=5
key=10
this
z
id
8
:Node
:Node
:Node
:Node
:Node
:Node
key=3
key=6
key=12
key=3
key=6
key=12
Delegieren
der
Aufgabe
durch
Delegieren
der
Aufgabe
durch
Aufruf
von
Aufruf
vonanchor.insertKey(id):
anchor.insertKey(id):
Durchlauf durch das Node-Geflecht mit
zwei Hilfsvariablen current und parent
Delegieren der Aufgabe durch
Aufruf von anchor.insertKey(id):
M. Wirsing: Bäume
M. Wirsing: Bäume
27
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfügen in geordneten Binärbaum (Implementierung)
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insertKey(8):
:BinTree
z
. . .
:Node
Falls id > current.key,
Setze
gehe nach
rechts:
= this;
if(id >current
current.key)
= current;
currentparent
= current.right;
Und
setze:
Falls
id > current.key,
parent
= current;
gehe nach
rechts:
if(id > current.key)
current = current.right;
:BinTree
current
:Node
. . .
key=7
key=7
z
this
28
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
anchor.insertKey(8):
t
26
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
z
this
id
8
:Node
:Node
id
8
:Node
:Node
this
z
key=5
key=10
this
z
key=5
key=10
id
8
current
parent
z
z
id
8
current
:Node
:Node
:Node
key=3
key=6
key=12
parent
z
z
:Node
:Node
:Node
key=3
key=6
key=12
Delegieren der Aufgabe durch
Aufruf von anchor.insertKey(id):
Durchlauf durch das Node-Geflecht mit
zwei Hilfsvariablen current und parent
M. Wirsing: Bäume
M. Wirsing: Bäume
29
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfügen in geordneten Binärbaum (Implementierung)
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insertKey(8):
anchor.insertKey(8):
:BinTree
current
:Node
. . .
Falls
id < current.key,
Und setze:
parent
current;
gehe
nach= links:
if(id < current.key)
current = current.left;
:BinTree
current
:Node
. . .
key=7
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
z
this
30
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
z
this
id
8
:Node
:Node
id
8
:Node
:Node
this
z
key=5
key=10
this
z
key=5
key=10
id
8
current
parent
z
z
M. Wirsing: Bäume
id
:Node
:Node
:Node
key=3
key=6
key=12
8
current
null
parent
z
M. Wirsing: Bäume
:Node
:Node
:Node
key=3
key=6
key=12
31
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfügen in geordneten Binärbaum (Implementierung)
anchor.insertKey(8):
:BinTree
current
:Node
. . .
Einfügen in geordneten Binärbaum
Wenn current= null, füge neuen Knoten ein:
if(current == null)
{ parent.left
= new Node(null,id,null);
return this;
}
Fügt einen neuen Knoten mit
Schlüssel id an der richtigen
Stelle im geordneten Baum ein
key=7
this
z
id
8
:Node
:Node
this
z
key=5
key=10
id
8
current
null
parent
z
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.insertKeyObj(id, o);
}
wobei insertKeyObj in class Node folgendermaßen definiert wird:
:Node
:Node
:Node
:Node
key=3
key=6
key=10
key=12
M. Wirsing: Bäume
M. Wirsing: Bäume
33
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
M. Wirsing: Bäume
34
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Rekursion auf Binärbäumen
Einfügen in geordneten Binärbaum (Implementierung)
Fügt einen neuen
Node insertKeyObj(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
}
ƒ
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
9
4
3
5
sumNodes: 8
(ist k vorhanden ?)
Falls isEmpty(B) : false
Ansonsten: getLeft().exists(k)
|| getKey()==k ||getRight().exists(k)
M. Wirsing: Bäume
35
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Einfache Baumoperationen
public class XBinTree extends BinTree
{
public int sumNodes()
{
if(isEmpty()) return 0;
else return
((XBinTree)getLeft()).sumNodes() +
((XBinTree)getRight()).sumNodes() +1;
}
Zusammenfassung
ƒ
isEmpty(), left(),
right() werden aus der
Oberklasse geerbt
ƒ
left() liefert einen
BinTree
ƒ
sumNodes() ist nur in der
Unterklasse definiert - für
XBinTrees
ƒ
public boolean exists(int k)
{
if(isEmpty()) return false;
else return
((XBinTree)getLeft()).exists(k)
|| getKey()==k
|| ((XBinTree)getRight()).exists(k);
}
M. Wirsing: Bäume
32
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 04/05
Wir brauchen casts um die
BinTrees in XBinTrees zu
verwandeln
ƒ 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.
M. Wirsing: Bäume
36
Herunterladen