Tutoraufgabe 1 (Implementierung eines ADTs):

Ähnliche Dokumente
Tutoraufgabe 1 (Implementierung eines ADTs):

Tutoraufgabe 1 (Implementierung eines ADTs):

Tutoraufgabe 1 (2 3 4 Bäume):

f 1 (n) = log(n) + n 2 n 5 f 2 (n) = n 3 + n 2 f 3 (n) = log(n 2 ) f 4 (n) = n n f 5 (n) = (log(n)) 2

Tutoraufgabe 1 (2 3 4 Bäume):

Präsenzübung Datenstrukturen und Algorithmen SS 2014

Geordnete Binärbäume

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.

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

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

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

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

Übung zur Vorlesung Programmierung

Grundlagen der Informatik / Algorithmen und Datenstrukturen. Aufgabe 139

16. Dynamische Datenstrukturen

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

13. Dynamische Datenstrukturen

Vorlesung Datenstrukturen

Informatik II, SS 2014

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

1 Abstrakte Datentypen

13. Bäume: effektives Suchen und Sortieren

13. Bäume: effektives Suchen und Sortieren

18. Natürliche Suchbäume

Informatik II, SS 2014

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

2.2 Spezifikation abstrakter Datentypen. 2.3 Implementierung und Anwendung von ADT. 2.4 Datenabstraktion und Objektorientierung

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

Anwendungsbeispiel MinHeap

Datenstrukturen. Mariano Zelke. Sommersemester 2012

ALP II Dynamische Datenmengen Datenabstraktion (Teil 2)

1.1 Abstrakte Datentypen 1.2 Lineare Strukturen 1.3 Bäume 1.4 Prioritätsschlangen 1.5 Graphen

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

Abgabe: (vor 12 Uhr)

Software Entwicklung 1

Übung zur Vorlesung Programmierung

Informatik II, SS 2016

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

Übung Algorithmen und Datenstrukturen

Software Entwicklung 1

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

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

Datenstrukturen und Algorithmen. Vorlesung 8

Algorithmen und Datenstrukturen

11. Elementare Datenstrukturen

Elementare Datenstrukturen

Kapitel 12: Induktive

Probeklausur zur Vorlesung

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

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

elementare Datenstrukturen

Übung Algorithmen und Datenstrukturen

Allgemeine Hinweise:

Übung zur Vorlesung Programmierung

Übung Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen Musterlösung 5

18. Natürliche Suchbäume

Einführung in die Informatik

Informatik II, SS 2016

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

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

Prof. Dr. Uwe Schmidt. 30. Januar 2017

9. Natürliche Suchbäume

Abstract Data Structures

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Abstrakter Datentyp (ADT): Besteht aus einer Menge von Objekten, sowie Operationen, die auf diesen Objekten wirken.

Software Entwicklung 1

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

Fallstudie: Online-Statistik

Programmieren in Java

Übung 3 Musterlösung

Wintersemester 2004/ Dezember 2004

Grundlagen der Informatik / Algorithmen und Datenstrukturen. Aufgabe 132

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

Grundlagen der Informatik / Algorithmen und Datenstrukturen. Aufgabe 143

Semestralklausur Informatik I - Programmierung

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

1. Rekursive Algorithmen 2. Rekursive (dynamische) Datenstrukturen

Datenstrukturen und Algorithmen (SS 2013) Prof. Dr. Leif Kobbelt Thomas Ströder, Fabian Emmes, Sven Middelberg, Michael Kremer

Übung 4: Die generische Klasse AvlBaum in Java 1

5.3 Doppelt verkettete Listen

7. Verkettete Strukturen: Listen

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

Informatik II, SS 2014

Übung Algorithmen und Datenstrukturen

ALP II Dynamische Datenmengen

Abstract Data Structures

In diesem Kapitel behandeln wir erste Algorithmen mit dynamischen Strukturen, wie Bäume und Graphen. 1. Bäume Grundlagen...

Übersicht. Datenstrukturen und Algorithmen. Abstrakte Datentypen. Übersicht. Vorlesung 3: Elementare Datenstrukturen (K10)

Datenstrukturen. einfach verkettete Liste

Einführung in die Informatik 2

3. Übungsblatt zu Algorithmen I im SoSe 2017

Tutoraufgabe 1 (Sortieren): Lösung: Datenstrukturen und Algorithmen SS14 Lösung - Übung 4

Informatik II, SS 2014

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

Transkript:

