tree

Bäume

Definition

Ein Baum ist eine hierarchische Datenstruktur, die aus Knoten besteht. Es gibt einen einzigen Wurzelknoten, von dem aus jeder andere Knoten über genau einen Pfad erreichbar ist. Jeder Knoten kann mehrere Kindknoten haben, wobei die Anzahl der Kindknoten je nach Baumtyp variieren kann:

  • Binärer Baum: Jeder Knoten hat höchstens zwei Kindknoten (linkes und rechtes Kind).
  • Allgemeiner Baum: Jeder Knoten kann eine beliebige Anzahl von Kindknoten haben.
Definition

Ein t-ärer Baum ist entweder die leere Menge oder ein Knoten (ein Objekt), welcher ein Datum und t Kindbäume enthält, welche t-äre Baume sind.

Definition

Ein Binär-Baum ist formal auch ein 2-ärer Baum.

Warum gibt es trees?

Binärbaum

Definition

  • Ein Binärbaum T ist eine Struktur, die auf einer endlichen Menge definiert ist. Diese Menge nennt man auch die Knotenmenge des Binärbaums.
  • Die leere Menge ist ein Binärbaum. Dieser wird auch als leerer Baum bezeichnet.
  • Ein Binärbaum ist ein Tripel (v,T1,T2), wobei T1 und T2 Binärbäume mit disjunkten Knotenmengen V1 und V2 sind, d.h. Und V1V2=, und vV1V2 Wurzelknoten heißt. Die Knotenmenge des Baums ist dann {v}V1V2 . T1 heißt linker Unterbaum von v und T2 heißt rechter Unterbaum von v.

Liste der Begriffe

Begriff Erläuterung Beispiel
Vorgänger (predecessor) - A ist Vorgänger von B
Nachfolger (successor) - B ist Nachfolger von A
Wurzel (root) kein Vorgänger A
Blatt (leaf) kein Nachfolger D, H, I, J, K
interner Knoten (inner node) alle Nachfolger besetzt A, B, C, G
Randknoten (boundary node) nicht alle Nachfolger besetzt D, E, F, H, I, J, K
Pfad (path) Knotenfolge von einem Anfangs- Pfad von der Wurzel nach F: A, C, F
bis zum Endknoten
Pfadlänge (path length) Anzahl der Kanten des Pfads Pfadlänge von A nach F: 2
Tiefe eines Knotens (depth) Pfadlänge zur Wurzel Tiefe von F: 2
Höhe eines Baumes (height) Größte Tiefe 3
Höhe eines Knotens v Höhe des Teilbaums von v Höhe von F: 1

Darstellung im Rechner

Binäre Suchbäume

Operationen

Durchlaufen

Inorder-Tree-Walk(x)          //Aufruf über Inorder-Tree-Walk(root(T))
1. if x ≠ nil then
2.    Inorder- Tree-Walk(lc(x))
3.    Ausgabe key(x)
4.    Inorder-Tree-Walk(rc(x))

Suchen – Rekursiv

1. if x =nil or k=key(x) then return x
2. if k<key(x) then return Baumsuche(lc(x),k) // Entweder links
3. else return Baumsuche(rc(x),k)             // oder rechts

Suchen – Iterativ

IterativeBaumsuche(x,k)
1. while x ≠ nil and k ≠ key(x) do
2.    if k < key(x) then x ← lc(x)
3.    else x ← rc(x)
4. return x

MIN/MAX Suche

MinimumSuche(x)
1. ehile lc(x) ≠ nil do x ← lc(x)
2. return x
MaximumSuche(x)
1. while rc(x) ≠ nil do x ← rc(x)
2. return x

Nachfolgersuche

Nachfolgersuche(x)
1. if rc(x) ≠ nil then return Minimumsuche(rc(x))
2. y ← p(x)
3. while y ≠ nil and x=rc(y) do
4.    x ← y
5.    y ← p(y)
6. return y

Vorgängersuche

Löschen

Höhe eines Binärbaumes

Definition

Die Höhe eines Binärbaumes mit Wurzel v ist die Länge (Anzahl der Kanten) des längsten einfachen Weges (keine mehrfach vorkommenden Knoten) von der Wurzel zu einem Blatt #Definition

Dynamische Bäume

Dynamische Baumoperationen

Traversierung von Bäumen

Definition

Die Traversierung eines Baum beschreibt die Reihenfolge in der alle Knoten eines Baumes besucht werden

Tiefen- und Breitensuche in Bäumen

!AlgoDat-LectureNotes, p.62

Kernkonzept

Tiefensuche in Bäumen

Bei der Tiefensuche (depth-first search) geht die Suche zunächst in die Tiefe und erst mit niedrigerer Präferenz in die Breite.
Man geht von einem Knoten zu dem Nachfolger, von dort wieder zu dessen Nachfolger usw. bis man an ein Blatt stößt. Dann geht man einen Schritt zurück und besucht den nächsten Nachfolger.
!AlgoDat-LectureNotes, p.58

Breitensuche in Bäumen

Bei der Breitensuche (breadth-first search) geht die SUche zunächst in die Breite und erst mit niedrigere Präferenz in die Tiefe.
Man geht von einem Knoten der Reihe nach zu allen direkten Nachfolgern und erst dann zu deren Nachfolgern.
!AlgoDat-LectureNotes, p.58

Pseudocode

Tiefensuche:

1 // Tiefensuche
2 D : ein Stapel ([[Stack]])
3 D ← {Wurzel}
4 while D̸ = ∅
5   v ← D.get () // pop()
6   besuche Knoten v
7   for all w Nachfolger von v
8     D.put(w) // push()
9   end
10 end

Rekursive Tiefensuche:

1 procedure DFS(v)
2   besuche Knoten v
3   for all w Nachfolger von v
4     DFS(w)
5   end
6 end
7
8 Aufruf durch: DFS( Wurzel )

Breitensuche:

1 // Breitensuche
2 D : eine Warteschlange (Queue)
3 D ← {Wurzel}
4 while D̸ = ∅
5   v ← D.get () // dequeue()
6   besuche Knoten v
7   for all w Nachfolger von v
8     D.put(w) // enqueue()
9   end
10 end