Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 15/16. Kapitel 13. Bäume. Bäume 1

Ähnliche Dokumente
Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 14. Bäume. Bäume 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 17/18. Kapitel 14. Bäume. Bäume 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12. Kapitel 13. Bäume. Bäume

Wintersemester 2018/19. Kapitel 14: Bäume

7. Dynamische Datenstrukturen Bäume. Informatik II für Verkehrsingenieure

Bäume. Martin Wirsing. Ziele. Implementierung von Knoten. Bäume (abstrakt) Standardimplementierungen für Bäume kennen lernen

Bäume. Prof. Dr. Christian Böhm. in Zusammenarbeit mit Gefei Zhang. WS 07/08

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 13. Listen. Listen 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 15/16. Kapitel 12. Listen. Listen 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12 1. Kapitel 11. Listen. Listen

Software Entwicklung 1

Bäume. Martin Wirsing. Ziele. Baumknoten. Bäume - 2-dimensionale Listen. Standardimplementierungen für Bäume kennenlernen

Semestralklausur Informatik I - Programmierung

Software Entwicklung 1

Suchbäume. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Anwendungsbeispiel MinHeap

Geordnete Binärbäume

Bäume 1. Thomas Röfer

Bäume. Text. Prof. Dr. Margarita Esponda SS 2012 O4 O5 O6 O ALP2-Vorlesung, M. Esponda

B6.1 Introduction. Algorithmen und Datenstrukturen. Algorithmen und Datenstrukturen. B6.1 Introduction. B6.3 Analyse. B6.4 Ordnungsbasierte Methoden

13. Bäume: effektives Suchen und Sortieren

13. Bäume: effektives Suchen und Sortieren

Natürliche Bäume. (Algorithmen und Datenstrukturen I) Prof. Dr. Oliver Braun. Letzte Änderung: :16. Natürliche Bäume 1/16

Kapitel 12: Induktive

Algorithmen und Datenstrukturen. Algorithmen und Datenstrukturen. B3.1 Einführung. B3.2 Verkettete Liste. B3.3 Bäume

Vorlesung Datenstrukturen

Algorithmen und Datenstrukturen

4.4.1 Implementierung vollständiger Bäume mit Feldern. Reguläre Struktur: Nachfolger des Knoten i sind die Knoten 2*i und 2*i+1.

Datenstruktur Baum Software Entwicklung 1

Informatik II Vorlesung am D-BAUG der ETH Zürich

18. Natürliche Suchbäume

Binäre Suchbäume. Mengen, Funktionalität, Binäre Suchbäume, Heaps, Treaps

Datenstruktur Baum und Rekursion Software Entwicklung 1

9. Natürliche Suchbäume

Einführung in die Informatik 2

Listen. Prof. Dr. Christian Böhm. in Zusammenarbeit mit Gefei Zhang. WS 07/08

Mengen. Binäre Suchbäume. Mengen: Anwendungen (II) Mengen: Lösung mit Listen 12/3/12. Mengen, Funktionalität, Binäre Suchbäume, Heaps, Treaps

Datenstrukturen Teil 2. Bäume. Definition. Definition. Definition. Bäume sind verallgemeinerte Listen. Sie sind weiter spezielle Graphen

elementare Datenstrukturen

Kapitel 5: Iterierbare Container

18. Natürliche Suchbäume

Algorithmen und Datenstrukturen. Algorithmen und Datenstrukturen. B6.1 Einführung. B6.2 Symboltabellen. B6.3 Einfache Implementationen

Physikalisch Technische Lehranstalt Wedel 31. Januar 2004 Prof. Dr. Uwe Schmidt

Datenstrukturen. einfach verkettete Liste

Übung 4: Die generische Klasse AvlBaum in Java 1

Übung Algorithmen und Datenstrukturen

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Tutoraufgabe 1 (Implementierung eines ADTs):

Algorithmen und Datenstrukturen. Algorithmen und Datenstrukturen. B4.1 Definitionen und Eigenschaften. B4.2 Traversierung. B4.

