1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen...

29
1 Definition 3: Ein Baum T ist ein Tupel T = (N, E) mit der Menge N von Knoten(-punkten) und der Menge E der Kanten(-linien) < Ν = ) ( 0 }, | { N card i n N i N N E × Begriffe & Eigenschaften (Teil 1) Ein besonderer Knoten ist die Wurzel (root) r: sie besitzt - im Gegensatz zu einem „normalen“ Knoten - keinen Vorgänger (parent) p sondern nur 0 ... k Nachfolger (children) c i p r r c p c X (p,c) E p c 1 c 2 c 3 c k ... Geschwister (siblings) Wurzel (root) r: Vorgänger (parent) p, Nachfolger (children) c i Geschwister: 1 ) ( }, ) , ( : | { = = R card E r p N p r R } ) , ( | { } { 1 E c p N c c c c S i i i k p = = K i i c p child p c parent E c p p card R N c = = = ) ( , ) ( 1 }) ) , ( | ({ : \ }

Transcript of 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen...

Page 1: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

1

Definition 3:

Ein Baum T ist ein Tupel

T = (N, E)

mit der Menge N von Knoten(-punkten)

und der Menge E der Kanten(-linien)

∞<≤Ν∈= )(0},|{ NcardinN i

NNE ×⊆

Begriffe & Eigenschaften (Teil 1)

Ø Ein besonderer Knoten ist die Wurzel (root) r: sie besitzt - im Gegensatz zu einem „normalen“ Knoten - keinen Vorgänger (parent) p sondern nur 0 ... k Nachfolger (children) c i

p

r

r

c

p

cX (p,c) ∈ Ep

c1 c2 c3 ck...

Geschwister (siblings)

Wurzel (root) r:

Vorgänger (parent) p,Nachfolger (children) c i

Geschwister:

1)(},),(:|{ =∈∈∃= RcardErpNprR

}),(|{}{ 1 EcpNccccS iiikp ∈∧∈== K

ii cpchildpcparent

EcppcardRNc

===∈∈∀

)(,)(

1})),(|({:\}

Page 2: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

2

Ø Jeder Knoten ausser der Wurzel hat genau einen parent (Vorgänger)

Ø Ein Baum ist zusammenhängend, d.h. man kann von einem beliebigen Knoten aus über eine Folge von parent-Knoten zur Wurzel „aufsteigen“. Ein „Aufstieg“ oder „Abstieg“ im Baum über m Knoten hinweg heisst Pfad mit Länge m-1.Die Höhe h eines Knotens ist die Länge des Pfades von der Wurzel bis zu diesem Knoten. Für jeden Knoten gibt es genau 1 Pfad von der Wurzel zu diesem Knoten. Die Höhe h des Baumes ist der längst-mögliche Pfad im Baum, also das Maximum aller Höhen.

Ø Ein „normaler“ Knoten (mit Vorgänger und Kind(ern)) heisst innerer Knoten, ein Knoten ohne Kind(er) heisst Blatt. Der Grad eines Knotens ist die Anzahl seiner Kinder. Ein Blatt besitzt also den Grad 0 (deg(p)=0 ⇔ Knoten p ist Blatt). Der Grad eines Baumes T ist das Maximum der Knotengrade. Ist deg(T) ≤≤ 2, so ist T ein Binärbaum, ist deg(T) > 2, so ist T ein Mehrweg-/Vielwegbaum.

Ø Die Menge aller Kinder eines Knotens n bilden zusammen mit n denTeilbaum mit Wurzel n

Ø Ein Baum T heisst der Höhe nach ausgeglichen (height balanced), wenn die Höhe aller Teilbäume zu einem Knoten n (= Wurzel zu diesen Teilbäumen) sich maximal um 1 unterscheidet.Ein Baum T heisst dem Gewicht nach ausgeglichen (weight balanced) oder auch vollständig ausgeglichen, wenn sich die Teilbaum-Knoten-Anzahlen aller Teilbäume zu einem Knoten n (= Wurzel zu diesen Teilbäumen) maximal um 1 unterscheidet.

height balanced weight balanced

Page 3: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

3

Anwendung von Bäumen

Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind.

Ø Datenorganisation (→ Zugriffsbeschleunigung)Die sortierte Datenmenge einer Datei sei im Hauptspeicher in einem „sortierten“ Baum abgelegt:

Für jeden Knoten gilt: Im linken Teilbaum nur kleinere, im rechten nur grössere Elemente.

(Binär-)Suche nach Element x: Vergleiche x mit Wurzel, falls grösser, dann rechter Teilbaum, falls kleiner, dann linker Teilbaum u.s.w.

Höhe des Baumes bestimmend für maximale Suchzeit; deshalb sollte der Baum möglichst ausgeglichen sein.

Suche, ob k in Datenmenge enthalten: k<m → k>g → k=k → k enthalten

Suche, ob z in Datenmenge enthalten: z>m → z>q → z>t → z≠v → z nicht enthalten

Page 4: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

4

Ø Decodier(binär)baum für Morsezeichen

Begriffe & Eigenschaften (Teil 2)

Ø In geordnete Bäumen sind die Kinder-Knoten (Geschwister) eines parent-Knotens in einer zugewiesenen „horizontalen“ Ordnung sortiert.

p

c1 c2 c3 ck...

zugewiesene Ordnung

Ø Ein ganzer Binärbäumen ist ein Binärbaum, bei dem alle Knoten mit weniger als 2 Kindern durch Blätter „binär ergänzt“ wurden; alle ursprünglichen Knoten sind dann innere Knoten (deg = 2), die Blätter sind alle vom Grad deg = 0. Der ganze Binärbaum muss nicht ausgeglichen sein.

Ø Ein vollständiger Binärbaum ist ein optimal ausgeglichener, ganzer Binärbaum, alle möglichen Pfade Blatt → Wurzel sind gleich lang (= Höhe h des Baums)

Page 5: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

5

Dieser vollständige Binärbaum (jeder Knoten 2 Kinder) besitzt:♣ 2h Blätter (hier 23= 8)♣ 20 + 21 + ... 2h-1 = geometr. Reihe = (2h - 1)/(2-1) = (2h - 1) innere Knoten

Höheh = 3

Tiefe

0

1

2

3

Ø Ein vollständiger k-stelliger Baum (jeder Knoten k Kinder) besitzt: ♣ Anzahl Blätter = kh

♣ Anzahl innerer Knoten = k0 + k1 + ... kh-1 = geometr. Reihe = (kh - 1)/(k-1)♣ eine Höhe h = logk(Anzahl Blätter)

1. Term-Bäume

• Notation arithmetischer Ausdrücke• Transformation eines arithmetischen Ausdrucks in

Postfix-Notation• Generierung von Analyse-Bäumen („parse-trees)

Page 6: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

6

Notation arithmetischer Ausdrücke

Ø Infix-Notationist Standard-Notation mathematischer Ausdrücke

• 1-stelligen Operatoren: <aus> = <op><operand><op> = + | –

• 2-stellige Operatoren: <aus> = <operand><op><operand><op> = + | – | • | /

• Strukturierung durch Klammern: ( | )

Ø Präfix-Notation für• 2-stellige Operatoren: <aus> = <op><operand><operand>

Ø Postfix-Notation für• 2-stellige Operatoren: <aus> = <operand><operand><op>• keine Strukturierung durch Klammern notwendig!!

→→ maschinelle Auswertung

+ –

A B C D

Ø Baum-Notation:

Beispiel:

Ø Infix-Notation: (A + B) • (C – D)

Ø Präfix-Notation: • + A B – C D

Ø Postfix-Notation: A B + C D – •

Page 7: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

7

Transformation eines arithmetischen Ausdrucks in Postfix-Notation

Ø Der arithmetische Ausdruck sei in Infix-Notation gegeben (Standard-Notation)

A + (B – C)/D

Ø shunting-yard algorithm (Verschiebebahnhof-Algorithmus)

Ø Regeln des shunting-yard algorithmDie Zeichenfolge des Ausdrucks wird von rechts nach links bewegt; dabei wird jedes Symbol individuell evaluiert nach 5 Regeln:

1 Transfer: Operanden (am Anfang des Eingabestrings) →→ in Ausgabestring

2 push: linke (öffnende) Klammer →→ auf stack

3 REPEAT pop UNTIL (: alle Operatoren auf dem stack bis zur öffnenden Klammer →→ in Ausgabestring; dann werden beide Klammern gelöscht.

4 WHILE priority(top) >= operator DO pop: Operatoren auf dem Stack →→ in Ausgabestring bis das oberste Stack-Element von geringerer Priorität ist.

(steigende Priorität: ( →→ + – →→ • / )Falls Stack leer oder oberstes Stack-Element von geringerer Priorität, dann Operator →→ auf Stack (push)

5 WHILE NOT stack_empty DO pop: Input string leer ⇒⇒ alle Elemente auf Stack →→ Ausgabestring

Page 8: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

8

Page 9: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

9

Generierung von Analyse-Bäumen („parse-trees)

Ø arithmetische Ausdrücke: duale Operanden ⇔⇔ binäre Bäume

Ø Infix- & Postfix-NotationInfix: A • (((B + C) • (D • E) ) + F) ← für uns

Postfix: A B C + D E • • F + • ← für den Rechner mit Stack

Ø Analysebaum •

A +

• F

+ •

B C D E

Aufbau eines Analysebaums aus einer Eingabe in Postfix-Notation

TYPELINK = POINTER TO NODE;NODE = RECORD

info : CHAR;left, right : LINKEND;

VARx, z : LINK;c : CHAR;

PROCEDURE createLeaf() : LINK;VARleaf : LINK;

BEGINNEW(leaf);leaf^.left := leaf;leaf^.right := leaf;RETURN leaf

END createLeaf;

inforight

left

link

left

right

leaf

Page 10: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

10

BEGINstackInit;z := createLeaf();

REPEATREPEATReadChar(c)

UNTIL c <> ; (* skip blanks *)

NEW (x);x^.info := c;IF (c = '*') OR (c = '+') THENx^.right := pop;x^.left := pop

ELSEx^.right := z;x^.left := z

END;

push(x)UNTIL EOLN

END ....

z

x

x

z

Page 11: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

11

1. Repräsentation allgemeiner Bäume

• allgemeine Bäume• reine bottom-up Baumbearbeitung• reine top-down Baumbearbeitung

Allgemeine Bäume

Ø Allgemeine Bäume besitzen Knoten mit variabler Anzahl von Kind-Knoten

Ø Die Repräsentation bestimmt die Art der Operationen und umgekehrt

Page 12: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

12

reine bottom-up Baumbearbeitung

Ø Bäume, die nur von den Blättern aufwärts (bottom-up) bearbeitet werden

Ø Für jeden Knoten wird nur der Verweis zum parent-Knoten repräsentiert

parent

RECORDelem : elemtype;parent := LINK

END

Hinweis : Die Wurzel r zeigt auf sich selbst

r

Ø Einfache und effiziente Realisierung mittels Feldern:

info[.] : Information, z.B. Zeichenparent[.] : Index des parent-Knoten

Ø Beispiel:

E

T

A

M LP

A S

R E

E

1 2

3

4 5 6 7

8

9 11

10

k : 1 2 3 4 5 6 7 8 9 10 11

info[k] : A S A M P L E T R E E

parent[k] : 3 3 10 8 8 8 8 9 10 10 10

Page 13: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

13

reine top-down Baumbearbeitung

Ø Verwaltung von Kind-Knoten ohne vorherige Allokation einer spezifischen (maximalen) Anzahl.⇒⇒ verkettete Liste für Repräsentation der Knoten (variable Anzahl)

Ø Konzept: Knoten des Baums haben genau 2 Zeiger:♠ Zeiger L(inks) zum 1. (am weitesten links stehenden) Kind-Knoten♠ Zeiger R(echts) zu den (eigenen) Geschwister-Knoten♠ Der letzte Geschwister-Knoten zeigt zurück auf parent-Knoten

(→ Schleifen)

n

c

s1 ..... sk

Geschwister s1 ...sk von n

p

Ø Frage: Gibt es einen Unterschied zwischen dieser (Baum-)Struktur und binären Bäumen?

Antwort: Nein

Ø Beispiel:

E

T

A

M LP

A S

R E

E

E

T

A

M

L

P

A

S

R

E

E

Page 14: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

14

1. Traversieren von Bäumen

• Traversieren von Bäumen allgemein• Strategie pre-order• Strategie in-order• Strategie post-order• Strategie level-order

Traversieren von Bäumen allgemein

Ø Travesieren eines Baumes bedeutet das systematische Absuchen eines Baumes, wobei jeder Knoten „besucht“ wird (visit). „Besuchen“steht für: auslesen, einlesen, vergleichen, markieren, ...

Ø Hier: elementare Operationen auf Binärbäumen

Ø Beispielbaum:

E

T

A

M L

P

A

S

R

E

E

Page 15: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

15

Strategie pre-order

Ø Rekursive Strategie: Wurzel → l inker Teilbaum → rechter Teilbaum

E

T

A

M L

P

A

S

R

E

E

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

visit(t);

traverse(t^.L);

traverse(t^.R)

END

END traverse;

z ist Zeiger auf Blatt

Knotenfolge:

Rekursionstiefe:

E

6

A

4

A

4

S

3

M

2

P

1

E

5

T

5

R

4

E

3

L

2

visit(t) zuerst

TYPE

LINK = POINTER TO NODE

NODE = RECORD

elem : <elemtype>;L, R : LINK (* Verzweigung L(eft) & R(ight*)

END

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

visit(t);

traverse(t^.L);

traverse(t^.R)

END

END traverse;

Page 16: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

16

PROCEDURE traverse (t : LINK);

BEGIN

push(t)

WHILE NOT stack_empty DO

t := pop;

visit(t);

IF (t^.R <> z) THEN

push(t^.R)

END;

IF (t^.L <> z) THEN

push(t^.L)

END

END

END traverse;

Ø nicht­rekursive Pre-Order-Traversierung → Stack­basierte Lösung

(Annahme: Stack­Initialisierung außerhalb der Prozedur !)

Travesiere rechts

Travesiere links

pre-order

t

t^.L

t^.R

t^.L^.L

t^.L^.R

t^.R

t^.R

t^.L^.R

t^.R

visit(t) visit(t^.L) visit(t^.L^.L)

visit(t^.L^.R) visit(t^.R)

t

t^.Rt^.L

t^.L^.L

t^.L^.R

Ø Beispiel:

Page 17: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

17

Strategie in-order

Ø Rekursive Strategie: linker Teilbaum → Wurzel → rechter Teilbaum

E

T

A

M L

P

A

S

R

E

E

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

traverse(t^.L);

visit(t);

traverse(t^.R)

END

END traverse;

z ist Zeiger auf Blatt

Knotenfolge:

Rekursionstiefe:

A

4

S

3

A

4

M

2

P

1

E

6

E

5

T

5

R

4

E

3

L

2

visit(t) in der Mitte

TYPE

LINK = POINTER TO NODE

NODE = RECORD

elem : <elemtype>;L, R : LINK (* Verzweigung L(eft) & R(ight*)

END

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

traverse(t^.L);

visit(t);

traverse(t^.R)

END

END traverse;

Page 18: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

18

Sonderfall 2

Sonderfall 1

Ø nicht­rekursive In-Order-Traversierung → Die stack­basierte Lösung ist ein Beispiel dafür, dass die rekursive Programmierung viel eleganter ist (aber auch langsamer). In der stack­basierten Lösung sind 2 Sonder-fälle zu berücksichtigen.

Strategie post-order

Ø Rekursive Strategie: linker Teilbaum → rechter Teilbaum → Wurzel

E

T

A

M L

P

A

S

R

E

E

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

traverse(t^.L);

traverse(t^.R);

visit(t)

END

END traverse;

z ist Zeiger auf Blatt

Knotenfolge:

Rekursionstiefe:

E

6

S

3

A

4

M

2

A

4

P

1

E

5

T

5

R

4

E

3

L

2

visit(t) zuletzt

Page 19: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

19

TYPE

LINK = POINTER TO NODE

NODE = RECORD

elem : <elemtype>;L, R : LINK (* Verzweigung L(eft) & R(ight*)

END

PROCEDURE traverse(t: LINK)

BEGIN

IF t <> z THEN

traverse(t^.L);

traverse(t^.R);

visit(t)

END

END traverse;

Strategie level-order

Ø Nicht-rekursive Strategie: oben → unten und auf jedem level links → rechts

E

T

A

M L

P

A

S

R

E

E

Knotenfolge: EAASMP ETREL

Page 20: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

20

PROCEDURE traverse (t : LINK);

BEGIN

enqueue(t)

WHILE NOT queue_empty DO

t := dequeue(t);

visit(t);

IF (t^.L <> z) THEN

enqueue(t^.L)

END;

IF (t^.R <> z) THEN

enqueue(t^.R)

END

END

END traverse;

Ø nicht­rekursive Level-Order-Traversierung → Queue­basierte Lösung

es existiert keine offensichtliche rekursive Lösung!

Ø Anpassung der (nicht-rekursiven, stack-orientierten) Pre-Order-Prozedur:

t

t^.Rt^.L

t^.L^.L

t^.L^.R

Ø Beispiel:

oben rein

Queue!

unten raus

Page 21: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

21

1. Binäre Suchbäume

• Struktur• Aufwand• Implementierung des Baums• Einfügen eines Knotens• Löschen eines Knotens

Struktur

Ø Problem: Eine Menge von INTEGER/CARDINAL-Zahlen (oder an-deren Elementen, für die eine Ordnung gilt) soll eingelesen und so abgespeichert werden, dass für weitere Elemente möglichst schnell entschieden werden kann, ob diese zur eingelesenen Menge gehören oder nicht.

Ø Lösung: Die einzulesende Menge wird in einer binären Baumstrukturabgelegt, sodass jeder Knoten ein Element enthält und für jeden Teilbaum gilt:

Elemente im < Wurzelelement < Elemente imlinken Teilbaum rechten Teilbaum

Ø Suchbaum

Ø Beispiel:

25

8 32

5 13 30 38

2 6 11 19 26 31 36 41

Page 22: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

22

Aufwand

Ø Gegeben: Ein vollständiger Binärbaum T und eine Zahl x, die als Suchschlüssel dient.

Ø Verfahren:1 Vergleich von x mit Wurzelelement, wenn gleich, dann gefunden →→ fertig

2 wenn kleiner, suche im linken Teilbaum, wenn grösser, suche im rechten Teilbaum

3 falls x nicht gefunden wurde bis das erste Blatt erreicht wurde, ist x im Suchbaum nicht enthalten

Ø Aufwand im schlechtesten Fall (Durchsuchen der gesamten Höhe des Baumes) bei n Knoten:

♠ vollständiger Baum: ld(Anzahl Blätter) = ld (n+1) Suchschritte♠ entarteteter Baum (lineare Liste): n Suchschritte

Implementierung des Baumes

Ø Struktur:

TYPE

elemtype = CARDINAL;

LINK = POINTER TO NODE;

NODE = RECORD

elem : elemtype;

parent, L, R : LINK

END;

VAR

el : elemtype;

tree, newNode : LINK;

Elemente sind Zahlen

Page 23: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

23

Ø Einlesen von Elementen und Generierung von Knoten des Baumes

newNode

Einfügen eines Knotens(siehe nächste Folie)

:

tree := NIL;

el := 1; (* Abbruchwert = 0 *)

WHILE el <> 0 DO

ReadCard(el);

IF el <> 0 THEN

NEW(newNode);

newNode^.elem := el;

newNode^.parent := newNode;

newNode^.L := NIL;

newNode^.R := NIL;

InsertNode(newNode, tree)

END

END;

:

In der 1. Suchrunde:vorläufiger parent = Wurzel

Ø Nicht-rekursiver Algorithmusgegeben sind: Zeiger x auf neuen Knoten und Zeiger tree auf Baum(wurzel)

♣ der neue Knoten newNode wurde im letzten Programm erzeugt und mit einem Element el versehen. Der parent-Zeiger zeigt auf newNode selbst, L- und R-Zeiger auf NIL. Der neue Knoten soll mittels InsertNode(newNode, tree) in den Baum eingefügt werden.

♣ If der Baum noch leer ist (tree=NIL), then wird der neue Knoten zur Wurzel (tree:=x), (fertig!), else zeigt dessen parent-Zeiger vorläufig auf die Wurzel (par := tree) und die Bool‘sche Variable nodeInsert wird auf FALSE gesetzt, d.h. der neue Knoten ist noch nicht im Baum plaziert.

♣ Suche nach der r ichtigen Posit ion des neuen Knotens im Baum:♥ Vergleich der Elemente: if Knotenelement < parent-Element then Einbau des

Knotens in den l inken Teilbaum des vorläufigen parent (else in dessen rech-ten Teilbaum).

♥ If der l inke Zeiger des vorläufigen parent bereits auf einen Knoten zeigt (par^.L<>NIL), then wird dieser zum neuen vorläufigen parent (par:=par^.L)

und es geht von vorne los mit Elemente-Vergleich (while (NOT nodeInsert) -Schleife), else - Platz ist noch leer - wird der Knoten dort eingebaut: par^.L:=x; x^.parent:=par; nodeInsert.=TRUE (fertig!)

Einfügen eines Knotens

Page 24: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

24

PROCEDURE InsertNode(x : LINK; VAR tree : LINK);

VAR

par : LINK;

nodeInsert : BOOLEAN;

BEGIN

IF tree = NIL THEN (* leerer Baum *)

tree := x (* parent(x) = x *)

ELSE

par := tree,

nodeInsert := FALSE;

WHILE (NOT nodeInsert) DO

IF (x^.elem < par^.elem) THEN

IF (par^.L <> NIL) THEN par := par^.L

ELSE par^.L := x;

x^.parent := par;

nodeInsert := TRUE

END

ELSE

IF (par^.R <> NIL) THEN par := par^.R

ELSE par^.R := x;

x^.parent := par;

nodeInsert := TRUE

END

END (* IF *)

END (* WHILE *)

END (* IF *)

END InsertNode;

Baum leer → Knoten x ist Wurzel

Baum nicht leer → Wurzel ist (vorläufiger) parent

Einbau von x in li. Teilbaum des (vorl.) parent

Einbau von x in re. Teilbaum des (vorl.) parent

WHILE-Schleife läuft, bis Knoten x eingebaut

Ø Rekursiver Algorithmusgegeben sind: Zeiger x auf neuen Knoten und Zeiger tree auf Baum(wurzel)

♣ der neue Knoten newNode wurde im letzten Programm erzeugt und mit einem Element el versehen. Der parent-Zeiger zeigt auf newNode selbst, L- und R-Zeiger auf NIL. Der neue Knoten soll mittels InsertNode(newNode, tree) in den Baum eingefügt werden (wie beim nicht-rekursiven Algorithmus).

♣ If der Baum noch leer ist (tree=NIL), then wird der neue Knoten zur Wurzel (tree:=x), (fertig!), else Vergleich der Elemente: if Knotenelement < tree-Element then Einbau des Knotens in den l inken Teilbaum, also Aufruf von InsertNode(x, tree^.L).Achtung: Die Variable tree bekommt in diesem Aufruf den Zeigerwert von tree^.L zu-gewiesen!, d.h. der Zeiger tree zeigt im rekursiven Algorithmus immer auf die Tei lbaumwurzel!Falls Knotenelement nicht kleiner tree-Element (else-Zweig), wir der Knoten in dessen rechten Teilbaum eingebaut, also Aufruf von InsertNode(x, tree^.R).

♣ Ist die richtige Position des Knotens gefunden, wird sein parent-Zeiger auf die letzte(!) Teilbaum-Wurzel (das ist ja sein parent exakt im letzten(!) Aufruf von

InsertNode) gesetzt: x^parent := tree.

♣ Der rekursive Algorithmus ist bedeutend eleganter als der nicht-rekursive.

Page 25: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

25

Baum leer → Knoten x ist Wurzel

Einbau von x in linken Teilbaum von tree

PROCEDURE InsertNode(x : LINK; VAR tree : LINK);

BEGIN

IF tree = NIL THEN (* leerer (Teil­) Baum *)

tree := x

ELSE

IF (x^.elem < tree^.elem) THEN

InsertNode(x, tree^.L) (*in linken Teilbaum *)

ELSE

InsertNode(x, tree^.R) (*in rechten Teilbaum *)

END;

IF (x^.parent = x) THEN

x^.parent := tree

END

END

END InsertNode;

Einbau von x in rechten Teilbaum von tree

Der parent-Zeiger des Knotens x wird mit

der Adresse des Vorgängers belegt.

tree zeigt im rekursiven Algorithmus nicht immer auf die (Gesamt-)Baumwurzel

sondern auf die Teilbaumwurzel, in die der neue Knoten x eingebaut werden soll.

tree verändert sich bei jedem rekursiven Aufruf.

Ist die richtige Stelle für den neuen Knoten x im Baum gefunden, zeigt tree genau

auf den Vorgänger (parent)

25

8 32

5 13 26 38

2 6 11 19 30 36 41

31

Ø Beispiel:

Folge: 25 8 32 5 2 6 13 11 19 26 30 31 38 36 41

Page 26: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

26

2

Ø Beispiel: Dieselben Elemente, diesmal der Größe nach geordnet

5

6

8

11

13

19

25

26

30

31

32

36

38

41

Folge: 2 5 6 8 11 13 19 25 26 30 31 32 36 38 41

Ø iterativer Algorithmusgegeben: Zeiger x auf zu löschenden Knoten und Zeiger tree auf Baum(wurzel)Es treten 3 Fälle auf:

0 der Knoten besitzt keine Nachfolger: x^.L=NIL und x^.R=NILIn diesem Fall wird der Vorgänger (parent) des Knotens modifiziert.

1 der Knoten besitzt einen Nachfolger: entweder x^.L=NIL oder x^.R=NIL

In diesem Fall wird der Knoten herausgeschnitten (siehe Listen).

2 der Knoten besitzt zwei Nachfolger: weder x^.L=NIL noch x^.R=NILIn diesem Fall wird im rechten Teilbaum des Knotens immer l inks hinuntergegangen bis zum Knoten, der links ein Blatt hängen hat. Dieser Knoten hat folgende Eigenschaften:

♠ Sein Element ist größer als das Element des zu löschenden Knotens und alle Knotenelemente im linken Teilbaum des zu löschenden Knotens

♠ Sein Element ist das kleinste im rechten Teilbaum des zu löschenden Knotens♠ Sein Element folgt also in der Elementordnung dem Element des zu löschenden Knotens♠ Der Knoten besitzt höchstens einen Nachfolger

Dieser Knoten wird wie im Fall (0) oder (1) herausgeschnitten und an die Stel le des zu löschenden Knotens gesetzt.

Löschen eines Knotens

Page 27: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

27

5

6

5

löschen

5

6

10

5

10löschen

keine Nachfolger: ein Nachfolger:

zwei Nachfolger: 32

26

24

28

22 25

35

32 40

29

löschen

ausschneiden

32

28

24

22 25

35

32 40

29

Ersetze Knoten old durch Knoten new

PROCEDURE ReplaceNode(old, new : LINK);

BEGIN

old^.elem := new^.elem;

new^.parent := new;

new^.L := NIL;

new^.R := NIL

END ReplaceNode;

PROCEDURE SuccessorElem(x : LINK) : LINK;

BEGIN

x := x^.R;

IF (x <> NIL) THEN

WHILE (x^.L <> NIL) DO

x := x^.L

END

END;

RETURN x

END SuccessorElem;

Ø Programm; zuerst zwei Hilfsprozeduren

Überschreibe altes Knotenelement mit neuem

Die Zeiger des neuen Knotens werden „ausgehängt“

Finde den Knoten mit dem nächstgrösseren Element

x zeigt auf den Knoten, für den der Knoten mit dem nächstgrößere Element gesucht werden soll .Ein Schritt nach rechts, dann solange Schritte nach l inks, bis der Zeiger x auf einen Knoten mit l inkem Blatt zeigt. Dieser Knoten enthält das nächstgrößere Element

Page 28: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

28

Lösche Knoten xØ Programm; jetzt die Lösch-Prozedur (1. Teil)

Fall 0 oder 1: der Knoten x wird mit Zeiger del markiert, der Unterbaum von x wird an seiner Wurzel mit Zeiger subT markiert.

Fall 2: der Knoten mit dem nächstgrößeren Element wird mit Zeiger del markiert, des Knotens Unterbaum wird an seiner Wurzel mit Zeiger subT markiert.

PROCEDURE DeleteNode(x : LINK; VAR tree : LINK);

VAR

del, subT : LINK;

BEGIN

IF (x^.L = NIL) OR (x^.R = NIL) THEN

del := x;

IF (x^.L = NIL) THEN subT := x^.R

ELSE subT := x^.L

END

ELSE

del := SuccessorElem(x);

subT := del^.R

END;

...

...

IF (x^.parent = x) THEN (* x = root(tree) ? *)

tree := subT;

IF (subT <> NIL) THEN

subT^.parent := subT

END

ELSE

IF (del^.parent^.L = del) THEN del^.parent^.L := subT

ELSE del^.parent^.R := subT

END;

IF (subT <> NIL) THEN

subT^.parent := del^.parent

END;

IF (del <> x) THEN (* x­Knoten ersetzen ? *)

replaceNode(x, del)

END

END;

DISPOSE(del)

END DeleteNode;

Ø Programm; die Lösch-Prozedur (cont‘d)

Löschen von del (Fall 0,1,2): falls del am linken(rechten) Zeiger seines parent hing, wird dort jetzt subT angehängt

del <> x gibt es nur im Fall 2: dort wird der Knoten mit dem nächstgrößeren Element gelöscht und dessen Element im Knoten x eingesetzt. (gleichbedeutend mit Löschen von x und ersetzen durch Knoten mit dem nächstgrößeren Element.

Falls die (Gesamt-)Baumwurzel gelöscht werden soll, dann wird der Baumwurzelzeiger tree umgesetzt auf den Knoten, auf den subT zeigt und eine neue Wurzel gebildet.

Page 29: 1 · 3 Anwendung von Bäumen Ø UNIX-Dateisystem. Dieses ist im Prinzip ein Vielweg-Baum, dessen Kanten über die Links hergestellt sind. Ø Datenorganisation (→ Zugriffsbeschleunigung)

29

§ Ein Baum ist rekursiv definiert: An seiner Wurzel hängen (Teil-)bäume. Er besteht aus Knoten und Kanten. Jeder Knoten hat einen parent und 0 ... mehrere children . Anwendungen sind: übersichtl iche Darstellung, eff iziente Suche, ...

§ Arithmetische Ausdrücke werden gewöhnlich in infix-Notation geschrieben oder als

Termbaum gezeichnet. Für die maschinelle Verarbeitung ist die (klammerlose)

postfix-Notation geeignet. Eine Transformation infix- → postfix-Notation ist mittels shunting-yard-algorithm möglich. Die Generierung eines Termbaums im Rechner geschieht mittels „Verzeigerung“ von Knoten-Records, die ein Element besitzen, eine Adresse (auf die ein Zeiger eines anderen Knoten-Records zeigen kann) und drei eigene Zeiger (parent, left child, right child) zum „Verzeigern“ mit anderen Knoten (Kanten)

§ Traversieren von Bäumen: Durchlaufen eines gegebenen Baumes entlang der Kan-ten, wobei jeder Knoten einmal besucht wird, um dort eine Operation durchzuführen (auslesen, einlesen, vergleichen, markieren, ...). 4 Verfahren zur Traversierung

wurden vorgestellt: pre-order, in-order, post-order, level-order

§ Suchbäume sind aufgebaut aus Knoten mit Elementen (die sich ordnen lassen). Einbau eines zusätzlichen Knotens: Dieser wird „über die Baumwurzel eingespeist“ und je nachdem ob sein Element kleiner/größer ist als das Wurzelelement, steigt der Knoten einen Links-/Rechtsschrit t den Baum hinab, usw. Dies geschieht bis zu einem „leeren Ende“. Dort wird der Knoten „eingehängt“.Weitere Standard- Operationen: Löschen eines Knotens, Suchen etc .