Bäume und der Sequence ADT

Ähnliche Dokumente
Algorithmen und Datenstrukturen

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

Kapitel 4: Bäume i. 1. Einleitung. 2. Ein Datenmodell für Listen. 3. Doppelt-verkettete Listen. 4. Bäume. 5. Das Collections-Framework in Java

Kapitel 12: Induktive

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

ContainerDatenstrukturen. Große Übung 4

Programm heute. Algorithmen und Datenstrukturen (für ET/IT) Übersicht: Graphen. Definition: Ungerichteter Graph. Definition: Ungerichteter Graph

Datenstrukturen und Algorithmen. Vorlesung 8

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

ALP II Dynamische Datenmengen

Vorlesung Datenstrukturen

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

Informatik II, SS 2014

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

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

Software Entwicklung 1

Einfache binäre Suchbäume können entarten, so dass sich die Tiefen ihrer Blattknoten stark unterscheiden

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

Informatik B Sommersemester Musterlösung zur Klausur vom

Bäume 1. Thomas Röfer

Motivation Binäre Suchbäume

Anwendungsbeispiel MinHeap

Algorithmen und Datenstrukturen 2. Dynamische Datenstrukturen

Vorlesung Datenstrukturen

Software Entwicklung 1

11. Elementare Datenstrukturen

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Informatik B Sommersemester Musterlösung zur Klausur am

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

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

Vorlesung Datenstrukturen

Teil 1: Suchen. Ausgeglichene Bäume B-Bäume Digitale Suchbäume. M.O.Franz, Oktober 2007 Algorithmen und Datenstrukturen - Binärbäume 1-1

Übung 3 Musterlösung

Beispiellösung zu den Übungen Datenstrukturen und Algorithmen SS 2008 Blatt 5

Informatik II, SS 2016

Grundlagen der Informatik / Algorithmen und Datenstrukturen. Aufgabe 143

Wörterbücher ihre Implementierung mit AVL Bäumen

12. Dynamische Datenstrukturen

Mengen und Multimengen

Datenstrukturen. Mariano Zelke. Sommersemester 2012

Sortieren II / HeapSort Heaps

Σ /6 /6 /6 /6 /24

5.5 Prioritätswarteschlangen

9. Natürliche Suchbäume

13. Bäume: effektives Suchen und Sortieren

13. Bäume: effektives Suchen und Sortieren

18. Natürliche Suchbäume

Mengen und Multimengen

Datenstrukturen. einfach verkettete Liste

Übung Algorithmen und Datenstrukturen

Informatik II Übung 7. Gruppe 2 Carina Fuss

Programmieren I. Kapitel 13. Listen

Algorithmen und Datenstrukturen (für ET/IT) Wiederholung: Ziele der Vorlesung. Wintersemester 2012/13. Dr. Tobias Lasser

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

Informatik Abitur Bayern 2017 / II - Lösung

Lineare Liste. struct list_element { float f; /* weitere Elemente */ struct list_element *next; /* Zeiger auf Nachfolger-Element */ }; Peter Sobe

Algorithmen und Datenstrukturen (für ET/IT)

EINI LogWing/WiMa. Einführung in die Informatik für Naturwissenschaftler und Ingenieure. Vorlesung 2 SWS WS 17/18

Programmierkurs Java

Einführung in die Informatik 2

Theoretische Informatik 1 WS 2007/2008. Prof. Dr. Rainer Lütticke

3. Übungsblatt zu Algorithmen I im SoSe 2017

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.

Algorithmen und Datenstrukturen (ESE) Entwurf, Analyse und Umsetzung von Algorithmen (IEMS) WS 2013 / Vorlesung 10, Donnerstag 9.

Informatik II - Übung 07

Algorithmen und Datenstrukturen 1

Datenstruktur Baum Software Entwicklung 1

Algorithmen und Datenstrukturen 1

16. Dynamische Datenstrukturen

Übung Algorithmen und Datenstrukturen

Grundkonzepte java.util.list

Wiederholung. Datenstrukturen und. Bäume. Wiederholung. Suchen in linearen Feldern VO