Objektorientierte Programmierung

Fachhochschule Wedel 31. Januar 2004 Prof. Dr. Uwe Schmidt

Algorithmen und Datenstrukturen. Bäume. M. Herpers, Y. Jung, P. Klingebiel

Tutoraufgabe 1 (Implementierung eines ADTs):

3 Dynamische Datenstrukturen

Bäume und der Sequence ADT

5.5 Prioritätswarteschlangen

Informatik II Prüfungsvorbereitungskurs

Abgabe: (vor 12 Uhr)

Binärbäume. Prof. Dr. E. Ehses,

Lösungshinweise/-vorschläge zum Übungsblatt 8: Software-Entwicklung 1 (WS 2017/18)

7. Verkettete Strukturen: Listen

Schwerpunkte. Verkettete Listen. Verkettete Listen: 7. Verkettete Strukturen: Listen. Überblick und Grundprinzip. Vergleich: Arrays verkettete Listen

Überblick. Rekursive Methoden. Backtracking. Memorization. Einfache rekursive Datenstrukturen. Aufzählen, Untermengen, Permutationen, Bitmengen

Aufrufe von Objektmethoden

Einführung in die Informatik 2

Wiederholung. Bäume sind zyklenfrei. Rekursive Definition: Baum = Wurzelknoten + disjunkte Menge von Kindbäumen.

Algorithmen und Datenstrukturen

Einstieg in die Informatik mit Java

Bäume. Listen und Bäume, Graphen und Bäume, elementare Eigenschaften von Binärbäumen, Implementierung, Generische Baumdurchläufe

Bäume. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 10: Collections 4. Inhalt. Bäume. Einführung. Bäume.

Prüfung Algorithmen und Datenstrukturen I

Einführung in die Objektorientierte Programmierung Vorlesung 18: Lineare Datenstrukturen. Sebastian Küpper

Verkettete Datenstrukturen: Bäume

Prof. Dr. Uwe Schmidt. 1. Februar Aufgaben zur Klausur C und Objektorientierte Programmierung im WS 2010/11 (WI h103, II h105, MI h353)

! 1. Rekursive Algorithmen.! 2. Rekursive (dynamische) Datenstrukturen. II.3.2 Rekursive Datenstrukturen - 1 -

Bäume, Suchbäume und Hash-Tabellen

1 Der Baum. Informatik I: Einführung in die Programmierung 11. Bäume. Bäume in der Informatik. Bäume in der Informatik - Definition.

Wiederholungsblatt Einführung in die Programmierung Lösungen

ALP II Dynamische Datenmengen

Objektorientierte Programmierung

Programmieren I. Kapitel 13. Listen

1. Rekursive Algorithmen 2. Rekursive (dynamische) Datenstrukturen

Komplexität eines Algorithmus, Grössenordnung, Landau-Symbole, Beispiel einer Komplexitätsberechnung (Mergesort) 7. KOMPLEXITÄT

Einführung in die Programmierung mit Java

Algorithmen und Datenstrukturen CS1017

Beispiellösung zur Klausur AI2 im Sommersemester 2007

