Vorlesung Datenstrukturen Binärbaum Suchbaum Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 356 Datenstruktur Binärbaum Strukturrepräsentation des mathematischen Konzepts Binärbaum struct node { Elementtyp data; node* left; // linker Teilbaum / Kindknoten node* right; // rechter Teilbaum / Kindknoten }; Es existieren zwei Verbindungen zu den Kindknoten und Nullzeiger realisieren externe Knoten. Mit dieser Darstellung können die meisten Operationen für binäre Bäume effizient realisiert werden, allerdings lassen sich so nur Bewegungen von der Wurzel weg im Baum ausdrücken, d.h. nur Kindknoten verarbeiten. Für Algorithmen, die auf der direkten Kenntnis der übergeordneten Knoten basieren, bietet sich analog zur doppelt verketteten Liste die Ergänzung der Knotenstruktur um einen Verweis auf den Vorgänger eines Knotens an. Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 357 Beispiel - Aufbau eines Binärbaums Gesucht Algorithmus zum Aufbau eines möglichst ausgeglichenen Binärbaums mit beliebiger Knotenanzahl Idee Rekursive Verteilung der zu erzeugenden Knotenanzahl gleichmäßig auf die Teilbäume node* exampleTree( int count ) { if ( count ) { int leftNodes = count / 2; int rightNodes = count - leftNodes - 1; node* newNode = new node; newNode->left = exampleTree( leftNodes ); newNode->right = exampleTree( rightNodes ); return newNode; } else return 0; } Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 358 Traversieren von Binärbäumen Traversierung geordneter Bäume Im Gegensatz zur linearen Durchmusterung von Listen muss bei Bäumen eine Entscheidung getroffen werden: Diese Entscheidung besteht jedoch nicht darin, welcher Nachfolgerknoten ausgewählt wird (denn die Reihenfolge ist durch die Ordnung bereits vorgegeben), sondern wann ein Knoten bzgl. seiner Kindknoten ausgewertet wird. Traversierung von Binärbäumen Bei Binärbäumen gibt es drei Möglichkeiten: • Präorder - Traversierung = Auswertung eines Knotens vor seinen Kindern • Inorder - Traversierung = Auswertung eines Knotens inmitten seiner Kinder • Postorder - Traversierung = Auswertung eines Knoten nach seinen Kindern Ergebnis der Traversierung Konvertierung einer komplexeren Baumstruktur in eine „flache“ Listenstruktur. Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 359 Präorder-Traversierung Reihenfolge void traverse( node* n ) { if ( n ) { process ( n->info ); traverse( n->left ); traverse( n->right ); } } 1. Auswertung des Knotens 2. Auswertung des linken Teilbaums 3. Auswertung des rechten Teilbaums A B I C D F E G J H K M L N O Bezeichnung Ein Knoten wird vor seinen Kindknoten verarbeitet, also Präorder-Traversierung Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 360 Inorder-Traversierung Reihenfolge void traverse( node* n ) { if ( n ) { traverse( n->left ); process ( n->info ); traverse( n->right ); } } 1. Auswertung des linken Teilbaums 2. Auswertung des Knotens 3. Auswertung des rechten Teilbaums H D L B A F C E J G I N K M O Bezeichnung Ein Knoten wird inmitten seiner Kindknoten verarbeitet, also Inorder-Traversierung Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 361 Postorder-Traversierung Reihenfolge void traverse( node* n ) { if ( n ) { traverse( n->left ); traverse( n->right ); process ( n->info ); } } 1. Auswertung des linken Teilbaums 2. Auswertung des rechten Teilbaums 3. Auswertung des Knotens O G N C A F B D J E H M I K L Bezeichnung Ein Knoten wird nach seinen Kindknoten verarbeitet, also Postorder-Traversierung Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 362 Level-Order-Traversierung Wunsch Ebenenweise Verarbeitung von Baumknoten A Problem B Im Gegensatz zu den bereits bekannten Traversierungs- C arten entspricht eine ebenenweise Verarbeitung von Baumknoten nicht der natürlichen rekursiven D E F G Definition eines Baums. Lösung H I J K L M N Um Bäume ebenenweise verarbeiten zu können, ist eine Zwischenspeicherung von Baumknoten nötig, die mit Hilfe der Datenstruktur Schlange realisiert wird. Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 363 O ADT Schlange / Queue ADT Schlange Für viele Aufgaben in der Informatik werden Datenstrukturen benötigt, die nach dem FIFO-Prinzip arbeiten, d.h. dass das zuerst eingefügte Element auch als erstes wieder entnommen wird. Analog zum ADT Stapel wollen wir deshalb einen abstrakten Datentyp für die Datenstruktur Schlange entwickeln. Anwendung Da wir die Schlange konkret zur Baumtraversierung benötigen, muss sie Baumknoten bzw. Zeiger auf Baumknoten verwalten. Dementsprechend gestalten wir die Schnittstelle des ADT: class Queue { Queue() // Schlange mit Elementtyp „Baumknoten“ // Konstruktor ~Queue() // bool isEmpty() // void enqueue(node* data) // node* dequeue() // Destruktor Test auf leere Schlange „Anstellen“ an die Schlange „Abfertigen“ des ersten Elements } Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 364 ADT Queue - Interne Struktur struct node { Elementtyp data; node* left; node* right; }; class Queue { struct list { node* data; // Wir fügen Baumknoten in Schlange ein list* next; list(node* value) { // Hier eine Variante mit struct-Konstruktor data = value; next = 0; } }; list* head; // Einfügen und Entnehmen von Elementen erfolgt bei list* tail; // Schlangen an den entgegengesetzten Enden einer Liste Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 365 ADT Queue - Methoden public: node* dequeue() { if (isEmpty()) { printf("Schlange leer"); Queue() { head = tail = 0; } return 0; } else { node* value = head->data; bool isEmpty() { return (head == 0); } list* next = head->next; delete head; head = next; return value; void enqueue(node* value) { list* t = tail; tail = new list(value); if (!head) } head = tail; } ~Queue() { … // Löschen aller Listenelemente t->next = tail; } else } Dr. Frank Seifert }; Vorlesung Datenstrukturen - Sommersemester 2016 Folie 366 Level-Order-Traversierung Um die ebenenweise Verarbeitung zu ermöglichen, modifizieren wir die Präorder-Traversierung: • Zu Beginn fügen wir den Wurzelknoten des Baumes in eine Schlange ein. • Solange die Schlange nicht leer ist entnehmen wir den aktuell zu verarbeitenden Knoten n aus der Schlange, verarbeiten ihn und fügen die Kinder von n in die Schlange ein void traverseLevelOrder( node* n ) { Queue q; q.enqueue( n ); while ( !q.isEmpty() ) { n = q.dequeue(); process( n->info ); if ( n->left ) q.enqueue( n->left ); if ( n->right ) q.enqueue( n->right ); } } Dr. Frank Seifert A B C D H E I Vorlesung Datenstrukturen - Sommersemester 2016 J F K L G M N Folie 367 O Binärer Suchbaum Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 368 Binärer Suchbaum Definition Ein binärer Suchbaum ist ein binärer Baum, dessen interne Knoten mit einem Schlüssel verbunden sind. 8 Schlüssel sind eindeutig, es gibt keine verschiedenen Knoten mit dem selben Schlüssel. 4 12 Alle Knoten, deren Schlüssel kleiner als der Schlüssel eines Knotens ist, befinden sich im linken Teilbaum. 2 6 10 14 Alle Knoten, deren Schlüssel größer als der Schlüssel eines Knotens ist, befinden sich im rechten Teilbaum. 1 3 5 7 9 11 13 Konsequenz Die Gestalt der Datenstruktur „Suchbaum“ ist abhängig von ihren Werten! Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 369 15 Suchen im binären Suchbaum (1) Rekursiver Algorithmus 8 Aus der Gestalt eines Suchbaums ergibt sich ein rekursiver Suchalgorithmus: • Ist der aktuell betrachtete Baumknoten n ein externer Knoten ➔ erfolgloser Abbruch der Suche • sonst Vergleich des gesuchten Schlüssels mit dem Schlüssel von n 1 4 12 2 6 3 5 10 7 9 14 11 13 - Stimmen die Schlüssel überein ➔ erfolgreicher Abbruch der Suche - Ist der gesuchte Schlüssel kleiner, suche im linken Teilbaum von n - Ist der gesuchte Schlüssel größer, suche im rechten Teilbaum von n Initialisierung Startknoten des Algorithmus ist die Wurzel des Suchbaumes Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 370 15 Suchen im binären Suchbaum (2) Quelltext Algorithmus liefert Zeiger auf Baumknoten mit gefundenem Element oder Nullzeiger node* search( node* tree, int value ) { if ( tree == 0 ) { // value nicht vorhanden return 0; if ( tree->data == value ) // Element gefunden return tree; if ( value < tree->data ) return search( tree->left, value ); // Suche links else return search( tree->right, value ); // Suche rechts } } Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 371 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 372 99 Suchen im Suchbaum 37 ist kleiner als 50 ➔ Verzweigung nach links Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 373 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 374 99 Suchen im Suchbaum Suche nach 37 50 37 ist größer als 20 ➔ Verzweigung nach rechts 20 11 40 6 3 15 7 70 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 375 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 376 99 Suchen im Suchbaum Suche nach 37 50 20 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 70 37 ist kleiner als 40 ➔ Verzweigung nach links 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 377 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 378 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 37 ist größer als 31 ➔ Verzweigung nach rechts 6 3 15 7 12 Dr. Frank Seifert 40 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 379 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 3 15 7 12 Dr. Frank Seifert 59 31 19 26 45 37 44 85 55 48 51 66 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 80 68 79 91 84 88 Folie 380 99 Suchen im Suchbaum Suche nach 37 50 20 70 11 40 6 15 59 31 45 85 55 66 80 91 37 wurde mit nur 5 Vergleichen gefunden, bei 31 Elementen 3 7 12 Dr. Frank Seifert 19 26 37 44 48 51 57 Vorlesung Datenstrukturen - Sommersemester 2016 63 68 79 84 88 Folie 381 99 Suchen im Suchbaum Suche nach 37 50 Komplexitätsanalyse Die Suche benötigt in einem ausgeglichenen binären Suchbaum bei N Knoten maximal 20 ld(N) Schritte. Damit hat das Suchverfahren 11 eine Komplexität von O(log N). 40 Vergleich 6 15 31 45 Im Vergleich zur linearen Laufzeit der Suche nach einem Listenelement oder einer 3 7 12 19 26 37 44 48 Feldkomponente arbeitet die Suche nach einem Element in einem ausgeglichenen Suchbaum wesentlich effizienter. Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 382 Einfügen in einen Suchbaum (1) Such- und Einfügeoperationen eines Suchbaums sind eng miteinander verwandt: Der Knoten, an dem die Suche (nach einem nichtvorhandenen Schlüssel) abbricht, entspricht der Position, an dem ein neuer Knoten mit diesem Wert eingefügt werden muss. Der eingefügte bzw. bereits vorhandene Knoten wird als Funktionswert zurückgeliefert. Dr. Frank Seifert node* insert(node* tree, int value) { node* temp; if (tree) { if (tree->data == value) return tree; if (value < tree->data) if (tree->left) return insert(tree->left, value); else tree->left = temp = new node; else if (tree->right) return insert(tree->right, value); else tree->right = temp = new node; } else temp = new node; temp->data = value; temp->left = 0; temp->right = 0; return temp; } Vorlesung Datenstrukturen - Sommersemester 2016 Folie 383 Einfügen in einen Suchbaum (2) Komplexitätsanalyse Analog der Suchoperation benötigen wir bei einem ausgeglichenen binären Suchbaum mit N Knoten höchstens ld(N) Vergleiche um die Einfügeposition zu bestimmen und einen neuen Knoten anzuhängen ➔ Komplexität O(log N). Im Vergleich zur linearen Laufzeit zum Bestimmen der Einfügeposition in einer Liste arbeitet das Einfügen in einen ausgeglichenen Suchbaum wesentlich effizienter. Aber Bei „falscher“ Reihenfolge des Einfügens kann ein Baum sehr schnell degenerieren. Wenn das Ausgeglichenheitskriterium verletzt wird, tendiert die Laufzeit für Such- und Einfügeoperationen in die Größenordnung der entsprechenden Listenoperationen. Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 384 Ende der Vorlesung Dr. Frank Seifert Vorlesung Datenstrukturen - Sommersemester 2016 Folie 385