Algorithmen und Datenstrukturen (ESE) Entwurf, Analyse und Umsetzung von Algorithmen (IEMS) WS 2014 / Vorlesung 10, Donnerstag 8.

Suchbäume. Suchbäume. Einfügen in Binären Suchbäumen. Suchen in Binären Suchbäumen. Prinzip Suchbaum. Algorithmen und Datenstrukturen

elementare Datenstrukturen

Übung Algorithmen und Datenstrukturen

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

Logische Datenstrukturen

6. Verkettete Strukturen: Listen

Technische Universität München. Vorlesungsgrobstruktur: wo stehen wir, wie geht s weiter

Informatik. Pointer (Dynamisch) Vorlesung. 17. Dezember 2018 SoSe 2018 FB Ing - SB Umwelttechnik und Dienstleistung - Informatik Thomas Hoch 1

Datenstrukturen und Algorithmen. Vorlesung 6

Problem: Was ist, wenn der Stapel voll ist? Idee: Erzeuge dynamisch ein grösseres Array und kopiere um. Dynamische Anpassung der Größe

Es sei a 2 und b 2a 1. Definition Ein (a, b)-baum ist ein Baum mit folgenden Eigenschaften:

Fragenkatalog 1. Kurseinheit

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

Binärbäume: Beispiel

Verkettete Datenstrukturen: Listen

13. Dynamische Datenstrukturen

Transkript:

Bäume und der Sequence ADT Motivation: Der Sequence ADT Bei der Vorstellung verschiedener Implementierungen für Stacks, Queues und Deques wurde vor allem auf die Unterschiede zwischen Arrays fester Größe, dynamiyschen Arrays (Vektoren) sowie einfach und doppelt verketteten Listen hingewiesen. Die Gemeinsamkeit all dieser Realisierungen lässt sich auf den Kern reduzieren, dass man mit Ihnen alle Elemente einer geordneten Kollektion in der gegebenen Reihenfolge durchlaufen kann. Diese Funktionalität wird durch das Java Interface Iterator<E> beschrieben, das nur die Hauptmethoden boolean hasnext() und E next() hat. Ein Iterator it einer Kollektion liefert mit dem ersten Aufruf it.next() das erste Element der Kollektion und mit jedem weiteren Aufruf das jeweils nächste Element. Mit it.hasnext() kann vor jedem it.next() Aufruf geprüft werden, ob man schon beim letzten Element der Kollektion angekommen ist. Diese Methoden reichen bereits aus, um Pseudocode Schleifenanweisungen der Form for all x... zu implementieren. Allerdings kann man mit dem minimalen Konzept der Iteratoren noch keine Einfüge oder Löschoperationen umsetzen. Solche Erweiterungen werden (in verschiedenen Ausprägungen) in den Java Interfaces Collection<E>, List<E>, ListIterator<E> und Set<E> beschrieben. Der Sequence ADT, den wir im folgenden besprechen wollen, ist in dieser Form kein Java Interface (es gibt eine Java Klasse Sequence, aber darin geht es um musikalische Informationen im MIDI System), am nächsten liegt das Java Interface List<E>. In einer solchen Sequence (Folge) hier werden Daten eines Typs E in einer linearen Ordnung gehalten (also ein Iterator), aber der Zugriff auf die Daten kann an beliebãger Stelle erfolgen. Dabei unterscheidet man zwischen der Position und dem Rang eines Elements. Unter der Position des Elements verstehen wir eine Referenz auf das Element. Dagegen ist der Rang die nummerierte Stelle des Elements in der Folge. Neben dem Zugriff auf ein Element über seine Position oder über seinen Rang sind Einfügeoperationen vor oder hinter einer gegebenen Position bzw. auf einem bestimmten Rang und Löschoperationen an einer Position oder auf einem bestimmten Rang gefordert. Wie bereits bei Deques besprochen, kann dieser Datentyp durch dynamische Arrays oder durch doppelt verkettete Listen implementiert werden. Der einzige wesentliche Vorteil der Array-Implementierung liegt im Zugriff auf das Element mit Rang k, für den man bei der Listenimplementierung k next- Referenzen vom Anfangselement verfolgen muss. Beim Einfügen und Löschen mit Rang hat die Array- Implementierung zwar auch den Vorteil, das man unmittelbar auf die Stelle zugreifen kann, aber dafür mus der gesamte Array-Inhalt hinter dieser Stelle um eins nach rechts (beim Einfügen) oder um eins nach links (beim Löschen) verschoben werden. Die Vor- und Nachteile dieser Implementierungen werden in der folgenden Tabelle deutlich. Die Länge der Folge wird dabei mit n bezeichnet. Operation Laufzeit bei Laufzeit bei Implementierung Array-Implementierung mit doppelt verk. Listen Zugriff auf Position Θ(1) Θ(1) Zugriff auf Rang Θ(1) Θ(n) Einfügen mit Position Θ(n) Θ(1) Einfügen mit Rang Θ(n) Θ(n) Löschen mit Position Θ(n) Θ(1) Löschen mit Rang Θ(n) Θ(n)

