11. Rekursive Datenstrukturen

Werbung
11. Rekursive Datenstrukturen
•
Lineare Listen
– Liste = leer | Element Liste
1. Die leere Liste ist eine Liste
2. Wird einer Liste ein Element angehängt, so erhalten wir
wiederum eine Liste
•
Rekursive Implementierung von Listen
– Die Klasse Node enthält „sich selbst“: Rekursion
– Die Liste wird (über node.next) so lange „reduziert“,
bis wir zur trivialen (leeren) Liste kommen
– Die Suche in einer Schleife wird durch den
rekursiven Abstieg ersetzt
László Böszörményi
ESOP
Rekursive Datenstrukturen - 1
Klasse Node und Interface List – unverändert
class Node {
// Klasse Node, represäntiert Knoten der Liste
Comparable info;
// info enthält die Funktion, wonach sortiert wird
Node
next;
// next zeigt auf den nächsten Knoten in der Liste
Node (Comparable info, Node next) { this.info = info; this.next = next;}
public String toString () { return "" + info; } // Retourniert info als String
} // Node
public interface List {
// 03.11.2000. LB
public Comparable search (Comparable key);
// Retourniert ein Element mit Schlüssel=key bzw. null, wenn nicht gefunden
public void insert (int key); // Fügt einen Knoten mit Schlüssel=key ein
public void remove (Comparable key);
// Entfernt Knoten mit Schlüssel=key, wenn vorhanden
public String toString ();
// Wandelt die Liste in eine Zeichenkette um
} // List
László Böszörményi
ESOP
Rekursive Datenstrukturen - 2
Benutzerklasse mit Zahlen
static void useList(List list) {
for (int i = 9; i > 0; i -= 2) list.insert( new CompInt(i) ) ;
Out.println(list);
for (int i = -2; i < 14; i+= 2) list.insert( new CompInt(i) ) ;
Out.println(list);
for (int i = -5; i < 16; i+= 4) {
CompInt k = (CompInt) list.search (new CompInt(i)); // Suche
if ( k != null ) { // gefunden
(13579)
list.remove ( k ) ;
( -2 0 1 2 3 4 5 6 7 8 9 10 12 )
Out.println(k + " entfernt ");
-5 nicht enthalten
} else
// nicht gefunden
-1 nicht enthalten
3 entfernt
Out.println(i + " nicht enthalten");
7 entfernt
} // for i
11 nicht enthalten
Out.println(list);
15 nicht enthalten
} // useList
( -2 0 1 2 4 5 6 8 9 10 12 )
Aufruf: useList (new RekList());
László Böszörményi
ESOP
Rekursive Datenstrukturen - 3
Rekursive Implementierung von Listen (1)
public class RekList implements List {
// Klasse List, für sortierte Liste
Node head = null;
// Kopf der Liste – auf null initialisiert
// durch den default-Konstruktor: RekList()
Node search (Comparable key, Node node) { // Suche key rekursiv ab node
if (node == null)
return null;
// Nicht gefunden
else if (key.compareTo (node.info) > 0) return search(key, node.next);
// Rekursiv weitersuchen solange key > aktueller Schlüssel
else if (key.compareTo (node.info) == 0) return node; // Gefunden
else return null;
// Nicht gefunden
} // search
public Comparable search (Comparable key) {
Node n = search(key, head);
// Führt die Suche durch
if (n == null) return null; else return n.info; // Retourniert das Ergebnis
} // search
László Böszörményi
ESOP
Rekursive Datenstrukturen - 4
Rekursive Implementierung von Listen (2)
String toString (Node node, String listString) { // Baut String rekursiv auf
if (node == null) return listString; // Vor dem Aufruf konkatenieren:
else return toString (node.next, listString + node + " ");
} // toString
// (sonst wäre der String umgekehrt)
public String toString () { return "( " + toString (head, "") + ")"; } // toString
Node insert(Comparable key, Node node) {// Fügt ab node ein, sucht rekursiv
if ( (node == null) || (key.compareTo(node.info) <= 0) )
return new Node(key, node); // Am Kopf der aktuellen Liste
else {
// Sonst: rekursiv weitersuchen
node.next = insert(key, node.next); return node;
} // if
} // insert
public void insert(Comparable key) {// Fügt Knoten mit Schlüssel=key ein
head = insert(key, head);
} // insert
László Böszörményi
ESOP
Rekursive Datenstrukturen - 5
Rekursive Implementierung von Listen (3)
Node remove (Comparable key, Node node) { // Sucht ab node rekursiv
if (node == null) return null;
// Nicht gefunden
else
if (key.compareTo (node.info) > 0) { // Rekursiv weitersuchen
node.next = remove (key, node.next); // Entfernen
return node;
// Kette muss aufrechterhalten werden
} // if
else if (key.compareTo (node.info) == 0) // Gefunden
return node.next;
// Zieladresse zurück
else
return node;
// Nicht gefunden
} // remove
public void remove (Comparable key) {
head = remove (key, head);
} // remove
} // RekList
László Böszörményi
ESOP
Rekursive Datenstrukturen - 6
Benutzerklasse mit Personen
static void useList(List list) {
String [] persons1 = {"Pete", "May", "Paul", "Bob"};
String [] persons2 = {"Sue", "Mic", "Xe", "Xa", "Ada", "Xu"};
for (int i = persons1.length - 1; i >= 0; i -- ) list.insert ( new Person (persons1[i])
);
Out.println(list);
for (int i = 0; i < persons2.length; i++ ) list.insert( new Person (persons2[i]) );
Out.println(list);
for (int i = 1; i < persons2.length; i+= 2 ) {
Person p = new Person (persons2[i]); String s;
if ( list.search(p) != null ) { list.remove (p); s = " entfernt";
} else s = " nicht gefunden";
( Bob May Paul Pete )
Out.println(p + s);
( Ada Bob May Mic Paul Pete Sue Xa Xe Xu )
Mic entfernt
} // for i
Xa entfernt
Out.println(list);
Xu entfernt
} // useList
( Ada Bob May Paul Pete Sue Xe )
László Böszörményi
ESOP
Rekursive Datenstrukturen - 7
Lineares Suchen in einem Array
•
Wir müssen das Array durchsuchen, solange wir entweder
–
–
•
Das gesuchte Element gefunden haben oder
Das Ende des Arrays erreicht haben
Implementierung (iterativ bzw. rekursiv)
–
Suchfunktion retourniert den Index des gefundenen Elementen bzw. -1
static int LinearSearch (int [] arr, int key) { // Iteratives lineares Suchen
int i = 0;
while ( (i < arr.length) && (arr[i] != key) ) i++;
if (i == arr.length) return -1;
// nicht gefunden: gibt -1 zurück
else return i;
// gefunden an Stelle i
} // LinearSearch
static int RekSearch (int [] arr, int key, int start) {// Rekursives lineares Suchen
if (start == arr.length) return -1;
// nicht gefunden : -1 zurück
else if (arr[start] == key) return start;
// gefunden an Stelle start
else return RekSearch(arr, key, start + 1); // weitersuchen ab start+1
} // RekSearch
László Böszörményi
ESOP
Rekursive Datenstrukturen - 8
Bäume („Schnupperkurs“ – Rest in SW2)
•
•
Ein Baum ist ein gerichteter Graph, in dem jeder Knoten
außer der Wurzel genau einen Vorgänger („Vater“) hat
Eine Baumstruktur mit Grundtyp T ist entweder
1. Die leere Struktur oder
2. Ein Knoten vom Typ T mit einer endlichen Anzahl verknüpfter
Baumstrukturen mit Grundtyp T (die sog. Teilbäume)
Wurzel
Höhe = 3
•
•
•
Bäume sind immer azyklisch
Pfadlänge: Die Anzahl der Kanten zwischen zwei Knoten
Höhe: Maximale Pfadlänge aus der Wurzel heraus
–
–
Höhe des leeren Baumes = 0
Höhe eines Baumes der nur aus Wurzel besteht = 1
László Böszörményi
ESOP
Rekursive Datenstrukturen - 9
Binärbäume
•
•
•
In einem Binärbaum hat jeder Knoten höchstens 2
Nachfolger („Kinder“)
Binärbaum = leer | Knoten Binärbaum Binärbaum
Ein Binärbaum ist entweder leer oder besteht aus einem
Knoten (Wurzelknoten) und 2 Teilbäume
Wurzel
Linker „Sohn“
László Böszörményi
Rechter „Sohn“
ESOP
Höhe = 5
Rekursive Datenstrukturen - 10
Binäre Suchbäume
•
In einem binären Suchbaum (geordneten Binärbaum) gilt für
jeden Knoten, dass
–
–
Alle Schlüsselwerte im linken Teilbaum kleiner
Alle Schlüsselwerte im rechten Teilbaum größer oder gleich
sind, wie der Schlüsselwert im Knoten selbst
(Ob wir gleiche Knoten rechts oder links einordnen ist Definitionssache)
50
20
10
5
70
35
10
László Böszörményi
60
40
90
85
ESOP
95
Rekursive Datenstrukturen - 11
Impliziter Suchbaum – Binäres Suchen
•
Wir suchen in einem geordneten Array
–
–
–
Wir schauen rekursiv, ob ein Element in der linken oder rechten
Hälfte des Arrays enthalten ist
Ist die Größe des Arrays n, kostet das höchstens log2N Schritte
(N ist die kleinste Zweierpotenz > n)
Es wird implizit ein Suchbaum, der Höhe log2N aufgebaut
30, 71, 92, 233, 284, 315, 326, 357, 478, 559, 6110, 7211
Suche von 28
315
92
30
478
233
71
László Böszörményi
6110
326
284
357
ESOP
Höhe = 4
(log216)
559
7211
Rekursive Datenstrukturen - 12
Implementierung vom Binären Suchen
static int BinSearch (int [] arr, int left, int right, int key) {
/* Gibt den Index des gefundenen Elementen bzw. -1 (falls nicht gefunden) zurück */
int middle = left + (right - left) / 2;
// Wurzel des nächsten Teilbaums
Out.println("arr[" + middle + "] = " + arr[middle]);
// Testausgabe
if (key == arr[middle]) return middle; // key == arr[middle]: gefunden
else if (key < arr[middle])
// key < arr[middle]: suche links
if (left < middle) return BinSearch(arr, left, middle - 1, key); arr[5] = 31
31 gefunden
else return -1;
// nicht gefunden
(in 1 Schritt)
else
// key >= arr[middle]: suche rechts
if (middle < right) return BinSearch(arr, middle + 1, right, key);
else return -1;
// nicht gefunden
arr[5] = 31
arr[5] = 31
} // BinSearch
int [] q = {3, 7, 9, 23, 28, 31, 32, 35, 47, 55, 61, 72};
int x = BinSearch (q, 0, q.length - 1, 28);
László Böszörményi
ESOP
arr[2] = 9
arr[3] = 23
arr[4] = 28
28 gefunden
arr[8] = 47
arr[10] = 61
arr[11] = 72
99 nicht gefunden
Rekursive Datenstrukturen - 13
Herunterladen