Pro Informatik 2009: Objektorientierte Programmierung Tag 16 Marco Block-Berlitz, Miao Wang Freie Universität Berlin, Institut für Informatik 07.09.2009 Agenda Tag 16 – Datenstrukturen Abstrakte Datentypen, ADT Folge: Stack, Queue, Liste, ADT Menge: Bäume: Binärbäume, Suchbäume, AVL-Bäume, Prioritätswarteschlangen, Heap, Graphen ADTs in Java Tag 17 – Sortieralgorithmen InsertionSort, BubbleSort, SelectionSort, ShellSort, MergeSort, QuickSort, Binary Tree Sort, HeapSort Untere Schranke für vergleichsbasierte Sortierverfahren, BucketSort, CountingSort, RadixSort Tag 18 – Suchalgorithmen Binärsuche, Breitensuche, Tiefensuche, Backtracking Klausurvorbereitung Tag 19 – Klausur Tag 20 – Letzter Tag Weitere Projekte am Fachbereich, Klausurnachbesprechung, Grillen? Pro Informatik 2009: Objektorientierte Programmierung 3 Abstrakter Datentyp Ein Abstrakter Datentyp (ADT) ist eine Sammlung von Daten, verbunden mit der Definition aller zulässigen Operationen, die auf sie zugreifen. Der Zugriff ist nur über die festgelegten Operationen möglich, damit die Daten nach außen gekapselt sind (Geheimnisprinzip). Ein ADT beschreibt was die Operationen tun (Spezifikation), aber noch nicht wie sie es tun (Implementierung). In der Regel gibt es viele Implementierungen für ein ADT. Ein Objekt eines abstrakten Datentyps wird Abstraktes Datenobjekt (ADO) genannt. Pro Informatik 2009: Objektorientierte Programmierung 4 Spezifikation vs. Implementierung Spezifikation beantwortet die Fragen „WAS leistet das System?“ „WAS kann der Benutzer erwarten?“ Implementierung beantwortet die Fragen „WIE erbringt das System seine Leistung?“ „WIE ist das System konstruiert?“ Spezifikation Implementierung Abstraktes Modell Abstrakte Invariante Abstrakte oder konkrete Signatur Abstrakte Vorbedingungen Abstrakte Effekte Konkretes Modell Konkrete Invariante Konkrete Signatur Konkrete Vorbedingungen Konkrete Effekte Pro Informatik 2009: Objektorientierte Programmierung 5 ADT Folge Typische Spezifikation eines ADT „Folge“: Modell: [T] mit Basistyp T Invariante: eventuell Längenbeschränkung Operationen: unterschiedlich - entsprechend unterscheidet man Stack Queue Liste size, length, count size, length, count size, length, count isEmpty isEmpty isEmpty push offer, enqueue, append append*, insert*, add* peek, top head, front, peek get* pop poll, dequeue remove* remove remove* iterate iterate iterate Stack<T> Queue<T> List<T>, LinkedList<T>, ArrayList<T>, Vector<T> * evtl. mit Positionsangabe Pro Informatik 2009: Objektorientierte Programmierung 6 Implementierung: Stack Ein Stack (Stapel oder Keller) verwaltet eine geordnete Menge von Objekten, wobei ein Element angefügt oder das letzte hinzugefügte wieder weggenommen werden kann. Ein Stack arbeitet also nach dem LIFO-Prinzip (last in first out) Wichtige Methoden eines Stacks: push(Objekt) Objekt pop() Objekt peek() boolean isEmpty() int size() Iterator<Objekt> iterator() fügt Objekt als oberstes Element dem Stack hinzu gibt das oberste Element des Stacks zurück und entfernt es gibt das oberste Element des Stacks zurück und entfernt es nicht prüft, ob der Stack leer ist liefert die Anzahl der im Stack vorhandenen Elemente zurück liefert ein Iterator-Objekt zurück In Java erbt Stack von Vector Pro Informatik 2009: Objektorientierte Programmierung 7 Stack Ein Stack, welches in der konkreten Implementierung über ein Array realisiert wird. import java.util.Iterator; public class Stack { private int currentIndex; private Object[] array; public Stack(int initSize){ currentIndex = -1; array= new Object[initSize]; } public void push(Object a) throws OverflowException { if (currentIndex >= array.length-1) throw new OverflowException("Stack is full"); else { array[++currentIndex] = a; } } public Object pop() throws UnderflowException { if (currentIndex < 0) throw new UnderflowException("Stack is empty"); else { return array[currentIndex--]; } } ... Pro Informatik 2009: Objektorientierte Programmierung 8 Stack ... public Object peek() throws UnderflowException { if (currentIndex < 0) throw new UnderflowException("Stack is empty"); else { return array[currentIndex]; } } public int size() { return currentIndex + 1; } public Iterator<Object> iterator() { return new Iterator<Object>() { int iteratorIndex = currentIndex; public boolean hasNext() { if(iteratorIndex >= 0) return true; return false; } public Object next() { return array[iteratorIndex--]; } public void remove() { //should not be used } }; } ... Pro Informatik 2009: Objektorientierte Programmierung 9 Stack ... public static void main(String[] args) { Stack s = new Stack(4); try { s.push(3); s.push(4); s.push(5); s.push(6); Iterator<Object> iter = s.iterator(); while(iter.hasNext()) System.out.println(iter.next()); //6 5 4 3 System.out.println(s.peek()); //6 System.out.println(s.pop()); System.out.println(s.pop()); System.out.println(s.pop()); System.out.println(s.pop()); } catch (Exception e) { e.printStackTrace(); } //6 //5 //4 //3 } class OverflowException extends Exception { public OverflowException(String msg) { super(msg); } } class UnderflowException extends Exception { public UnderflowException(String msg) { super(msg); } } } Pro Informatik 2009: Objektorientierte Programmierung 10 Stack Laufzeitanalyse für die Operationen push pop peek isEmpty size Pro Informatik 2009: Objektorientierte Programmierung O(1) O(1) O(1) O(1) , wenn Zähler vorhanden O(1) , wenn Zähler vorhanden 11 Stack Wofür kann ein Stack gebraucht werden? • Abarbeiten von rekursiven Aufrufen • Speicherverwaltung (und Verwaltung anderer Ressourcen) • Auswertung von Ausdrücken (Postfix, Infix) • Verarbeitung von Klammerstrukturen • Compiler • Traversieren komplexerer Datenstrukturen • uvm. Pro Informatik 2009: Objektorientierte Programmierung 12 Implementierung: Queue Eine Queue (Schlange, Warteschlange) verwaltet eine geordnete Menge von Objekten, wobei ein Element angefügt oder das am längsten vorhande Objekt wieder weggenommen werden kann. Wie bei einer Warteschlange, muss gewartet werden, bis man an der Reihe ist. Ein Stack arbeitet also nach dem FIFO-Prinzip (first in first out) Wichtige Methoden einer Queue: offer(Objekt) Objekt poll() Objekt peek() boolean isEmpty() int size() Iterator<Objekt> iterator() fügt Objekt hinten an die Queue, falls möglich liefert das vordere Element der Queue und entfernt es gibt das vorderste Element der Queue zurück und entfernt es nicht prüft, ob die Queue leer ist liefert die Anzahl der in der Queue vorhandenen Elemente zurück liefert ein Iterator-Objekt zurück In Java ist Queue ein Interface von der es mehrere Implementierungen gibt. Pro Informatik 2009: Objektorientierte Programmierung 13 Queue Es gibt unterschiedliche Repräsentationen für eine Queue: 1. Feld, zyklisch benutzt (Längenbeschränkung) 2. Lineares Geflecht, einfach verkettet tail head head tail head 3. Zyklisches Geflecht, einfach verkettet 4. Lineares Geflecht, doppelt verkettet tail head head 5. Zyklisches Geflecht, doppelt verkettet Pro Informatik 2009: Objektorientierte Programmierung 14 Queue Eine Queue repräsentiert durch ein zyklisch benutztes Feld. import java.util.Iterator; public class QueueArray { private Object[] array; private int head, count; public QueueArray(int initSize){ head = 0; count= 0; array= new Object[initSize]; } public void offer(Object o) { if(count == array.length) return; array[(head+count++)%array.length] = o; } //Null-Operation when full public Object poll() { if(count == 0) return null; Object o = array[head]; head = (head+1)%array.length; count--; return o; } //return null when empty ... Pro Informatik 2009: Objektorientierte Programmierung 15 Queue ... public Object peek() { if(count == 0) return null; return array[head]; } public int size() { return count; } public Iterator<Object> iterator() { return new Iterator<Object>() { int iteratorIndex = head; public boolean hasNext() { if(iteratorIndex < count) return true; return false; } public Object next() { return array[(head+iteratorIndex++)%array.length]; } public void remove() { //not implemented } }; } ... Pro Informatik 2009: Objektorientierte Programmierung 16 Queue ... public static void main(String[] args) { QueueArray q = new QueueArray(3); q.offer(3); q.offer(4); q.offer(5); q.offer(6); Iterator<Object> iter = q.iterator(); while(iter.hasNext()) { System.out.println(iter.next()); } //3 4 5 System.out.println(q.peek()); //3 System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); //3 //4 //5 //null } } Pro Informatik 2009: Objektorientierte Programmierung 17 Queue Laufzeitanalyse für die Operationen offer poll peek isEmpty size Pro Informatik 2009: Objektorientierte Programmierung O(1) O(1) O(1) O(1) , wenn Zähler vorhanden O(1) , wenn Zähler vorhanden 18 Queue Wofür kann eine Queue gebraucht werden? • Ressourcenverwaltung (z.B. bei Betriebssystemen) • Datenpuffer • Baum- und Graph-Traversierung • Verwaltung „realer“ Warteschlangen • Simulation zeitdiskreter Systeme • Repräsentation „höherer“ ADT (Mengen, Relationen, ...) • uvm. Pro Informatik 2009: Objektorientierte Programmierung 19 Implementierung: Liste Eine imperative Liste (List, Geflecht) ist eine beliebig manipulierbare Folge mit Positionen 0,1,2, ... head Wichtige Methoden einer Liste: add(Objekt o, int index) add(Objekt o) Object remove(int index) Object get(int index) boolean isEmpty() int size() Iterator<Objekt> iterator() fügt Objekt o an Stelle index ein fügt Objekt o am Ende ein liefert das Objekt an Position index und entfernt es liefert das Objekt an Position index und entfernt es nicht prüft, ob die Liste leer ist liefert die Anzahl der in der Liste vorhandenen Elemente liefert ein Iterator-Objekt zurück In Java ist List ein Interface von der es mehrere Implementierungen gibt. Pro Informatik 2009: Objektorientierte Programmierung 20 Liste Es gibt unterschiedliche Repräsentationen für eine Liste: 1. wechselnde Felder variabler Länge 2. zyklisches Geflecht, doppelt verkettet, mit innerer Klasse Pro Informatik 2009: Objektorientierte Programmierung ArrayList<T>, Vector<T> LinkedList<T> 21 Liste Repräsentation einer doppelt verkettete Liste. import java.util.Iterator; public class DoubleLinkedList<T> { protected class Node { T value; Node prev; Node next; public Node(T v) { value = v; } } private Node head = new Node(null); private Node tail = new Node(null); private int count = 0; public DoubleLinkedList() { head.prev = null; head.next = tail; tail.prev = head; tail.next = null; } ... Pro Informatik 2009: Objektorientierte Programmierung 22 Liste ... public void add(T value, int index) throws IndexOutOfBoundsException { Node cursor = get(index); Node newItem = new Node(value); newItem.prev = cursor; newItem.next = cursor.next; cursor.next.prev = newItem; cursor.next = newItem; count++; } public void add(T value) { add(value, count); } public T remove(int index) throws IndexOutOfBoundsException { //Übungsaufgabe } ... Pro Informatik 2009: Objektorientierte Programmierung 23 Liste ... public Node get(int index) throws IndexOutOfBoundsException { if (index < 0 || index > count) { throw new IndexOutOfBoundsException(); } else { Node cursor = head; for (int i = 0; i < index; i++) { cursor = cursor.next; } return cursor; } } public boolean isEmpty() { return count == 0; } public int size() { return count; } ... Pro Informatik 2009: Objektorientierte Programmierung 24 Liste ... public Iterator<Node> iterator() { return new Iterator<Node>() { Node cursor = head; public boolean hasNext() { return cursor.next != null; } public Node next() { cursor = cursor.next; return cursor; } public void remove() { //not implemented } }; } ... Pro Informatik 2009: Objektorientierte Programmierung 25 Liste ... public String toString() { StringBuffer result = new StringBuffer(); result.append("(head) - "); Node temp = head; while (temp.next != tail) { temp = temp.next; result.append(temp.value + " - "); } result.append("(tail)"); return result.toString(); } public static void main(String argv[]) { DoubleLinkedList<Integer> list = new DoubleLinkedList<Integer>(); list.add(3); list.add(4); list.add(5); list.add(6); list.add(7, 2); System.out.println(list); list.remove(list.size()); list.remove(1); System.out.println(list); } } Pro Informatik 2009: Objektorientierte Programmierung 26 Liste Laufzeitanalyse für die Operationen (bei Verwendung eines Arrays) add(Object o, int index) remove(int index) remove(Object o) get(int index) isEmpty size merge O(n) O(n) O(n) O(1) O(1) , wenn Zähler vorhanden O(1) , wenn Zähler vorhanden O(n) Laufzeitanalyse für die Operationen (bei Verwendung eines Geflechts) add(Object o, int index) remove(int index) remove(Object o) get (int index) isEmpty size merge Pro Informatik 2009: Objektorientierte Programmierung O(n) O(n) O(n) bei einfach verkettetem Geflecht O(1) bei doppelt verkettetem Geflecht O(n) O(1) , wenn Zähler vorhanden O(1) , wenn Zähler vorhanden O(1) 27 PAUSE Pro Informatik 2009: Objektorientierte Programmierung 28 ADT Menge Typische Spezifikation eines ADT „Menge“: Modell: {T} mit Basistyp T Invariante: eventuell Längenbeschränkung Operationen: unterschiedlich - entsprechend unterscheidet man elementOf isEmpty size add, remove union, intersection, difference, subset iterate In Java gibt es unter der Schnittstelle java.util.Set eine Vielzahl von verschiedenen Implementierungen. Pro Informatik 2009: Objektorientierte Programmierung 29 Bäume Ein freier Baum ist in der Informatik definiert als kreisfreier zusammenhängender Graph. G = (E,V), mit E Menge aller Kanten (edges) und V Menge aller Knoten (vertices) Ein (Wurzel-)Baum ist ein freier Baum B mit einer ausgezeichneter Knoten als „Wurzel“ w Pro Informatik 2009: Objektorientierte Programmierung 30 Bäume Terminologie Wurzel Vater Blatt Kind Kind Teilbaum Unterbaum Pro Informatik 2009: Objektorientierte Programmierung 31 Bäume Terminologie 0 1 2 3 Grad (degree) eines Knotens = Anzahl der Kinder (= Anzahl der nichtleeren Teilbäume des zugehörigen Unterbaums) Ebene, Stufe (level) eines Knotens = Weglänge von der Wurzel Höhe (height) eines nichtleeren Baums = maximale Ebene vollständiger Baum: alle Ebenen sind vollständig besetzt, außer eventuell der untersten Pro Informatik 2009: Objektorientierte Programmierung 32 Bäume Terminologie balancierter Baum Ein balancierter Baum garantiert eine maximale Höhe von entarteter Baum Die Höhe nähert sich n Pro Informatik 2009: Objektorientierte Programmierung 33 Binärbäume Ein Binärbaum ist ein gewurzelten Baum, bei dem jeder Knoten höchstens zwei Kindknoten besitzt. Ein Binärbaum mit Höhe h hat folgende Eigenschaften: • maximal 2h+1-1 Knoten, • maximal 2h Blätter Bei einer vorgegebenen Knotenzahl n hat ein Binärbaum mindestens die Höhe Pro Informatik 2009: Objektorientierte Programmierung 34 Binärbäume Implementierung eines Binärbaums public class BinTree<T> { static class Node<T> { Node<T> left; T value; Node<T> right; Node(T v) { left = null; right = null; value = v; } Node(T v, Node<T> l, Node<T> r) { left = l; right = r; value = v; } } private Node<T> root; public BinTree() { root = null; } ... Pro Informatik 2009: Objektorientierte Programmierung 35 Binärbäume Implementierung eines Binärbaums ... public static void main(String[] args) { BinTree<Integer> b = new BinTree<Integer>(); b.root = new Node<Integer>(5); b.root.left = new Node<Integer>(2); b.root.right = new Node<Integer>(7, new Node<Integer>(6), new Node<Integer>(9)); } } 5 7 2 6 Pro Informatik 2009: Objektorientierte Programmierung 9 36 Traversierung Es gibt mehrere Möglichkeiten einen Baum zu traversieren (= „mit jedem Element wird etwas gemacht“) • Tiefendurchlauf • Alternativen: Preorder, Inorder, Postorder • Breitendurchlauf Siehe Vorlesung zu Suche Pro Informatik 2009: Objektorientierte Programmierung 37 Suchbäume Suchbäume sind Bäume zur Repräsentation einer linear geordneter Mengen. Wir beschränken uns hier auf binäre Suchbäume. Invariante eines binären Suchbaums: Die Wurzel ist größer als alle Elemente im linken Teilbaum und kleiner als alle Elemente im rechten Teilbaum, und die Teilbäume sind ebenfalls binäre Suchbäume. Die geordnetete Menge { 1, 3, 4, 5, 7, 9, 11 } kann folgendermaßen repräsentiert werden: 5 7 3 1 11 4 9 Es gibt in der Regel mehrere Darstellungen für eine Menge Pro Informatik 2009: Objektorientierte Programmierung 38 Suchbäume In einem Suchbaum kann effizient nach einem Element gesucht werden und somit überprüft werden ob ein Element sich in der Menge befindet oder nicht. Algorithmus um nach Element x zu suchen: In jedem Teilbaum von der Wurzel nach unten, wobei an jedem Scheideweg die Entscheidung aufgrund der Suchbaum-Invariante getroffen wird. Wird x gefunden, gebe true zurück. Enden wir an einem Blatt und haben x nicht gefunden, gebe false zurück. (wenn Suchelement größer als Wurzel, gehe nach rechts, sonst links) 5 7 3 1 11 4 9 Die Laufzeit beträgt O(h) = O(log n). Wobei h die Höhe des Suchbaums ist und n die Anzahl von Knoten im Suchbaum. Pro Informatik 2009: Objektorientierte Programmierung 39 Suchbäume Um ein neues Element in einen Suchbaum einzufügen, verfahren wir ähnlich: Algorithmus um Element x einzufügen: Suche nach Element x mit dem Suchalgorithmus. Wenn x bereits vorhanden, tue nichts. Ansonsten endet die Suche bei einem Blattknoten. Füge x an diesen Blattknoten gemäß Suchbaum-Invariante. 5 7 3 1 4 6 11 9 Die Laufzeit entspricht der Laufzeit vom Suchen, also ebenfalls O(h) = O(log n). Pro Informatik 2009: Objektorientierte Programmierung 40 Suchbäume Um ein Element zu entfernen, müssen verschiedene Situationen betrachtet werden. Algorithmus um Element x zu entfernen: Wenn x ein Blatt ist, entferne das Blatt einfach. 3 3 1 Wenn x nur einen Nachfolger hat, setze den Nachfolger an die Position von x 3 1 1 Pro Informatik 2009: Objektorientierte Programmierung 41 Suchbäume Algorithmus um Element x zu entfernen: Wenn x zwei Nachfolger hat gibt es zwei Möglichkeiten: Setze den linken Teilbaum an die Position von x und den rechten Teilbaum rechts an den linken gemäß Suchbaum-Invariante. (oder analog spiegelbildlich) 2 9 4 2 12 8 4 6 8 5 12 7 6 5 7 Pro Informatik 2009: Objektorientierte Programmierung drohende Unausgeglichenheit (Entartung) 42 Suchbäume Algorithmus um Element x zu entfernen (besser): Ersetze x durch seinen symmetrischen Vorgänger (größter Wert im linken Teilbaum). (entsprechend auch symmetrischer Nachfolger möglich) 9 8 2 12 2 4 12 4 8 6 5 6 7 Pro Informatik 2009: Objektorientierte Programmierung Höhe bleibt erhalten, Entartung immer noch möglich 5 7 43 Balancierte Bäume Die Entartung von Bäumen stellt ein großes Problem für die Performance der Operationen dar. Es gibt eine Klasse von balancierten Bäumen, die nach jeder Operation den Baum an der Stelle der Änderung neu balancieren. • AVL-Bäume • Rot-Schwarz-Bäume • 2-3-4-Bäume • B-Bäume • B+-Bäume • B*-Bäume • Treap • AA-Bäume • Splay-Bäume Pro Informatik 2009: Objektorientierte Programmierung 44 AVL-Bäume Ein Suchbaum heißt k-ausgeglichen, wenn für jeden Knoten die Höhen seiner beiden Teilbäume um höchstens k voneinander abweichen. Ein AVL-Baum ist ein 1-ausgeglichener Suchbaum (Adelson-Velsky und Landis, 1962). Invariante eines AVL-Baums: Invariante eines binären Suchbaums + für jeden Knoten k gilt: die Höhen h1 und h2 der beiden Teilbäume unterscheiden sich um höchstens 1 Suchen, Einfügen und Löschen in einem AVL-Baum: Genauso wie beim binären Suchbaum + gegebenenfalls ausgleichen („rebalancing“) durch Rotationen. Pro Informatik 2009: Objektorientierte Programmierung 45 AVL-Bäume Einfache Rotation: x 0 -2 y A <x B >x <y -1 C >y y 0 x A <x B >x <y C >y Geht jedoch schief, wenn an Teilbaum B erweitert wird! Pro Informatik 2009: Objektorientierte Programmierung 46 AVL-Bäume Doppelte Rotation: -2 -2 x 0 x +1 z -1 0 0 x y 0 z 0 y A <x B1 >x <y,z y B2 <z >x,y z C >z Pro Informatik 2009: Objektorientierte Programmierung A <x B1 >x <y,z B2 <z >x,y C >z A <x B1 >x <y,z B2 <z >x,y C >z 47 Prioritätswarteschlange Wir kennen bereits die einfachen Warteschlangen (Queue). Eine Prioritätswarteschlange (Priority Queue) erweitert die bisherigen Warteschlangen, indem jedes Element ein Schlüssel (eine Priorität) mitgegeben wird, der die Reihenfolge der Abarbeitung der Elemente bestimmt. Wichtige Methoden einer Priority Queue: insert(Objekt, Schlüssel) insert(Objekt) Objekt extractMin() fügt Objekt in die Priority Queue an die Stelle gemäß Schlüssel fügt Objekt in die Priority Queue, (Schlüssel implizit im Objekt) liefert das Element mit dem kleinsten Schlüssel bzw. der höchsten Priorität und entfernt es aus der Priority Queue Objekt peek() liefert das Element mit dem kleinsten Schlüssel bzw. der höchsten Priorität, entfernt es aber nicht remove(Objekt) entfernt Objekt aus der Priority Queue decreaseKey(Objekt, Schlüssel) verringert den Schlüssel bzw. erhöht die Priorität vom Objekt in der Priority Queue In Java basiert der Schlüssel auf der Implementierung der Schnittstelle Comparable oder Comparator Siehe java.util.PriorityQueue Pro Informatik 2009: Objektorientierte Programmierung 48 Prioritätswarteschlange Typische Repräsentationen für Prioritätswarteschlangen: 1. 2. Als Array oder Liste (nicht sortiert) insert(Objekt, Schlüssel) Objekt extractMin() remove(Objekt) decreaseKey(Objekt, Schlüssel) O(1) O(n) O(1) bei doppelt verkettetem Geflecht, sonst O(n) O(1) Als Array oder Liste (sortiert) insert(Objekt, Schlüssel) Objekt extractMin() remove(Objekt) decreaseKey(Objekt, Schlüssel) O(n) O(1) O(1) bei doppelt verkettetem Geflecht, sonst O(n) O(n) 3. Als Array von Warteschlangen für begrenzte Anzahl von Schlüsseln alles O(1) 4. Als Heap alles O(log n) Pro Informatik 2009: Objektorientierte Programmierung 49 Heap Ein Heap (Haufen, Halde) ist ein Baum, wo die Elemente mit Schlüsseln versehen sind. Häufig werden auch die Elemente selbst als Schlüssel verwendet. Invariante eines Min-Heaps: Der Heap ist (links-)vollständig und partiell geordnet (Jeder Knotenwert ist kleiner oder gleich der Knotenwerte seiner Kinder). Invariante eines Max-Heaps: Der Heap ist (links-)vollständig und partiell geordnet (Jeder Knotenwert ist größer oder gleich der Knotenwerte seiner Kinder). Wir beschränken uns auf Binärheaps (jeder Knoten hat höchstens zwei Kindknoten), aber es gibt noch andere Sorten von Heaps: • Binomial-Heap • Fibonacci-Heap • Treap • Radix-Heap Pro Informatik 2009: Objektorientierte Programmierung 50 Binärheap Ein Binärheap ist ein Heap, wo jeder Knoten höchstens zwei Kindknoten besitzt. Er ist (links-)vollständig und partiell geordnet. Beispiel: 2 9 7 13 20 7 15 11 18 8 Ein Binärheap unterstützt sehr effizient die üblichen Operationen einer Prioritätswarteschlange: insert, extractMin, decreaseKey, remove Pro Informatik 2009: Objektorientierte Programmierung 51 Binärheap Algorithmus um Element x einzufügen: insert Element x hinten anhängen, dann solange mit dem jeweils nächsten Vorgänger vertauschen, solang x kleiner ist (heapify). 2 2 9 7 13 20 7 15 8 11 6 9 6 18 13 20 7 15 8 11 18 7 Laufzeit: O(h) = O(log n) Pro Informatik 2009: Objektorientierte Programmierung 52 Binärheap Algorithmus um Element x zu entfernen: remove Vertausche x mit dem letzten Element y im Heap und entferne x. Dann wird y solange mit dem jeweils kleineren der beiden Nachfolger-Werte vertauscht, solang es noch größer als einer der beiden ist (heapify). 2 7 9 7 13 20 7 15 11 8 9 7 18 13 20 8 15 11 18 2 Analog dazu das Minimum aus der Menge zu entfernen: Entferne die Wurzel extractMin Analog auch das Ändern eines Schlüssels: Vertauschen bis Invariante wieder hergestellt decreaseKey Laufzeiten: alle O(h) = O(log n) Pro Informatik 2009: Objektorientierte Programmierung 53 Binärheap Ein Binärheap kann als Baumstruktur repräsentiert werden oder auch effizient als Array mit Breitensuch-Anordnung (Wurzel hat Index 1). 1 2 4 8 3 7 5 13 9 20 2 15 10 6 7 9 11 i= 2n + j , 8 k1 = 2i , 2 7 9 13 7 11 18 20 15 8 1 2 3 4 5 6 7 8 9 18 n = Ebene k2 = 2i+1 10 index(x) = i ⇔ index(left(x)) = 2i ∧ index(right(x)) = 2i+1 Pro Informatik 2009: Objektorientierte Programmierung 7 54 Graph Ein Graph besteht aus einer Menge an Knoten V und einer Menge an Kanten E = V x V b b a a d c gerichteter Graph „d ist Nachfolger von a“ „a ist Vorgänger von d“ Pro Informatik 2009: Objektorientierte Programmierung d c ungerichteter Graph Relation E ist symmetrisch (a,d) є E ⇔ (d,a) є E „d ist Nachbar von a“ 55 Graph Ein Graph kann als Adjazenzliste oder Adjazenzmatrix gespeichert werden: Adjazenzliste a: b , c , d b: b , c c: a d: b a d Pro Informatik 2009: Objektorientierte Programmierung c Adjazenzmatrix a b c d a x x x b x x c x d 56 Graph Auf einen Graph werden oft Operationen ausgeführt: • um ein Knoten zu finden siehe Vorlesung: Suche • um einen Weg von einem Knoten zu einem anderen Knoten zu finden Ein Weg (path) ist eine Folge von Knoten e0 , e1 , e2 , . . . , en, n ≥ 0 Sehr viele Sachverhalten werden in der Informatik als Graphen repräsentiert. Daher finden man Sie in vielen Anwendungsgebieten wieder: • Verkehrsnetze, z.B. Navis • Kommunikationsnetze, z.B. Internet • Energienetze • Netzpläne • Spiele • uvm. Pro Informatik 2009: Objektorientierte Programmierung 57