Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik I Vorlesung Rekursion-
2 Übersicht Das Prinzip der Rekursion Beispiel 1: Fakultätsfunktion Beispiel 2: QuickSort –„Teile und Herrsche“ –Konstruktion der Partition mit einem(!) Array –Wahl eines guten Anfangselements –Programmkonstrukte von Java –Quicksort: Umsetzung in Java –Funktion „RekQuickSort“ –Funktion „Swap“ (Vertauschen zweier Elemente)
3 Das Prinzip der Rekursion Eine rekursive Definition reduziert ein Problem auf ein kleineres Problem derselben Art. Eine rekursive Funktion setzt eine rekursive Definition in ein Programm um.
4 Definition: Für n 0 gilt Beispiel 1: Fakultätsfunktion
5 Fakultät int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; }
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(4)
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 4 != 0 fak(4)
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 4 > 0 fak(4)
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 4 * fak(3) fak(4)
4 * fak(3) fak(4)fak(4)=4*fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(3)
fak(4)=4*fak(3) 3 != 0 fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; }
fak(4)=4*fak(3) 3 > 0 fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; }
fak(4)=4*fak(3) 3 * fak(2) fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; }
fak(4)=4*fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 3 * fak(2) fak(3)fak(3)=3*fak(2) fak(2)
fak(4)=4*fak(3)fak(3)=3*fak(2) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 2 * fak(1) fak(2)
fak(4)=4*fak(3) fak(3)=3*fak(2) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(3)=3*fak(2) 2 * fak(1) fak(2)fak(2)=2*fak(1) fak(1)
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 1 * fak(0) fak(1)
fak(4)=4*fak(3) fak(3)=3*fak(2) fak(2)=2*fak(1) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(2)=2*fak(1) 1 * fak(0) fak(1)fak(1)=1*fak(0) fak(0)
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1)fak(1)=1*fak(0) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } n = 0 fak(0)
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1)fak(1)=1*fak(0) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } 1 fak(0)
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1)fak(1)=1*fak(0) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(0) = 1
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1)fak(1)=1*fak(0) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(0) = 1
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(1)=1*1
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(1)=1
fak(4)=4*fak(3)fak(3)=3*fak(2)fak(2)=2*fak(1) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(1) = 1
fak(4)=4*fak(3)fak(3)=3*fak(2) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(2) = 2*1
fak(4)=4*fak(3)fak(3)=3*fak(2) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(2) = 2
fak(4)=4*fak(3)fak(3)=3*fak(2) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(2) = 2
fak(4)=4*fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(3) = 3*2
fak(4)=4*fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(3) = 6
fak(4)=4*fak(3) int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(3) = 6
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(4) = 4*6
int fak(int n) { if(n==0) return 1; else if (n>0) return n * fak(n-1); else return -1; } fak(4) = 24
34 Beispiel 2: QuickSort einer der schnellsten Sortieralgorithmen Grundidee: „Teile und Herrsche“ (“divide and conquer“) - ein wichtiges Paradigma für geometrische Algorithmen rekursiver Algorithmus
35 Sortierfeld A mit n Elementen Wahl eines Wertes W des Feldes „Teile und Herrsche“
36 W Konstruktion einer Partitionierung des Feldes „Teile und Herrsche“
37 A1A1 A2A2 W 1 l-1 l+1n Sortieren von A 1 und A 2 durch Rekursion „Teile und Herrsche“ alle Elemente von A 1 sind <= W (noch unsortiert) alle Elemente von A 2 sind >= W (noch unsortiert)
38 Konstruktion der Partition mit einem(!) Array Wahl eines Elementes W im Inneren des Array Suchen eines i von links an mit A[ i ] >= W Suchen eines j von rechts an mit A[ j ] <= W Vertauschen von A[ i ] und A[ j ] Wiederhole dies, bis i >= j gilt
W = 7 Konstruktion der Partition mit einem(!) Array Suchen eines i von links an mit A[ i ] >= W Suchen eines j von rechts an mit A[ j ] <= W Vertauschen von A[ i ] und A[ j ]
Konstruktion der Partition mit einem(!) Array Suchen eines i von links an mit A[ i ] >= W Suchen eines j von rechts an mit A[ j ] <= W Vertauschen von A[ i ] und A[ j ] W = 7
41 W = 7 rekursiv weitermachen Konstruktion der Partition mit einem(!) Array Suchen eines i von links an mit A[ i ] >= W Suchen eines j von rechts an mit A[ j ] <= W Vertauschen von A[ i ] und A[ j ] Wiederhole dies, bis i >= j gilt
42 das mittlere von links(Low)4 mitte(Middle)1 rechts(High) Wahl eines guten Anfangselements vertausche 4 und 1
43 das mittlere von links(Low)4 mitte(Middle)1 rechts(High)9 Wahl eines guten Anfangselements vertausche 4 und 1
44 a / b ganzzahlige Division, wenn beide Operanden ganzzahlig Iteration wiederhole die Anweisung solange die Bedingung erfüllt ist a) Überprüfen der Bedingung vor Schleifeneintritt while (Bedingung) do Anweisung b) Überprüfen der Bedingung nach Schleifeneintritt do Anweisung while (Bedingung) Programmkonstrukte von Java
45 void QuickSort (char[] A) { int Hi = A.length-1; RekQuickSort ( A, 0, Hi); } Quicksort: Umsetzung in Java
46 void RekQuickSort (char[] A, int Lo, int Hi) { int li = Lo; int re = Hi; int mid = (li+re)/2; if (A[li] > A[mid]) Swap(A, li, mid); if (A[mid] > A[re]) Swap(A, mid, re); if (A[li] > A[mid]) Swap(A, li, mid); Funktion „RekQuickSort“
if((re - li) > 2) { char w = A[mid]; do { while(A[li] < w) li++; while(w < A[re]) re--; if(li <= re) { Swap (A, li, re); li++; re--; } }while(li <= re); if(Lo < re) RekQuickSort (A, Lo, re); if(li < Hi) RekQuickSort (A, li, Hi); }
private void Swap (char [] A, int i, int k) { char h = A[i]; A[i] = A[k]; A[k] = h; } Funktion „Swap“ (Vertauschen zweier Elemente)