Verschränkte Rekursion

Werbung
Verschränkte Rekursion
Typdefinition umfasst mehrere neue Typen und in den Typausdrücken können alle Typen
auftreten.
type `b wald = LeerW | Wald of `b * `b wald
and à baum = LeerB| Baum
of ‘a * (‘a baum) wald;;
Der erste Teil dieser Typdefinition hat hierbei die Struktur einer Liste, der zweite führt zur
Verschränkung durch Rückgriff auf „wald“.
Durch verschränkt rekursive Sortendeklaration werden auch die darauf arbeitenden
Funktionen rekursiv. Beispiel:
Funktion zur Suche nach einem Teilbaum mit einer bestimten Wurzel x.
let rec baumsuche(x,baum) = match baum with
| LeerB  LeerB
| Baum(y,wald) when x = y  Baum(y,wald)
| Baum(y,wald)  waldsuche(x,wald)
and waldsuche (x,wald) = match wald with
| LeerW  LeerB
| Wald (ersterB,restWald)
let t = baumsuche (x,ersterBaum)
in match t with
| LeerB  waldsuche (x,restWald)
|_t
;;
Weiteres Beispiel für Bäume mit mehreren „Kindbäumen“: (a,b)- Bäume.
Ein (a,b)-Baum ist ein externer Suchbaum (d.h. alle Informationen befinden sich in den
Blättern), für den gilt:
- alle Blätter haben die selbe Tiefe
- für die Anzahl N der Kinder eines jeden internen Knotens (außer
der Wurzel) gilt: a < N < b
- für die Wurzel gilt: 2 < N < b
außerdem gilt für b: b  2a 1
Spezialfall: b = 2 a -1, hier spricht man von B-Bäumen.
B-Bäume finden vor allem als Datenbank- Externspeicher Verwendung.
Funktoren: Datentypen mit Funktionen als Argument.
Bis hierher: Datentypen enthielten bisher Konstruktoren, deren Argumente wieder Datentypen
sind.
Bei den häufig verwendeten Sorten wie etwa stacks, Listen etc. sind die Zugriffsfunktionen
immer dieselben und eng mit der Datenstruktur verbunden. Deshalb sinnvoll: Funktionen
werden zum Bestandteil der Datenstruktur (ebenfalls zentrales Konzept oder OOP).
type ’a listFum = Wert of ’a |
Fum of (‘a  ‘a) * ‘a listFum;;
Der Konstruktor “Fum” enthällt hierbei aber als erstes Argument die Signatur ‘a  ‘a und als
zweites Argument ein Element des zu definiernden Datentyps.
Soll ein Objekt dieses Datentyps erzeugt (für Klugscheißer: instanziert) werden, so müssen
dem Konstruktor geeignete Eigenschaften übergeben werden, z.B.:
let succ = (+) 1;;
let div8= (/) 8;;
let a = Fum(div8, Fum(succ, Wert 3));;
Der Datentyp listFum ist also Listenstruktur, wobei der Kopf der Liste eine Funktion ist, die
auf den Rest der Liste angewendet werden kann. Ausgeführt werden könnte eine solche
Funktionsdeklaration mit Hilfe der Funktion:
let rec compute = function
| Wert v  v
| Fum (f,x)  f(compute x);;
hinmit ergäbe sich für compute a = 2.
Beispiel 2: Graphen und Suche in Graphen.
In einfacher Weise charakterisieren wir einen Graphen, indem wir jedem Knoten die Menge
seiner direkten Nachfolger angeben. Graph besteht also aus einer Funktion, die zu jedem
Knoten die Menge seiner Nachfolger berechnet bzw. zuordnet.
type ’a graph = Graph of (’a  ‘a list)
Beispiel: Graph zur Darstellung der echten Teiler einer natürlichen Zahl.
12
13
8
14
9
6
4
7
5
2
3
1. Schritt: Definition der NachfolgerFunktion.
let teiler n =
let rec f m = match m with
| m when (m<2)  []
| m when ( n mod m = 0)
& ( m <= n /2)  m :: f (m-1)
| m  f (m-1)
in f n;;
2. Schritt: Erzeugung des Objekts
let graph1 = Graph(teiler);;
Start
Ziel
In derart definierten Graphen soll nun nach Elementen gesucht werden, die gewisse Prädikate
pred erfüllen. Vorgehen:
1.)
Ausgehend vom Startknoten werden die direkten Nachfolgeknoten ermittelt.
2.)
Bei Breitensuche werden zuerst alle Nachgfolger geprüft und dann erst die
Nachfolger der Nachfolger; bei Teifensuche umgekehrt.
3.)
Jeder Nachfolgerknoten verweist seinerseits auf eine Menge von Knoten, hierbei
sollen nur die Knoten besucht (geprüft) werden, die vorher nicht bescuht wurden
(Vermeidung von Zyklen)
Algortihmus zur Teifensuche:
type ’a reachable = OK of ’a | Fail;;
type ‘a graph = Graph of (‘a  ‘a List);;
let getSuccFum(Graph(f))= f;;
let depthsearch graph pred startnodes=
let rec find visited startnodes =
match startnodes with
| []  Fail
| a:: rest, when isElem (a,visited)  find visited rest
/*getrennt zu spezifizieren
| a:: rest when (pred a)  OK a
| a:: rest  find (a:: visited)
((( getSuccFum graph)a) @ rest)
in find [] [startnodes];;
Herunterladen