Document

Werbung
Funktionale Programmierung
Zentrale Strukturen und Algorithmen
Was kenne ich bisher?

Rekursive Funktionsaufrufe (linear, Einstellig)

Rekursive Datenstrukturen (Listen, Bäume)
Was ist zu tun?
1.)
Vertiefung der Rekursion über Funktion
2.)
Terminierung rekursiver Funktionen
3.)
Verallgemeinerung / Vertiefung rek. Datenstrukturen: Polymorphie, Pattern
matching
4.)
Korrektheit von Implementierungen
5.)
Wichtigsten rekursiv zu formulierenden Algorithmen
1.) Vertiefung rekursiver Funktionen
Definition (informell): Wir sprechen von Rekursion, wenn auf der rechten Seite einer
Funktionsdefinition der Form let f1 = (m x) n: E im Ausdruck E die zu definierende Fkt. F1
auftritt.
m
x
n
E
Sorte
Parametersatz
Sorte der Rückgabewerte
Berechnungsausdruck
Allgemein: Sei
let f1 = ( m1 x1,…, mnxn)n1:E1
eine Funktionsdeklaration. Dann ist f1 rekursiv, wenn der Bezeichner f1 im Ausdruck E1
enthalten ist (also: rein syntaktisch prüfbar!)
Lineare Rekursion:
Der Bezeichner f1 tritt in E1 innerhalb einer Verzweigung einer Fallunterscheidung höchstens
ein mal auf.
Beispiel:
a) der durch den euklidischen Algorithmus definierte GGT ist linear rekursiv
b) Die Funktion lowerpart, welche die Elemente einer liste l berechnet, die kleiner als
ein best. Element el sind, ist linear
let rec lp (el, liste) = match (el, liste) with
| (el, [])  []
| (el, a :: rest) when (a<el)  a::(lp el rest)
| (el, a:: rest)  lp el rest
;;
Nichtlineare Rekursion:
Der Bezeichner f1 tritt in E1 innerhalb eines Zweiges einer Fallunterscheidung mind. 2 mal
auf.
Beispiel:
a) Sortieralgorithmus Quicksort (Moore)
 Sortieren durch Zerlegen
o Wähle ein beliebiges Element x aus der zu sortierenden Menge M aus. (x heißt
auch „Pirot- Element“)
o Zerlege M in die Mengen
M< = { L| L<x}, M= = {c| c =x}, M > = {u| u>x}
o Sortiere M<, M=, M >
o Die sortierte Menge M`ergibt sich dann durch Konkatenation wie folgt:
o M`= M< = M= = M >, wenn auf M eine Ordnung existiert.
Implementierung Quicksort:
Let rec quicksort liste = match liste with
| []  []
| [e]  [e]
| (e::rest)  quicksort(lp(e,liste)
@ ep (e, liste)
@ quicksort (up(e,liste))
;;
Bemerkung: „ep“ und „up“ sind analog zu „lp“ der equalpart und upponpart
b) Permutation auf Sequenzen
( Erinnerung: Kryptographie, Kombinatorik, Zufallszahlen- Erzeugung)
Permutationen sind bijektive Abbildungen
: [1,…n]  [[1,…,n]]
Gesucht:
Rechenvorschrifft, die zu einer Sequenz s die Sequenz aller
Permutationen von s liefert. Zum Beispiel;
perm([abc]) = ([abc],[acb],[bac],[bca],[cab],[cba])
Lösungsvorschläge für Berechnung der Permutation:
1.) systemantsiches Vorgehen: „Durchschieben“ des Elements am Kopf der Liste auf
alle Listenpositionen und Permutation der aus den anderen Elementen der
gebildeten Liste.
n=1
a
n=2
ab
ba
n=3
abc
acb
bac
cab
bca
cba
n=4
abcd
abdc
acbd
adbc
acdb
adcb
…
…
„a“ durchschieben je
„bc permutieren.
Wenn alle Permutationen des Listenrestes bekannt sind, folgt die Permutation durch
Durchschieben des Listenkopfes durch alle (Teil)Permutationen

Formulierung unter Nutzung von Hilfsfkt. wie folgt:
a) Funktion „StickOn“: ’a x list x list  list x list
Platziert ein Element x an den Anfang jedes Elements jeder Teilliste innerhalb
einer übergebenen Gesamtliste.
let rec stickOn x l = match l with
| []  []
| (h :: t)  (x :: h) :: stickOn x t;;
Aufruf: stickOn 3 [[1;4;5];[4;1;5];[4;5;1]];;
b) Funktion PutInAll ’a x list  list x list
let rec putInAll x l = match l with
| []  [[x]]
| (h::t)  (x::l) :: stickOn h (putInAll x t);;
c) Schließlich wird eine Funktion benötigt, die unter Verwendung von putInAll ein
Element x durch die Liste von Teilpermutationen schiebt und daraus die
Ergebnisliste erzeugt.
’a x list x list  list x list
let rec permuteAux x l = match l with
| [] -> []
| (h::t) -> (putInAll x h) @ (permuteAux x t) ;;
d) Damit möglich, Permutation anzugeben :
let rec permute l = match l with
| [] -> [[]]
| (h :: t) -> permuteAux h (permute t);;
Herunterladen