Für große Werte von n ist keine dieser Implementierungen wirklich befriedigend. Die Idee für eine effizientere Implementierung gründet sich zuerst auf die Beobachtung, dass sich alle Nachteile der Listenimplementierung auf einen Punkt fokussieren lassen: Das Finden der Position (Referenz) bei gegebenen Rang. Ist das geschehen, kann auch in konstanter Zeit eingefügt und gelöscht werden. Um den Zusammenhang zwischen Rang und Position algorithmisch schneller bearbeiten zu können, wird ein binärer Baum über die Liste gelegt, so dass jedes Blatt eine Referenz auf ein darunter liegendes Listenelement hält. Wenn man zusätzlich in jedem inneren Knoten vermerkt, wieviele Blätter der linke und der rechte Teilbaum enthalten, kann man leicht einen Algorithmus entwerfen, der bei gegebenem k von der Wurzel beginnend das k-te Blatt erreicht. Die Zeit ist proportional zur Tiefe des Baums, bei einem balancierten Baum O(log 2 n). Beim Einfügen und Löschen muss natürlich auch der Baum aktualisiert werden, aber das geht wieder in logarithmischer Zeit. 4 3 2 2 2 1 1 1 1 1 1 1 Das Hauptproblem besteht darin, dass bei einer ungünstigen Folge von Einfügeoperationen der Baum die Balanceeigenschaft verlieren und damit die Zeit auf Ω(n) anwachsen kann. Es gibt verschiedene Ansätze zur Lösung dieses Problems mit denen wir uns in den nächsten Vorlesungen beschäftigen werden. Bäume mit Wurzeln (rooted Trees) Definition: Ein (gewurzelter) Baum besteht aus einer Menge T von Knoten, die wie folgt strukturiert ist: 1. Es gibt genau einen hervorgehobenen Knoten r T, die Wurzel des Baums 2. Jeder Knoten außer r hat genau einen Vaterknoten (pc: Elternknoten) 3. Die Wurzel r ist Vorfahr jedes Knotens. Dabei wird der Begriff v T ist Vorfahr u T rekursiv definiert, durch die Fälle 1. u = v oder 2. v ist Vorfahr des Vaterknotens von u Weitere Begriffe, die mit dieser Definition in Zusammenhang stehen, sind: u ist Kind von v genau dann, wenn v Vaterknoten von u ist.