Prof. aa Dr. E. Ábrahám Datenstrukturen und Algorithmen SS Tutoriumslösung - Übung (Abgabe.05.0) F. Corzilius, S. Schupp, T. Ströder Tutoraufgabe (Implementierung eines ADTs): Wir spezifizieren den ADT Union-Find wie folgt: Wertebereich: Sei Element ein Datentyp, der eine ganze Zahl in seinem Feld key enthält, d. h. e.key ist vom Typ int für e vom Typ Element. Der Wertebereich des ADT Union-Find enthält für alle n alle Partitionen von e,..., e n mit e i.key = i für alle i,..., n. D. h. der Wertebereich enthält für alle n und k n alle Mengen T,..., T k mit T i e,..., e n, e i.key = i für alle i n, T i für alle i k, T i T j = für alle i < j k und k T i = e,..., e n. i= Eine Menge in einer Partition wird durch eins ihrer Elemente, ihren eindeutigen Repräsentanten, identifiziert. Operationen: Der Konstruktor UnionFind(int n) erstellt die Partition e,..., e n von e,..., e n mit e i.key = i für alle i n. Vorbedingung: n. Element find(element e) gibt den Repräsentanten derjenigen Menge T j aus der Partition zurück, die e enthält. Vorbedingung: e.key n. void union(element e, Element e) vereinigt in der Partition die Mengen mit den Repräsentanten e und e. Vorbedingung: Die Partition enthält Mengen mit Repräsentanten e und e. (Um diese Datenstruktur sinnvoll verwenden zu können, benötigen wir noch eine Methode, die für ein i n das in der Datenstruktur verwendete Element e mit e.key = i zurückgibt; um die Aufgabe nicht zu komplex werden zu lassen, vernachlässigen wir diese Methode in der Schnittstelle.) Beispiel: Wir initialisieren eine Union-Find Datenstruktur UnionFind uf = UnionFind(5) und erhalten Führen wir nun uf.union(e, e) aus, erhalten wir e e e e wobei uf.find(e) == uf.find(e) == e. Führen wir zudem uf.union(e5, e) aus, erhalten wir wobei uf.find(e5) == e. e e e e e5 5 e e e e5 5 e5 5 e a) Implementieren Sie die Union-Find Datenstruktur unter Nutzung genau einer Instanz einer wie in der Vorlesung vorgestellten doppelt verketteten Liste (List). Es dürfen jedoch beliebig viele primitive (elementare) Datentypen verwendet werden. Tipp: Benutzen Sie zum Trennen der Mengen in einer Partition ein Element mit dem Wert 0. b) Implementieren Sie die Union-Find Datenstruktur unter Nutzung genau einer Instanz t eines (nicht reduzierten) doppelt verketteten Baumes (Tree), welcher wie der in der Vorlesung vorgestellte Baum definiert ist, nur dass jedes Element (Knoten) e zusätzlich einen Vorgänger e.father hat (mit t.root.father == null und e.father!= null für e!= t.root). Sie können die folgenden Operationen für Tree verwenden:

Tutoriumslösung - Übung (Abgabe.05.0) void addchild(element e, int key) fügt dem gegebenen Element (Knoten) e ein Kind mit Wert key hinzu. Vorbedingung: e ist ein Knoten im Baum. void removechild(element e, Element e) entfernt das Kind e von e. Vorbedingung: e ist ein Knoten im Baum, e ist ein Kind von e. void appendchild(element e, Element e) schneidet e von seinem Vater ab und fügt es anschließend e als Kind hinzu. Vorbedingung: e und e befinden sich im Baum und e ist kein Vorgänger von e (befindet sich nicht auf dem Pfad von der Wurzel zu e). Es dürfen jedoch beliebig viele primitive (elementare) Datentypen verwendet werden. Tipp: Benutzen Sie zum Trennen der Mengen in einer Partition ein Element mit dem Wert 0. Lösung: a) Die Liste fängt mit einem Element mit Schlüssel 0 an. Danach stehen die Elemente der Teilmengen, getrennt durch jeweils ein Element mit Schlüssel 0. Die Teilmengen werden repräsentiert durch das erste Element in dem entsprechenden Block in der Liste. class UnionFind // Attribute List content; // Operationen UnionFind(int n) content = List(); // konstruiert eine leere Liste content.insert(0); for(int i = ; i <= n; i++) content.insert(i); content.insert(0); Element find(element e) Element representative = e; while(content.predecessor(representative).key!= 0) representative = content.predecessor(representative); return representative; void union(element e, Element e) if(e == e) return; // die Teilmengen sind identisch // finde den Separator nach der. Teilmenge Element post = content.successor(e); while(post.key!= 0) post = content.successor(post); //finde den Separator vor der. Teilmenge Element pre = content.predecessor(e); // finde den Separator nach der. Teilmenge Element post = content.successor(e); while(post.key!= 0)

Tutoriumslösung - Übung (Abgabe.05.0) post = content.successor(post); // nehme die. Teilmenge (e bis post) aus der Liste pre.next = post.next; if (post.next!= null) post.next.prev = pre; else tail = pre; // fuege die. Teilmenge (e bis post) hinter der. Teilmenge (post) ein post.next = post.next; if(post.next!= null) post.next.prev = post; else tail = post; post.next = e; e.prev = post; // entferne den Separator zwischen den beiden Teilmengen content.remove(post); b) Der Baum hat eine Wurzel mit Schlüssel 0. Die Teilmengen sind die Kinder der Wurzel. class UnionFind // Attribute Tree content; // Operationen UnionFind(int n) // konstruiere einen Baum mit einem Knoten (=root) mit dem Wert (key) 0 content = Tree(0); // fuege fuer jedes <=i<=n ein Kind an for(int i = ; i <= n; i++) content.addchild(content.root, i); Element find(element e) Element representative = e; while(representative.father.key!= 0) representative = representative.father; return representative; void union(element e, Element e) if(e == e) return; // die Teilmengen sind identisch // entferne den. Repraesentanten von der Wurzel // und fuege ihn dem. Repraesentanten als Kind hinzu appendchild(e, e);

