Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Algorithmen und Datenstrukturen Übungsmodul 8

Ähnliche Präsentationen


Präsentation zum Thema: "Algorithmen und Datenstrukturen Übungsmodul 8"—  Präsentation transkript:

1 Algorithmen und Datenstrukturen Übungsmodul 8
Dr. W. Narzt u. Dr. A. Stritzinger Institut für Wirtschaftsinformatik- Software Engineering JKU Linz

2 Bäume - Definitionen Definition: nach Wirth [86, S. 200f]
Eine Baumstruktur vom Grundtyp T ist entweder ·   die leere Struktur oder ·   ein Knoten vom Typ T mit einer endlichen Zahl verknüpfter, voneinander verschiedener Baumstrukturen vom Grundtyp T, sogenannte Teilbäume (subtrees). Definition n. Sedgewick p. 230 ff Ein Baum ist ein Knoten (Wurzel), der mit einer Folge von disjunkten Bäumen verbunden ist. Eine derartige Folge nennt man Wald (forest). Ein Baum besteht aus Knoten (nodes), die durch Kanten (edges) verbunden sind. In den Knoten sind Nutzdaten (Elemente) gespeichert.

3 Rekursion - Konzept Rekursion im Allgemeinen bedeutet, dass sich etwas als Teil enthält oder mithilfe von sich selbst definiert ist. Veranschaulichung: Mathematische Definition der Fakultätsfunktion: fak(n) = n* fak(n-1); fak(0) = 1. Rekursive Algorithmen: Wenn eine Funktion, Prozedur oder Methode einen Aufruf von sich selbst enthält (= direkte Rekursion). Wenn eine Methode eine andere aufruft und diese wiederum die erste direkt oder indirekt ruft (= indirekte Rekursion)

4 Rekursionsbedingungen
Ein rekursiver Aufruf darf nicht die gleichen Parameterwerte erhalten, wie die aktuelle Ausführung, da dies zu einer endlos Rekursion führen würde. Statt dessen muss bei jedem rekursiven Aufruf, die durch die Parameter definierte Aufgabe etwas "kleiner" sein. Jeder rekursive Algorithmus muss eine Fallunterscheidung enthalten mit mindestens einem nicht rekursiven Zweig, der bei der Terminierung ausgeführt wird (kann u.U. leer sein). Bei jedem rekursiven Aufruf muss ein neuer Datensatz für alle lokalen Variablen und Parameter angelegt werden, der während der Algorithmusausführung, den darunterliegenden Datensatz verbirgt. Stack-verwaltete (Aktivierungs-) Datensätze sind in fast allen modernen Programmiersprachen üblich. Für praktische Anwendungen muss die Tiefe der Rekursion relativ klein sein.

5 Beispiel: Fakultät berechnen
int factorial(int n) { if (n > 1) return factorial(n - 1) * n; } else return 1; trace: factorial(5), factorial(4), factorial(3), factorial(2), factorial(1) return 1 return 1*2 return 2*3 return 6*4 return 24*5 ergebnis: 120

6 Rekursion vs. Iteration
Die Falkultätsfunktion kann natürlich einfacher und effizienter iterativ berechnet werden int factorial(int n) { int result = 1; for (int i=2; i<=n; i++) result = result * i; } return result; Grundsätzlich gilt: Jeder rekursive Algorithmus kann auch iterativ (d.h. mittels Wiederholungs-aktionen) gelöst werden und umgekehrt kann jede iterative Lösung in eine rekursive überführt werden. Rekursive Algorithmen eigenen sich besonders dann, wenn das zugrundeliegende Problem rekursiv definiert ist, oder wenn die Datenstrukturen rekursiv sind.

7 Beispiel: Fibonacci-Funktion
Leonardo Fibonacci (ital. Mathematiker, 12 Jhdt. Pisa) fand eine Reihe, welche angeblich die Populationsentwicklung von Kaninchen präzise beschreibt. Dabei hängt die Zahl der Kaninchen einer Generation n von der Summe der Zahl der Eltern-Generation (n-1) und der Zahl der Großeltern-Generation (n-2) ab. Fibonacci-Reihe: rekursive Fassung: Anzahl der Aufrufe wächst exponentiell, daher ziemlich unbrauchbar! besser: iterative Fassung: int fib(int n) { if (n==0) return 0; if (n==1) return 1; return fib(n-1) + fib(n-2); } int fib(int n) { int i = 1, x = 1, y = 0, z = 0; while (i<n) z = x; x = x + y; y = z; i++; } return x;