public interface Stack<E> { public void push(e e); public E pop();

Software Entwicklung 1. Fallstudie: Arithmetische Ausdrücke. Rekursive Klassen. Überblick. Annette Bieniusa / Arnd Poetzsch-Heffter

Was ist ein assoziativer Speicher?

Informatik II, SS 2016

Transkript:

Kapitel 13 Bäume Bäume 1

Ziele Den Begriff des Baums in der Informatik kennenlernen Bäume als verkettete Datenstruktur repräsentieren können Rekursive Funktionen auf Bäumen verstehen und schreiben können Verschiedene Möglichkeiten zum Durchlaufen von Bäumen kennenlernen ( depth-first, breadth-first ) Bäume 2

Bäume Bäume sind eine der am meisten verwendeten Datenstrukturen in der Informatik. Bäume verallgemeinern Listen: In einer Liste hat jeder Knoten höchstens einen Nachfolger. In einem Baum kann ein Knoten mehrere Nachfolger haben. Liste: Baum: Bäume 3

Bäume: Definition Ein Baum besteht aus Knoten, die durch Kanten miteinander verbunden sind. Ein Wurzelknoten ist ein Knoten, auf den keine Kante zeigt. In Knoten können je nach Anwendung verschiedene Daten gespeichert sein. Die Menge aller Bäume wird durch folgende Regeln konstruiert: Es gibt einen leeren Baum. Ein einzelner Knoten ohne irgendwelche Kanten ist ein Baum. Ist n > 0 und sind B 1, B 2,, B n Bäume mit Wurzelknoten w 1, w 2,, w n, so kann man diese zu einem größeren Baum zusammensetzen, indem man einen neuen Knoten w hinzufügt und diesen mit w 1, w 2,, w n verbindet. Der neue Knoten ist dann Wurzelknoten des so aufgebauten Baums. w w 1 w 2 w n B 1 B 2 B n Bäume 4

a ist der Wurzelknoten des Baums. Bäume: Terminologie (1) h und i sind die Nachfolger- oder auch Kindknoten des Knotens d. d ist Vorgänger- oder Elternknoten von h. Knoten ohne Nachfolger (hier: e, j, k, g, h, i) heißen Blattknoten. Die Tiefe eines Knotens im Baum ist die Anzahl der Schritte, die benötigt werden, um den Knoten von der Wurzel zu erreichen. Die Tiefe des Baums ist das Maximum der Tiefen aller Knoten des Baums. (hier: 3) Ein Baum ist ein Binärbaum wenn jeder Knoten darin höchstens zwei Nachfolger hat. a: b: c: d: e: f: g: h: i: j: k: Tiefe 0 1 2 3 Bäume 5

Bäume: Terminologie (2) Jeder Knoten in einem Baum ist Wurzel eines Teilbaums des gegebenen Baums. Ein Teilbaum mit Wurzel w besteht aus dem Knoten w, seinen Kindern, Kindeskindern, usw. Beispiele: Der Teilbaum mit Wurzel b ist schwarz markiert und der mit Wurzel d ist weiß markiert. Der Teilbaum mit Wurzel a ist der ganze Baum selbst. Die Teilbäume mit Wurzeln b und d sind beide Binärbäume. Der gesamte Baum ist kein Binärbaum. a: b: c: d: e: f: g: h: i: j: k: Bäume 6

Bäume: Anwendungen (1) Bäume sind eine der am meisten verwendeten Datenstrukturen in der Informatik. Binärbäume können zur effizienten Speicherung von Daten benutzt werden. Sie stellen einen Mittelweg zwischen Arrays und Listen dar. Arrays: Listen: Zugriff auf Elemente: O(1) Einfügen eines Elements: O(n) Zugriff auf Elemente: O(n) Einfügen eines Elements: O(1) Geordnete Binärbäume: Zugriff auf Elemente: O(log n) Einfügen eines Elements: O(log n) Bäume 7

Datenbanken: Bäume: Anwendungen (2) Bäume werden zur indizierten Speicherung großer Datenmengen benutzt. Betriebssysteme: Dateisysteme sind in Baumdatenstrukturen organisiert und gespeichert. Baumartige Datenstrukturen sind in verschiedensten Anwendungen nützlich. Als Beispiel betrachten wir im Folgenden die Anwendung von Huffman-Bäumen zur Datenkomprimierung. Bäume 8

Beispielanwendung: Huffman-Kodierung (1) Bei der Speicherung von Text werden üblicherweise die einzelnen Zeichen kodiert und die Kodes der Zeichen dann hintereinander geschrieben. ASCII-Kodierung: Ein Zeichen wird mit 7 Bit kodiert. Java benutzt Unicode; ein Zeichen benötigt 16 Bit. Alle Zeichen, die einen ASCII-Kode haben, haben denselben Wert im Unicode. Unicode kann viele weitere Zeichen kodieren. Der 34 Zeichen lange Text lege an eine brandnarbe nie naegel hat mit ASCII-Kodierung eine Länge von 34*7 Bit = 238 Bit: 1101100110010111001111100101 Zeichen ASCII-Code a 1100001 e 1100101 g 1100111 l 1101100 l e g e In Texten kommen nicht alle Zeichen gleich häufig vor. Es wäre effizienter, für oft vorkommende Zeichen einen kürzeren Kode zu verwenden. Bäume 9

Beispielanwendung: Huffman-Kodierung (2) Die Huffman-Kodierung gibt häufig vorkommenden Zeichen einen kurzen Kode. Diese Kodierung wird z.b. im ZIP-Format benutzt. Anhand der Häufigkeiten der einzelnen Buchstaben wird ein Huffman-Baum aufgestellt. (Wir erklären hier nicht, wie der Baum errechnet wird.) Der Kode eines Zeichens ist die Liste der Entscheidungen, die man treffen muss, um von der Wurzel im Huffman-Baum zu dem Zeichen zu gelangen. (0 = gehe zu linkem Kindknoten, 1 = gehe zu rechtem Kindknoten) Beispiele: e = 01 (erst links, dann rechts) b = 1011 Der Baum wird so gewählt, dass häufig vorkommende Zeichen einen kurzen Kode haben. a e _ n d l g i r b Bäume 10

Der Text Beispielanwendung: Huffman-Kodierung (3) lege an eine brandnarbe nie naegel wird kodiert als: 00010110000111000111111001100111101110101110100011110 l e g e 0001110011010101101110111100101110111001011000010001 Der Text benötigt 105 Bits statt 238 Bits. e a _ n d l g i r b Bäume 11

Binärbäume in Java Bäume können in Java als verkettete Datenstruktur ganz ähnlich wie verkettete Listen implementiert werden. Zur Erinnerung: Speicherung einer Liste durch eine Kette von Objekten: :MyList first = :ListElement value = 3.0 next = :ListElement value = 7.0 next = :ListElement value = 5.0 next = null Anstelle eines Nachfolgezeigers next haben die Elemente bei Binärbäumen nun zwei Nachfolgerzeiger left und right. :BinTree root = :Node value = 3.0 left = right = repräsentiert den Baum 3.0 :Node :Node value = 4.0 value = 5.0 left = null right = null left = null right = null 4.0 5.0 Bäume 12

Klassen für Binärbäume BinTree: Eine Klasse für Binärbäume, die Methoden für die verschiedene Operationen auf Binärbäumen bereitstellt. Objekte der Klasse BinTree haben eine Referenz auf den Wurzelknoten des Baumes. Node: Eine Klasse, deren Objekte Baumknoten darstellen. Jedes Objekt hat einen double-wert und zwei Referenzen: Eine auf den Wurzelknoten des linken Teilbaums und eine auf den Wurzelknoten des rechten Teilbaums. Die Referenz ist jeweils leer (null), wenn es keinen entsprechenden Teilbaum gibt. - Node root BinTree + BinTree() + BinTree(double v) + BinTree(BinTree left, double v, BinTree right) + boolean isempty() + double getrootvalue() + BinaryTree getleft() + BinaryTree getright() + int size() + double sum()... - double value - Node left - Node right Node + Node(Node left, double value, Node right) + double getvalue() + Node getleft() + Node getright() Bäume 13

public class Node { private Node left; private double value; private Node right; public Node(Node left, double value, Node right) { this.left = left; this.value = value; this.right = right; public double getvalue() { return this.value; public Node getleft() { return this.left; Implementierung der Klasse Node public Node getright() { return this.right; Bäume 14

Die Klasse BinTree in Java: Konstruktoren public class BinTree { private Node root; /** Erzeugt den leeren Baum */ public BinTree() { this.root = null; /** Erzeugt einen Baum mit einem einzigen Knoten */ public BinTree(double v) { this.root = new Node(null, v, null); /** Konstruiert einen Baum, aus zwei gegebenen * Teilbäumen und einer neuen Wurzel mit Wert v. */ public BinTree(BinTree left, double v, BinTree right) { this.root = new Node(left.root, v, right.root); repräsentierter Baum: leer v v left right Bäume 15

Beispiel für die Konstruktion eines Baums public class BinTreeTest { a: 1 public static void main(string[] args) { BinTree k = new BinTree(8); BinTree j = new BinTree(7); BinTree f = new BinTree(j, 5, k); BinTree e = new BinTree(6); BinTree b = new BinTree(e, 2, f); BinTree g = new BinTree(4); BinTree empty = new BinTree(); BinTree c = new BinTree(empty, 3, g); BinTree a = new BinTree(b, 1, c); // Die Variablen repräsentieren jeweils // den Teilbaum mit dem gleichnamigen // Wurzelknoten. b: 2 c: 3 e: 6 f: 5 g: 4 j: 7 k: 8 Bäume 16

Der Baum im Heap :BinTree root = :Node value = 1.0 left = right = :Node value = 2.0 left = right = :Node value = 3.0 left= null right= :Node value = 6.0 left = null right = null :Node value = 5.0 left = right = :Node value = 4.0 left = null right = null :Node value = 7.0 left = null right = null :Node value = 8.0 left = null right = null Bäume 17

Operationen auf Binärbäumen Wir implementieren folgende typische Operationen auf Binärbäumen: isempty() testet, ob ein Baum leer ist. Selektoren: getrootvalue() gibt den Wert an der Wurzel zurück. 1 getleft() gibt den linken Teilbaum zurück. getright() gibt den rechten Teilbaum zurück. 2 3 size() berechnet die Anzahl der Knoten im Baum. sum() berechnet die Summe der in den Knoten gespeicherten Zahlen. 6 5 4 7 8 rechter Teilbaum linker Teilbaum Bäume 18

import java.util.nosuchelementexception; public class BinTree { private Node root; Die Klasse BinTree in Java: Methoden public boolean isempty() { return this.root == null; public double getrootvalue() { if (this.root == null) { throw new NoSuchElementException( "Ein leerer Baum hat keine Wurzel."); return this.root.getvalue(); public BinTree getleft() { if (this.root == null) { throw new NoSuchElementException( "Ein leerer Baum hat keinen linken Teilbaum."); BinTree l = new BinTree(); l.root = this.root.getleft(); return l; Bäume 19

Anzahl der Knoten (1) Die Anzahl der Knoten in einem binären Baum kann rekursiv wie folgt berechnet werden: Berechne die Anzahl sizeleft der Knoten im linken Teilbaum. Berechne die Anzahl sizeright der Knoten im rechten Teilbaum. Gesamtanzahl der Knoten: 1 + sizeleft + sizeright 1 2 3 6 5 4 7 8 sizeright = 2 sizeleft = 5 Bäume 20

Anzahl der Knoten (2) Implementierung des rekursiven Algorithmus: Deligiere die Berechnung der Größe des Baums an die Node-Objekte, d.h. füge in der Klasse Node noch eine Methode size() hinzu. Ein Node-Objekt berechnet die Größe des von ihm repräsentierten Teilbaums, indem es rekursiv die size()-methode auf seinem linken und rechten Node-Objekt aufruft und so die Werte sizeleft und sizeright berechnen lässt. Die Größe des Teilbaums ist dann 1+sizeLeft+sizeRight. a :BinTree root = n1 : Node left = right = n2 : Node left = right = n3 : Node left = null right = left = null n4 : Node right = null left = null n5 : Node right = null left = null n6 : Node right = null Bäume 21 sizeleft = 3 sizeright = 2

Anzahl der Knoten: Implementierung public class BinTree { public class Node { public int size() { if (this.root == null) { return 0; else { return this.root.size(); public int size() { int sizeleft = 0; int sizeright = 0; if (this.left!= null) { sizeleft = this.left.size(); if (this.right!= null) { sizeright = this.right.size(); return (1 + sizeleft + sizeright); Bäume 22

Bäume 23

Alternative Implementierung von size() Rekursive Funktionen können auch direkt in BinTree implementiert werden durch Fallunterscheidung bzgl. des leeren Baums und rekursiven Aufruf der Methode auf den von den Selektoren getleft() und getright() gelieferten Teilbäumen. public class BinTree { public double size() { if (isempty()) return 0; else return 1 + this.getleft().size() + this.getright().size(); Diese Implementierung ist eleganter aber weniger effizient. Bäume 24

Summe der Werte aller Knoten Die Summe der in einem Binärbaum gespeicherten Zahlen kann ebenfalls rekursiv berechnet werden: Berechne die Summe sumleft im linken Teilbaum. Berechne die Summe sumright im rechten Teilbaum. Gesamtsumme der Knoten: value + sumleft + sumright 1 2 3 6 5 4 7 8 sumright = 7 sumleft = 28 Bäume 25

Summe der Werte aller Knoten: Implementierung public class BinTree { public class Node { public double sum() { if (this.root == null) { return 0; else { return this.root.sum(); public double sum() { double sumleft = 0; double sumright = 0; if (this.left!= null) { sumleft = this.left.sum(); if (this.right!= null) { sumright = this.right.sum(); return this.value + sumleft + sumright; Bäume 26

Alternative Implementierung von sum() public class BinTree { public double sum() { if (isempty()) return 0; else return this.getrootvalue() + this.getleft().sum() + this.getright().sum(); Bäume 27

Durchlaufen eines Baums (1) Wie bei Listen möchte man über alle Elemente des Baums iterieren können. Bei Listen gibt es eine natürliche Ordnung des Durchlaufs, von vorn nach hinten. Bei Bäumen gibt es mehrere sinnvolle Reihenfolgen des Durchlaufs, die je nach Anwendungsfall alle benutzt werden. Wichtige Beispiele: Tiefendurchlauf ( depth-first traversal ): Besuche Wurzel Besuche linken Teilbaum mit Tiefendurchlauf Besuche rechten Teilbaum mit Tiefendurchlauf 1 2 7 Reihenfolge der Knoten in einem Tiefendurchlauf: 3 4 8 5 6 Bäume 28

Durchlaufen eines Baums (2) Breitendurchlauf ( breadth-first traversal ) Besuche die Knoten nach der Breite des Baumes geordnet. 1 2 3 Reihenfolge der Knoten in einem Breitendurchlauf: 4 5 6 7 8 Bäume 29

Baumdurchlauf mit Iteratoren Implementierung zweier Iteratoren, welche die beiden Arten des Baumdurchlaufs realisieren. Iterator für Tiefendurchlauf:... + DFIterator dfiterator() + BFIterator bfiterator() BinTree DFIterator - LinkedList<Node> tovisit + DFIterator(Node n) + boolean hasnext() + double next() Iterator für Breitendurchlauf: BFIterator - LinkedList<Node> tovisit + BFIterator(Node n) + boolean hasnext() + double next() Bäume 30

Erzeugung von Iteratoren in BinTree public class BinTree { private Node root; public DFIterator dfiterator() { return new DFIterator(this.root); public BFIterator bfiterator() { return new BFIterator(this.root); Bäume 31

Klasse DFIterator für Tiefendurchlauf (1) import java.util.linkedlist<e>; public class DFIterator { // Liste der Wurzeln aller noch zu besuchender Teilbäume, // in der Reihenfolge, in der sie besucht werden sollen. private LinkedList<Node> tovisit; // Der Iterator durchläuft den Baum mit Wurzel // im Tiefendurchlauf. public DFIterator(Node n) { this.tovisit = new LinkedList<Node>(); if (n!= null) { this.tovisit.addfirst(n); public boolean hasnext() { return! this.tovisit.isempty(); Bäume 32

Klasse DFIterator für Tiefendurchlauf (2) // Die Methode soll nur aufgerufen werden, wenn vorher mit hasnext() getestet wurde, // dass es ein nächstes Element gibt. public double next() { // Das erste Element der Liste tovisit ist die Wurzel des // nächsten zu besuchenden Baums. Beim Tiefendurchlauf // soll diese Wurzel als nächster Knoten besucht werden. Node n = this.tovisit.removefirst(); Node left = n.getleft(); Node right = n.getright(); // Als nächstes muss der Baum mit Wurzel left besucht werden // und danach der Baum mit Wurzel right. if (right!= null) { this.tovisit.addfirst(right); if (left!= null) { this.tovisit.addfirst(left); // Nun ist left ganz vorne in tovisit, gefolgt von right. return n.getvalue(); // Rückgabe des Werts der aktuellen Wurzel Bäume 33

Beispiel für einen Tiefendurchlauf public class BinTreeTest { public static void main(string[] args) { BinTree k = new BinTree(8); BinTree j = new BinTree(7); BinTree f = new BinTree(j, 5, k); BinTree e = new BinTree(6); BinTree b = new BinTree(e, 2, f); BinTree g = new BinTree(4); BinTree empty = new BinTree(); BinTree c = new BinTree(empty, 3, g); BinTree a = new BinTree(b, 1, c); a: 1 b: 2 c: 3 e: 6 f: 5 g: 4 DFIterator it = a.dfiterator(); while (it.hasnext()) { System.out.print(it.next() + " "); j: 7 k: 8 Ausgabe: 1.0 2.0 6.0 5.0 7.0 8.0 3.0 4.0 Bäume 34

Klasse BFIterator für Breitendurchlauf (1) import java.util.linkedlist<e>; public class BFIterator { // Liste der Wurzeln aller noch zu besuchender Teilbäume, // in der Reihenfolge, in der sie besucht werden sollen. private LinkedList<Node> tovisit; // Der Iterator besucht den Baum mit Wurzel n als // Breitendurchlauf. public BFIterator(Node n) { this.tovisit = new LinkedList<Node>(); if (n!= null) { this.tovisit.addfirst(n); public boolean hasnext() { return! this.tovisit.isempty(); Bemerkung: Dieser Teil ist identisch zum Iterator für Tiefensuche. Bäume 35

Klasse BFIterator für Breitendurchlauf (2) public double next() { Node n = tovisit.removefirst(); Node left = n.getleft(); Node right = n.getright(); // Im Unterschied zum Tiefendurchlauf werden die beiden // Teilbäume von n hier hinten angefügt. if (left!= null) { this.tovisit.addlast(left); if (right!= null) { this.tovisit.addlast(right); return n.getvalue(); Bäume 36

Beispiel für einen Breitendurchlauf public class BinTreeTest { public static void main(string[] args) { BinTree k = new BinTree(8); BinTree j = new BinTree(7); BinTree f = new BinTree(j, 5, k); BinTree e = new BinTree(6); BinTree b = new BinTree(e, 2, f); BinTree g = new BinTree(4); BinTree empty = new BinTree(); BinTree c = new BinTree(empty, 3, g); BinTree a = new BinTree(b, 1, c); a: 1 b: 2 c: 3 e: 6 f: 5 g: 4 BFIterator it = a.bfiterator(); while (it.hasnext()) { System.out.print(it.next() + " "); j: 7 k: 8 Ausgabe: 1.0 2.0 3.0 6.0 5.0 4.0 7.0 8.0 Bäume 37

Zusammenfassung Bäume sind eine wichtige Datenstruktur in der Informatik Binäre Bäume können in Java implementiert werden als Verallgemeinerung der einfach verketteten Listen mit bis zu zwei Nachfolgerverweisen. Viele Operationen auf binären Bäumen werden rekursiv definiert. In Java kann man rekursiv definierte Funktionen auf Bäumen implementieren durch Weitergeben der Operation an die Knotenklasse oder durch Fallunterscheidung bzgl. des leeren Baums und rekursiven Aufruf der Selektoren getleft() und getright() von BinTree. Wichtige Arten des Baumdurchlaufs sind Tiefendurchlauf und Breitendurchlauf. Bäume 38