Tutoriumslösung - Übung (Abgabe.05.0) Tutoraufgabe (ADT einer Implementierung): Gegeben sei die folgende Klasse in der Programmiersprache Java: public class A private int [] pos ; private int [] neg ; public A() this. pos = new int [ 670886]; this. neg = new int [ 670886]; public boolean contains ( int i) if (i < 0) final int j = -i - ; return ( this. neg [j / ] & ( << (j % )))!= 0; else return ( this. pos [i / ] & ( << (i % )))!= 0; public void add ( int i) if (i < 0) final int j = -i - ; this. neg [j / ] = ( << (j % )); else this. pos [i / ] = ( << (i % )); public void remove ( int i) if (i < 0) final int j = -i - ; this. neg [j / ] &= ( -( << (j % )) - ); else this. pos [i / ] &= ( -( << (i % )) - ); Geben Sie eine möglichst allgemeine Spezifikation (Wertebereich und Signatur) für den abstrakten Datentyp an, der durch diese Klasse implementiert wird. Dabei ist der Wertebereich des Datentyps int die Menge I =, +,...,. Lösung: Ein Objekt vom Typ A repräsentiert eine Menge ganzer Zahlen aus I. Der Wertebereich des ADTs, den A implementiert, ist also I. Dieser ADT bietet die folgenden Operationen an: Der Konstruktor A() erstellt die leere Menge. boolean contains(int i) gibt true zurück, falls die Zahl i in der Menge enthalten ist. Ansonsten gibt es false zurück. void add(int i) fügt die Zahl i zur Menge hinzu. void remove(int i) löscht die Zahl i aus der Menge.

Tutoriumslösung - Übung (Abgabe.05.0) Tutoraufgabe 5 (ADT verwenden): Gegeben sei die folgende Spezifikation des abstrakten Datentyps BinaryTree für binäre Bäume: Wertebereich: Spezifiziert durch alle möglichen Belegungen der Variablen int value, BinaryTree leftchild und BinaryTree rightchild Operationen: int value() gibt den Wert von value zurück. BinaryTree left() gibt den Wert von leftchild zurück. BinaryTree right() gibt den Wert von rightchild zurück. Ein Pfad in einem Binärbaum b null vom Typ BinaryTree ist eine Sequenz e,..., e n von BinaryTree Objekten mit n, e = b, e i+ left(e i ), right(e i ) für alle i n und left(e n ) = right(e n ) = null. Entwerfen Sie a) einen rekursiven Algorithmus bool duplicate(binarytree b, int v, bool found), b) einen iterativen Algorithmus bool duplicate(binarytree b, int v), der überprüft, ob es im Binärbaum b einen Pfad gibt, auf dem mindestens zwei Objekte den Wert v haben. Verwenden Sie Stapel(Stacks) für den iterativen Algorithmus. Beispiel: btree duplicate(btree,) = true duplicate(btree,) = true duplicate(btree,) = false Lösung: a) boolean duplicate(binarytree b, int v, boolean found) boolean equals = (b.value() == v); if (equals && found) return true; // first instance already found found = found equals; if (b.left()!= null) if (duplicate(b.left(),v,found)) return true; if (b.right()!= null) return duplicate(b.right(),v,found); return false; Die rekursive Variante traversiert den Baum und hält den aktuellen Suchstatus im dritten Parameter fest. 5

Tutoriumslösung - Übung (Abgabe.05.0) b) boolean duplicate(binarytree b, int v) Stack firstfound, firstnotfound; // Keep track of found and other instances firstnotfound.push(b); // initialize stack bool found; BinaryTree current; while (!firstnotfound.isempty()!firstfound.isempty()) // as long as there are nodes left if (!firstfound.isempty) // give priority to subtrees where the element has been found current = firstfound.pop(); if (current.value() == v) return true; found = true; else // otherwise try to find first occurence current = firstnotfound.pop(); found = (current.value() == v); // push children to correct stack if (current.left()!= null) if (found) firstfound.push(current.left()); else firstnotfound.push(current.left()); if (current.right()!= null) if (found) firstfound.push(current.right()); else firstnotfound.push(current.right()); return false; Die iterative Variante behält Stacks: Einen für die Knoten, in denen das Element noch nicht gefunden wurde, und einen für die Knoten, in denen das Element schon einmal gefunden wurde. Der letztere wird bevorzugt und die beinhalteten Teilbäume traversiert. Genau wie für den ersten Stack gilt dabei: Wenn Kinder vorhanden sind, werden diese auf den jeweils korrekten Stack geschoben. Anschließend wird der nächste Knoten vom Stack geholt und überprüft. 6