8 Bäume - Begriffe Der Knoten an der Spitze heißt Wurzel des Baumes.
Ein Pfad ist eine Liste von zusammenhängenden Kanten. Ausgehend von der Wurzel kann jeder Knoten über genau einen Pfad aus Kanten erreicht werden. Jeder Knoten, außer der Wurzel hat genau einen Vorgänger. Dieser wird auch als Elternknoten, Vater, Mutter (parent) bezeichnet. Die Nachfolgerknoten, die mit einem Vorgänger durch eine Kante verbunden sind bezeichnet man auch als Kindknoten, Sohn oder Tochter (children). Knoten ohne Nachfolger, werden als Bätter (leaves), Knoten mit Nachfolgern als innere Knoten bezeichnet. Die Ebene (Stufe, level) eines Knotens ist um 1 größer als die Ebene des Vorgängers (Wurzel hat Ebene = 0). Die Höhe eines Baumes ist das Maximum der Ebenen aller Knoten. Der Grad eines Baumes gibt die maximal mögliche Anzahl der direkten Nachfolgerknoten eines Knotens an. (Binärbaum: Grad = 2)

9 Binärbaum und Binärer Suchbaum
Ein Binärbaum ist ein Baum, dessen Grad 2 beträgt. Ein Binärbaum mit N inneren Knoten hat maximal N+1 Blätter. Ein Binärbaum mit N inneren Knoten hat maximal 2*N Kanten: N-1 zu inneren Knoten N+1 zu Blättern. Binärer Suchbaum (Definition n. Sedgewick p. 531) Ein binärer Suchbaum (binary search tree, BST) ist ein Binärbaum, der mit jedem inneren Knoten ein Schlüsselattribut assoziiert und die Eigenschaft hat, dass für jeden Knoten K gilt: die Schlüsselwerte aller Knoten des linken Unterbaums sind kleiner und die Schlüsselwerte des rechten Unterbaums sind größer oder gleich dem Schlüsselwert des Knotens K.

10 Binärer Suchbaum in Jana
type Tree = { reftype Item = String key int value } reftype Node = Item item Node left Node right Node root init() {root = null} ... // Algorithmen Verwendung: Tree t t.init() t.insert(item) Item i = t.search(key)

11 Binärer Suchbaum: Einfügen und Suchen (rekursiv)
Node insertRec(Node h, Item x) { if (h == null) return new Node(x) if (x^.key < h^.item^.key) h^.left = insertRec(h^.left, x) else h^.right = insertRec(h^.right, x) return h } void insert(Item x) { root = insertRec(root,x) } Item search(String key) { return searchRec(root,key) } Item searchRec(Node h, String key) { if (h == null) return null if (key == h^.item^.key) return h^.item if (key < h^.item^.key) return searchRec(h^.left, key) else return searchRec(h^.right, key) }

12 Binärer Suchbaum: Einfügen (iterativ)
void insertIter(Item x) { if (root == null) root = new Node(x) else { Node parent, current = root while (true) { parent = current if (x^.key < current^.item^.key) { current = current^.left if (current == null) { parent^.left = new Node(x) return; } } else { current = current^.right parent^.right = new Node(x) } // while } // else

13 Binärer Suchbaum: Suchen (iterativ)
Item searchIter(String key) { Node current = root while (current != null) if (current^.item^.key == key) return current^.item if (key < current.item.key) current = current^.left else current = current^.right } return null // not found

14 Binärbaum: In-/Pre-/Postorder Traversierung (rekursiv)
void inorder() { traverseInorderRec(root) } void traverseInorderRec(Node h) if (h == null) return traverseInorderRec(h^.left) h^.item^.visit() traverseInorderRec(h^.right) void traversePreorderRec(Node h) { if (h == null) return h^.item^.visit() traversePreOrderRec(h^.left) traversePreOrderRec(h^.right) } void traversePostorderRec(Node h) { if (h == null) return traversePostOrderRec(h^.left) traversePostOrderRec(h^.right) h^.item^.visit() }

15 Binärbaum: Preorder Traversierung (iterativ)
void traverse() { traverseIter(root); } void traverseIter(Node h) NodeStack s = new NodeStack s.push(h) while (!s.isEmpty()) h = s.pop() h^.item^.visit() if (h^.right != null) s.push(h^.right) if (h^.left != null) s.push(h^.left) //zu beachten: zuerst wird rechter Teilbaum gekellert!

16 Binärbaum: Levelorder Traversierung (iterativ)
void traverse() { traverseLevels(root) } void traverseLevels(Node h) NodeQueue q = new NodeQueue q.enqueue(h) while (!q.isEmpty()) h = q.dequeue() h^.item.^visit() if (h^.left != null) q.enqueue(h^.left) if (h^.right != null) q.enqueue(h^.right)


Herunterladen ppt "Algorithmen und Datenstrukturen Übungsmodul 8"

Ähnliche Präsentationen


Google-Anzeigen