u ist Nachkomme von v genau dann, wenn v Vorfahr von u ist. u und v sind Geschwister genau dann, wenn sie den selben Vaterknoten haben. Knoten ohne Kinder heißen Blätter oder äußere Knoten. Knoten mit (mindestens) einem Kind heißen innere Knoten. Wenn wir in diesem Teil der Vorlesung von einem Baum sprechen, meinen wir immer einen gewurzelten Baum. Die in der Graphentheorie definierten Bäume sind ungewurzelt, aber wie man bei BFS und DFS gesehen hat, kann man durch Festlegung eines speziellen Knotens ungewurzelte Bäume leicht in gewurzelte Bäume verwandeln. Definition: Ein Baum ist ein geordneter Baum, wenn für jeden Knoten die Menge seiner Kinder geordenet ist (erstes Kind, zweites Kind,...). Ein ADT für geordnete, gewurzelte Bäume Die Beschreibung eines ADTs für gewurzelte Bäume weist große Ähnlichkeit zum Listen-ADT auf. Auch hier konzentriert sich die Beschreibung auf die Knoten. Zur Repr sentation des Baums reicht dann ein einzelner Knoten, nämlich die Wurzel aus. Ein Baumknoten muss die Referenzen auf den Elternknoten und die Kinder sowie auf ein Objekt vom Typ E (falls der Knoten Daten speichern soll) halten. Der Typ TreeNode wird durch die folgenden Methoden beschrieben: TreeNode parent(); //der Elternkonten E element(); //die Daten TreeNode[] children(); //Liste der Kinder boolean isroot(); boolean isleaf(); void setelem(e e); void setparent(treenode v); void addchild(treenode v); //dazu muss v setparent(this) ausfuehren void addsubtree(treenode v); //macht das Gleiche wie addchild(treenode v) Definition: Ist T ein Baum und T T eine Untermenge der Knotenmenge, so nennen wir T einen Unterbaum von T, wenn T selbst ein Baum ist und für jeden Knoten v T auch alle Kinder von v zu T gehören. Wie man leicht sieht gibt es eine Bijektion (d.h. eine umkehrbare Abbildung) zwischen der Menge der Knoten und der Menge der Unterbäume von T. Einerseits kann man jedem Knoten v, den Unterbaum aller Nachfolger von v (inklusive v als Wurzel) zuordnen. Für die Umkehrabbildung ordnen wir jedem Unterbaum seine Wurzel zu. Definition: Sei T ein Baum und v T ein Knoten. Der Abstand von v zur Wurzel nennen wir die Tiefe von v und den Abstand von v zu seinem weitesten Nachfahren die Höhe von v. Die Höhe der Wurzel definiert die Höhe und gleichzeitig die Tiefe des Baums. Beide Definitionen kann man rekursiv formulieren und entsprechend implementieren: { 0 falls v die Wurzel ist Tiefe(v) = 1 + Tiefe(Vater von v) sonst Höhe(v) = { 0 falls v ein Blatt ist 1 + max{höhe(u) u ist Kind von v sonst

int depth(){ // als Methode von TreeNode int d=0; if(! isroot()) d = 1 + parent().depth(); return d; int height(){ // als Methode von TreeNode int h=0; if(! isleaf()){ for(int i=0; i< children().length; i++) if(h < (children()[i]).height()){ h= (children()[i]).height(); h++; return h; Die Laufzeit der Tiefenberechnung ist proportional zur Tiefe, die Laufzeit der Höhenberechnung ist proportional zur Größe des Unterbaums. Ähnlich wie bei verketteten Listen wird ein Baum nur durch seine Wurzel repräsentiert. Die vollständige Struktur ergibt sich erst durch die Verkettung von Referenzen. Da diese Struktur komplexer als bei verketteten Listen ist, spielen Methoden zum Durchlaufen von Bäumen (tree traversals) eine wichtige Rolle. Zwei dieser Durchlaufmethoden kann man für beliebige Bäume anwenden: Preorder- und Postorder-Traversierungen. Sie laufen nach den folgenden Regeln ab: Preorder: Für jeden zu durchlaufenden Teilbaum besuche zuerst die Wurzel und durchlaufe dann nacheinander die Teilbäume aller Kinder. Postorder: Für jeden zu durchlaufenden Teilbaum durchlaufe nacheinander die Teilbäume aller Kinder und zum Schluss die Wurzel. Beispiel: a b c d e f g h i j k l m n o p

Für den abgebildeten Baum ergeben sich die Knotenfolgen a,b,e,m,n, f,g,o,c,h,i, p, j,d,k,l beim Preorder-Durchlauf, m,n,e, f,o,g,b,h, p,i, j,c,k,l,d,a beim Postorder-Durchlauf.