STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN ·...

20
STRUKTURIERTES PROGRAMMIEREN Vorlesung im Sommersemester 2014 Prof. E.G. Schukat-Talamazzini Stand: 15. Oktober 2014 Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ Teil VIII Rekursion Maurits Cornelis Escher: Zeichnen (1948) Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ Mathematische Induktion Gaußsche Summationsformel σ(N ) def = N X i =1 i = 1 + 2 + 3 + ... + N = N 2 · (N + 1) Induktionsbeweis 1. Induktionsanfang: σ(1)= 1 = 1 / 2 · (1 + 1) 2. Induktionsvoraussetzung: σ(N - 1)= (N-1) / 2 · N 3. Induktionsschritt: σ(N ) = σ(N - 1)+ N = (N-1) / 2 · N + N = (N+1) / 2 · N = N / 2 · (N + 1) Rekursionsformel für die Reihe arithmetischer Summen σ(N ) def = 1 N = 1 σ(N - 1)+ N N > 1 Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ Was ist Rekursion ? Rekursiv formulierte Algorithmen Eine Funktion f ruft sich bei Berechnung selbst auf. direkter oder indirekter Selbstaufruf ? Aufruf einfacherer Inkarnationen ihrer selbst Effektivität Terminierung · Zyklen · endloser Abstieg ? Effizienz Berechnungsaufwand Aufrufverzweigung Beispiele rekursiver Algorithmen Zählen aller Bytes in den Dateien eines Katalogbaums Nachschlagen einer Bedeutung im Wörterbuch Arithmetische Ausdrücke in BNF-Notation

Transcript of STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN ·...

Page 1: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

STRUKTURIERTES PROGRAMMIEREN

Vorlesung im Sommersemester 2014

Prof. E.G. Schukat-Talamazzini

Stand: 15. Oktober 2014

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teil VIII

Rekursion

Maurits Cornelis Escher: Zeichnen (1948)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Mathematische InduktionGaußsche Summationsformel

σ(N)def=

N∑i=1

i = 1 + 2 + 3 + . . .+ N =N2· (N + 1)

Induktionsbeweis1. Induktionsanfang: σ(1) = 1 = 1/2 · (1+ 1)

2. Induktionsvoraussetzung: σ(N − 1) = (N−1)/2 · N

3. Induktionsschritt:σ(N) = σ(N − 1) + N = (N−1)/2 · N + N

= (N+1)/2 · N = N/2 · (N + 1)

Rekursionsformel für die Reihe arithmetischer Summen

σ(N)def=

{1 N = 1σ(N − 1) + N N > 1

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Was ist Rekursion ?

Rekursiv formulierte AlgorithmenEine Funktion f ruft sich bei Berechnung selbst auf.

• direkter oder indirekter Selbstaufruf ?

• Aufruf einfacherer Inkarnationen ihrer selbst

• EffektivitätTerminierung · Zyklen · endloser Abstieg ?

• EffizienzBerechnungsaufwand Aufrufverzweigung

Beispiele rekursiver AlgorithmenZählen aller Bytes in den Dateien eines KatalogbaumsNachschlagen einer Bedeutung im WörterbuchArithmetische Ausdrücke in BNF-Notation

Page 2: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursion und IterationBeispiel — rekursive Summenberechnungint sigmaRec(int n) {

return (n==0) ? 0 : // Trivialfall(sigmaRec(n-1) + n) ; // Selbstaufruf

}

Beispiel — induktive Summenberechnungint sigmaInd(int n) {

int[] sig = new int[1+n]; // Zwischenergebnissesig[0] = 0; // Trivialfallfor (int i=1; i<=n; i++) // Traversieren

sig[i] = sig[i-1] + i; // Gedächtnisabrufreturn sig[n];

}

Kompaktvariante (Speicherüberlagerung für Zwischenresultate)int sig = 0;for (int i=1; i<=n; i++) sig = sig + i;return sig;

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele rekursiver Funktionsdeklarationenin Java-ähnlicher Notation

Ganzzahlige Addition und Multiplikationint add (int n, int m)

{ return (n == 0) ? m : succ (add (n-1,m)); }

int mult (int n, int m){ return (n == 0) ? 0 : add (mult (n-1,m), m); }

Ganzzahlige Division und Restint div (int n, int m)

{ return (n < m) ? 0 : div (n-m,m) + 1; }

int mod (int n, int m){ return (n < m) ? n : mod (n-m,m); }

Binomialkoeffizientenint binom (int n, int m) {

return (m == 0 || m == n) ? 1 :binom (n-1,m-1) + binom (n-1,m);

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele rekursiver Funktionsdeklarationen(Fortsetzung)

Palindromeigenschaftint zpot (int n)

{ return (n < 10) ? 1 : zpot (n/10) * 10; }

int spiegel (int n) {return (n < 10) ? n :

n%10 * zpot (n) + spiegel (n/10);}

boolean palindrom (int n){ return (n == spiegel (n)); }

Spiegelung von Dezimalziffern

4 7 1 1 4 7 1 1 471 1 1 471 1 1 7 4

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Page 3: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen IKetten- oder baumförmige Aufrufhierarchie

fak(4)

fak(3)

fak(2)

fak(1)

fak(0)

linear

bifak(1,5)

bifak(1,3) bifak(4,5)

bifak(2,2)bifak(1,1)

bifak(1,2) bifak(5,5)bifak(3,3) bifak(4,4)

kaskadiert

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen II

ack(3,3)

ack(2,?) ack(3,2)

ack(3,0)

ack(2,?)

ack(2,?)

ack(2,1)

ack(2,0)ack(1,?)

ack(1,0)ack(0,?)

ack(1,1)

ack(0,1)

ack(3,1)

verschachtelt

dynamische Schachtelung

wechselseitiger Aufruf

q2odd(LOLLO)

q2odd(LOLL)

q2even(LOL)

q2odd(LO)

q2odd(L)

verschränkt

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Lineare Rekursion

STECKBRIEFLaufzeit Aufruf provoziert ≤ 1 UnteraufrufeSyntax ≤ 1 F -Auftreten je BedingungszweigAufwand Aufrufkette lineares WachstumBeispiele div, fac, ggT, sqrt

Beispiel - Fakultätsfunktionint factorial (int n)

{ return (n == 0) ? 1 : n * factorial (n-1); }

Aufrufdiagrammfac(5) r*5

fac(4) r*4

fac(3) r*3

fac(2) r*2

fac(1)←1

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele — lineare Rekursion

Größter gemeinsamer Teilerint ggT (int n, int m) {

return (n == m) ? n :(n < m) ? ggT (n, m-n) :

ggT (n-m, m) ;}

Der Funktionsbezeichnerdarf durchaus mehrfachim Rumpf auftreten,allerdings maximal 1× jeZweig einerFallunterscheidung.

Quadratwurzel durch Intervallschachtelungdouble sqrt (double x, double a, double b) {

final double Z = (b-a) / 2;return (b-a < 1e-24) ? Z :

(Z*Z < x) ? sqrt (x, Z, b) :sqrt (x, a, Z) ;

}

Das initialeAufrufintervall[a, b] muß dierichtige Lösung√

x mitSicherheitenthalten.

Aufrufausdruck: (x>1) ? sqrt(x,1,x) : sqrt(x,x,1)

Page 4: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Kaskadierte RekursionSTECKBRIEFLaufzeit Aufruf provoziert evt. auch > 1 UnteraufrufeSyntax ex. Bedingungszweig mit ≥ 2 F -AuftretenAufwand Aufrufbaum u.U. exponentielles WachstumBeispiele fib, bifac, Kansas City, Quicksort

Beispiel - Fibonaccizahlenint fib (int n) {

return (n == 0) ? 1 :(n == 1) ? 1 : fib (n-2) + fib (n-1) ;

}

Aufrufdiagrammfib(3) ⊕ 1+ 2

fib(1)←1fib(2) ⊕ 1+ 1

fib(0)←1 fib(1)←1

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele — kaskadierte Rekursion

Fakultät durch Bisektionint bifac (int m, int n) {

return (m > n) ? 1 :(m == n) ? n :

bifac (m, (m+n)/2) * bifac ((m+n)/2 + 1, n) ;}

Aufruf:fac(n) ≡ bifac(1,n)

Optimale Wege in Kansas-Cityint kansas (int i, int j, int m, int n) {

return (i == m) ? 1 :(j == n) ? 1 : kansas (i+1,j,m,n) + kansas (i,j+1,m,n) ;

}Iterierte Quersummenberechnungint quer (int n) {

return (n < 10) ? n : x%10 + quer (x/10) ;}int iquer (int n) {

return (n < 10) ? n : iquer (quer (n)) ;}

Achtung!nichtgeschachteltnichtverschränktnicht einmalkaskadiert

Optimale Wege in der L1-MetrikIn der Reißbrettstadt Wolfsburg (oder Kansas City) verlaufen alle Straßen äquidistantund kartesisch, d.h. genau Ost-West oder Nord-Süd.

d(x , y) = ‖x − y‖1def= |x1 − y1|+ |x2 − y2|

Die Kreuzungen seien mit ganzzahligen Koordinaten (i , j) ∈ Z× Z bezeichnet.Kürzeste Wege von (0, 0) nach (n,m) vermeiden konsequent jeglichen Umweg inRichtung Süd oder West; ihre Länge ist also stets n + m.

Analytische LösungFür die auf kürzesten Wegen zu bewältigenden Streckenelemente (n× Nord und m×Ost) gibt es (n + m)! mögliche Reihenfolgen, von denen aber wegen der inhärentenUnunterscheidbarkeit der Nord- und der Ostelemente nur

wolfsburg(n,m) =(n + m)!

n! ·m!=(n + m

n

)zu berücksichtigen sind.

Rekursive LösungVon (0, 0) nach (10, 10) gibt es 184.756 Minimalwege. Die kaskadierte Rekursionbenötigt zur Berechnung dieses Resultats stattliche 369.511 Funktionsaufrufe,beginnend mit kansas(0,0,10,10).

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Verschachtelte RekursionSTECKBRIEFLaufzeit auch die F -Argumente werden durch F -Aufrufe berechnetSyntax extrem diffizile TerminierungsbeweiseAufwand unter Umständen hyperexponentielles WachstumBeispiele ackermann

Beispiel - die Ackermannfunktionint acker (int m, int n) {

return (m == 0) ? (n+1) :(n == 0) ? acker (m-1, 1) :

acker (m-1, acker (m, n-1)) ;}Einige Funktionswerte

m/n 0 1 2 3 4 5 60 1 2 3 4 5 6 71 2 3 4 5 6 7 82 3 5 7 9 11 13 153 5 13 29 61 125 253 5094 13 ?? . . . . . .5 ?? . . . . . . . . .

Anzahl Selbstaufrufem/n 0 1 2 3 4 5 60 1 1 1 1 1 1 11 2 4 6 8 10 12 142 5 14 27 44 65 90 1193 15 106 541 2432 10307 42438 1722334 107 ?? (> 5 · 106)5 ?? . . .

Page 5: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Wissenswertes über die AckermannfunktionInduktiv definierte arithmetische VerknüpfungenUnendliche Folge zweistelliger Rechenoperationen:

g1(n,m)def= n +m = (n + (m − 1)) + 1

g2(n,m)def= n ·m = (n · (m − 1)) + n

g3(n,m)def= nm =

(nm−1) · n

g4(n,m)def= n ◦m = (n ◦ (m − 1))n

g5(n,m)def= n ♦m = (n ♦ (m − 1)) ◦ n

. . . . . . . . .

gk(n,m)def= gk−1(gk(n,m − 1), n) (∀k ∈ IN)

DiagonalenprojektionWir beschränken unser Interesse auf Berechnungen mit gleichen Operandenn = m, also n + n, n · n, nn, n ◦ n, n ♦ n, usw.:

ackermann(k, n) def= gk(n, n) für alle k, n ∈ IN

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Verschränkte Rekursion

Zyklus wechselseitiger AufrufeSystem von KFunktionsdeklarationenIndirekter Selbstaufruf „über Bande“Typisch für OO-Programmierung

f1 ← f2 ← . . . ← f`−1

↓ ↑fK f`↓ ↑

fK−1 → fK−2 → . . . → f`+1

Beispiel - Test auf un/gerade Quersummeboolean q2odd (int n) {

return ( n == 0) ? false :(n%2 == 0) ? q2odd (n/2) :

q2even (n/2) ;}boolean q2even (int n) {

return ( n == 0) ? true :(n%2 == 0) ? q2even (n/2) :

q2odd (n/2) ;}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Schlichte Rekursion (Endrekursion)

STECKBRIEFSpezialfall der linearen RekursionLaufzeit Selbstaufruf ist die „letzte Amtshandlung“ im RumpfSyntax F -Aufruf = äußere Schale im KlammergebirgeAufwand wie lineare Rekursion; ggf. speicherfreundlichBeispiele mod, ggT, sqrt, iquer, divauxGegenbeispiele add, mult, div, fac, kaskadierte Deklarationen

Aufrufdiagramm für die ggT-DeklarationggT(21,33) r

ggT(21,12) r

ggT(9,12) r

ggT(9,3) r

ggT(6,3) r

ggT(3,3)←3

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — eine schlichte Variante der DivisionDivision mit Hilfsargumentint divaux (int n, int m, int h) {

return (n < m) ? h: divaux (n-m, m, h+1) ;

}

Semantische ÄquivalenzEin divaux(n,m,0) -Aufruf berechnet den Ganzzahlquotienten, denn:

divaux (n,m,h) ≡ div (n,m) + h

Beweis.• Induktionsanfang: Ist n < m, so gilt div(n,m)≡ n/m = 0.

Der Aufruf divaux(n,m,h) liefert dann aber auch h = 0+ h.

• Induktionsschluß:divaux(n,m,h) ≡ divaux(n-m,m,h+1)

I .V .≡ div(n-m,m) + (h+1)

≡ div(n,m) + h

Page 6: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Endrekursion und Iteration

EndrekursionSchema für einen Parameter

T f (T ′ x) {return B(x) ?

f (φ(x)) :ψ(x) ;

}

IterationSemantisch gleichwertig:

T f (T ′ x) {while (B(x))

x = φ(x);return ψ(x);

}

Trivialschalter B, Problemreduktion φ, Trivialrechnung ψ

Aufrufschema für die Endrekursionf (x) r

f (φ(x)) r

f (φ2(x)) r

f (φ3(x)) r

ψ(φ3(x))

Eingespart Rechenzeit⊕ Speicher

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Zwischenbilanz

Mathematische Funktion implementierte FunktionDie Rekursionsform ist eine Eigenschaft derFunktionsdeklaration, nicht aber der mathematischen Funktionper se.• Die ganzzahlige Division ist in unseren Beispielen einmal linear(div) und einmal schlicht (divaux) deklariert.

• Die Fakultätsfunktion ist einmal linear (fac) und einmalkaskadiert (bifac) deklariert.

EinbettungstechnikSystematische Methode zurVerschönerung der Rekursionsform

scheinbar N.R.

kaskadiertlinear

schlicht(iterativ)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Einbettung mit ZusatzargumentenAufgabe ohne kanonisch-rekursive Formulierungprim(n)

?≡ Ψ( n, prim(n-1), prim(n-2), . . .)

zusätzliche

Parameter

EINBETTUNG

Problemstellung Verallgemeinerung

Spezialfall

Einbettungstechnik

1. Hilfsargumente einführen f (x) g(h, x)

2. Rekursiv formulieren g(h, x) ≡ Ψ(x , h, g(h′, x ′), g(h′′, x ′′), . . .)

3. per Treibermethode aufrufen f (x) ≡ g(h∗, x)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Rekursion um jeden Preis(scheinbar nicht rekursiv schlicht)

GrundideeEine Zahl n ∈ IN ist prim n besitzt keinen Teiler in [2, n/2]

Teilerrekursion für den Primzahltest

boolean teilerBis (int h, int n) {return (h < 2) ? false :

(n%h == 0) ? true :teilerBis (h-1, n) ;

}

Treibermethode für den Primzahltest

boolean prim (int n) {return (n > 1) && ! teilerBis (n/2, n) ;

}

Page 7: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Fakultät für schlichte Informatik(linear schlicht)

Rekursion für Fakultät

int sfac (int h, int n) {return (n == 0) ?

h :sfac (h*n, n-1) ;

}

Treibermethode für Fakultät

int sfac (int n) {return sfac (1, n);

}

(überladene Methodennamen!)

GrundideeStatt n! auf n · (n − 1)! zu reduzieren,berechne sukzessive Produkte derForm n · (n − 1) · . . . · (m + 1) ·m;Weiterleitung via h an denUnteraufruf.

Invariantesfac(h, n) = h · n!

Beweis.Vollständige Induktion:Für n = 0 liefert sfac(1,n) dasArgument h = 1 ab und für n > 0 gilt:

sfac(h, n) = sfac(h · n, n − 1)I .V .= h · n · (n − 1)!

= h · n!

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Fibonacci goes schlicht(kaskadiert schlicht)

Rekursion für Fibonacci

int sfib (int r, int q, int k) {return (k == 0) ?

q : (k == 1) ?r :sfib (r+q, r, k-1) ;

}

Treibermethode für Fibonacci

int sfib (int n) {return sfib (1,1,n);

}

(überladene Methodennamen!)

GrundideeHilfsparameter für Fn−1 und Fn−2

InvarianteNach Aufruf sfib(1, 1, n) gilt stets=β [(r , q, k)] = (Fn−k+1,Fn−k , k)

Beweis.Es gilt die Äquivalenzkette

sfib(n) ≡ sfib(1, 1, n)

≡ sfib(F1,F0, n)

≡ sfib(F2,F1, n − 1)

≡ sfib(F3,F2, n − 2)

≡ . . .

≡ sfib(Fn−1,Fn−2, 2)

≡ sfib(Fn,Fn−1, 1)

≡ Fn

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Entwurf rekursiver Algorithmen(Küchlin & Weber, Kapitel 10.1)

AlgorithmenschemaBestandteile des Deklarationsrumpfes einer rekursiven Funktion

1 Initialisierungen final int FAC0 = 1;Deklaration & Definition von Variablen und Konstanten

2 Ausnahmefälle if (n<0) throw new Except...();Prüfen der Vorbedingungen

3 Trivial- oder Basisfälle if (n==0) return FAC0;Induktionsanfang: Direktberechnung

4 Reduktion int sub1 = n-1;auf „einfachere“ Teilaufgaben

5 Rekursion int res1 = fac (sub1);durch Unteraufruf(e) der Funktion selbst

6 Rekombination return n * res1;der erzielten Zwischenresultate

Page 8: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Korrekte, terminierende & effiziente Rekursion4+1 goldene Regeln rekursiver Programmierung (M.A. Weiss)

• es gibt mindestens einen direkt lösbaren Fall• Unteraufrufe Fortschritt in Richtung Trivialfall• alle Unteraufrufe sind generell erfolgreich• keine unnötige Berechnung von Zwischenergebnissen• keine vermeidbaren Anfängerfehler

Berechnung der Binomialkoeffizienten(nk

)=

n!k! · (n − k)!

=

{ n/k ·(n−1k−1

)k > 0

1 k = 0

Warum ist das folgende Programmfragment keine gute Idee ?

int binom (int n, int k) {return (k == 0) ? 1 : n/k * binom (n-1, k-1) ;

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Die Effizienz eines Algorithmus

Papierverbrauch: Schreibtischfläche:Wieviele Blätter werden Wieviele Blätter werdeninsgesamt benötigt ? gleichzeitig verwendet ?RECHENAUFWAND SPEICHERBEDARF

PapierbogenmetapherU.-Aufruf =̂ neues BlattResultat zerknüllen

DefinitionFür eine Funktionsdeklaration

T0 f (T1 n, ...) { SRumpf }

mit einem formalen Parameter n ganzzahligen Typs definieren wir diefolgenden Effizienzmaße:1. Aufrufbreite Φb

f (n) Gesamtzahl aller ausgeführten f -Aufrufe

2. Aufruftiefe Φtf (n) Max. Anzahl gleichzeitig aktiver f -Aufrufe

3. Rechenaufwand Φrf (n) Gesamtzahl auszuwertender Grundoperationen

4. Speicherbedarf Φsf (n) Max. Anzahl simultaner Identifikatorbindungen

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Effizenzberechnung

Ganzzahlige Divisionsmethode

int div (int n, int m){ return (n < m) ? 0 : div (n-m,m) + 1; }

AufruftiefeΦt

div(n,m) = n/m + 1

Der (kettenförmige) Aufrufbaumbesitzt n/m innere Knoten und einenBlattknoten (ohne Unteraufruf).

AufrufbreiteΦb

div(n,m) = n/m + 1

In jedem der n/m + 1 Aufrufe schlagendie beiden lokalen Variablen n und m zuBuche.

SpeicherbedarfΦs

div(n,m) = 2 · n/m + 2

In jedem Aufruf sind drei arithmetischeOperationen auszuführen: derGrößenvergleich n<m, die Subtraktionn-m und die Addition div()+1.

RechenaufwandΦr

div(n,m) = 3 · n/m + 1

Im Blattaufruf entfallen die beidenletzten Operationen.

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rechenaufwand und Programmlaufzeit

Beispielprozedur(geschachtelte Laufschleifen)

void proz (int n){proz_1();proz_1();for (int i=1; i<=n; i++){

proz_2();proz_2();proz_2();for (int j=1; j<=n; j++){

proz_3();proz_3();

}}

}

Laufzeit in Sekundenproz_1 proz_2 proz_3

Rechner A 3 s 5 s 4 sRechner B 5 s 3 s 7 sRechner C 17 s 14 s 23 sallgemein ζ1 s ζ2 s ζ3 s

Anzahl Operationen=β [n] 1 10 100 1000 nproz_1 2 2 2 2 2proz_2 3 30 300 3000 3nproz_3 2 200 20000 2000000 2n2

Asymptotisches VerhaltenWelches ist der dominierende Term für n→∞ ?

Φz(n)Φz(m)

=2n2ζ3 + 3nζ2 + 2ζ12m2ζ3 + 3mζ2 + 2ζ1

≈ 2n2ζ32m2ζ3

=( nm

)2

Page 9: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Die Landau-SymbolikDefinitionEs seien g : IN→ IN und φ : IN→ IN zwei Abbildungen. Wir schreiben

g(n) = O(φ(n)) (g(·) ist ein Groß-„Oh!“ von φ(·)),

wenn es zwei positive reelle Zahlen c1, c2 gibt und ein n0 ∈ IN mit

n ≥ n0 ⇒ c1 ≤g(n)

φ(n)≤ c2 ,

d.h., g(·) wächst in der gleichen Größenordnung wie φ(·).

Beispielkomplexitäten:

• Φb(n) = 17 O(1) bzw. O(n0)

• Φb(n) = 2n + 5 O(n) bzw. O(n1)

• Φb(n) = 2n2 + 3n + 2 O(n2)

• Φb(n) = n3 + 883n2 O(n3)

• Φb(n) = n log2(n) + 12n O(n log n)

• Φb(n) = 2n + 17n8 O(2n)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Asymptotik gängiger Komplexitätsklassenkonstant · logarithmisch · linear · polynomial · exponentiell

1

10

100

1000

10000

2 4 6 8 10 12 14 16 18

Kom

plex

itaet

Parameter ’n’

2*x**0log(x)

x**1x*log(x)

x**210*x**2

x**32**x

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Terminierung rekursiver FunktionenO(∞) — die scheußlichste aller Komplexitätsklassen

FaktMethodenaufruf terminiert endliche Zahl von Selbstaufrufen

MotivationFür die Aufrufbreite des kaskadierten Algorithmus zur Berechnung derFibonacci-Zahlen gilt

Φbfib(n) =

{1 n ∈ {0, 1}Fn+1 + Fn−2 − 1 n ≥ 2 ;

dabei sei {Fn}n∈IN die Fibonacci-Reihe.Insbesondere terminiert der Algorithmus für alle Eingaben n ∈ IN.

Fibonaccizahlen und ihre Aufruftiefe

n 0 1 2 3 4 5 6 7 8 9 10 11 ...Fn 1 1 2 3 5 8 13 21 34 55 89 144 ...Φb

fib(n) 1 1 3 5 9 15 25 41 67 109 177 287 ...

Beweis.Für n ≥ 2 gehorcht die Aufrufbreite der Rekursionsformel

Φbfib(n) = 1+Φb

fib(n − 1) +Φbfib(n − 2)

• Induktionsanfang.Für n ∈ {0, 1} ergibt sich die Aussage aus der Tabelle und für n ∈ {2, 3}gilt:

Φbfib(2) = 3 = 3+ 1− 1 = F3 − F0 − 1

Φbfib(3) = 5 = 5+ 1− 1 = F4 − F1 − 1

• Induktionsschritt.Und nun der Schluß von n − 2 und n − 1 auf n:

Φbfib(n) = Φb

fib(n − 2) +Φbfib(n − 1) + 1

= (Fn−1 + Fn−4 − 1) + (Fn + Fn−3 − 1) + 1

= (Fn−1 + Fn) + (Fn−4 + Fn−3) + (1− 1− 1)

= Fn+1 + Fn−2 − 1

Page 10: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Terminierungsbeweise

DefinitionEine Funktion ϕ : IN→ IR heißt Majorante für die Aufrufbreite von f ,wenn sie eine obere Schranke für die Anzahl rekursiver f -Aufrufe darstellt:

∀n ∈ IN : Φbf (n) ≤ ϕf (n)

Direkter BeweisBerechne die Funktion Φb

f (n)

⊕ Induktionsbeweis simpel

Formel finden schwierig

Indirekter BeweisFinde (irgendeine) geeigneteMajorante ϕf (n) von Φb

f (n)

⊕ Induktionsbeweis simpel

⊕ Schranke durch Probieren

Beispiel FibonaccizahlenΦb

fib(n) ≤ ϕfib(n)def= 2n

Beweis.• Induktionsanfang.

Die drei ersten Fälle:

20 ≥ 1

21 ≥ 1

22 ≥ 3

• Induktionsschritt.Ab n = 3 verfängt der Induktionsschritt

Φbfib(n) = Φb

fib(n − 2) +Φbfib(n − 1) + 1

≤ 1+ 2n−2 + 2n−1

≤ 2n−2 + 2n−2 + 2n−1

= 1/4 · 2n + 1/4 · 2n + 1/2 · 2n

= 2n

0 2 4 6 8 10

15

1050

100

500

1000

n

loga

rithm

isch

e S

kala

● ●

● ●

Majorante 2^nAufruftiefeFibonaccizahlen

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Klassische Entwurfstechnikenam Beispiel der Berechnung power(x,n) = xn

AufwandΦ(f(n)) = Φ(Overhead) + Φ(U-Aufrufe)

Dekomposition⊗ eindeutig zerlegbar ?⊗ gleicher Gesamtaufwand ?⊗ gleiches Zwischenergebnis ?

Zwischenergebnisse⊗ dopppelt gemoppelt⊗ überflüssig

Gierige Algorithmenwählen (erst-)beste Zerlegung

Vorbedingungen abprüfen

Trivialfälle direkt ausrechnen

Zerlegung der Aufgabenstellung

f(n¹) f(n²) f(n³) f(...)

Zusammenführung der Teilergebnisse

Page 11: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Gierige Algorithmen„greedy“ oder „gefräßig“

SteckbriefDie Aufgabe wird in sehr ungleiche Teile zerlegt; höchstens eineTeilaufgabe ist nicht trivial.

• ignoriert Zerlegungsvarianten u.U. suboptimales Ergebnis

• lineare Rekursion i.A. günstige Laufzeit

Im Beispiel beträgt die Aufrufbreite ΦbpowerGR(n) = n + 1.

double powerGR (double x, int n) {return (n == 0) ? 1

: x * powerGR (x, n-1) ;}

x9

x8

x7

x6

x5

x4

x3

x2

x1

x0

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teile und Herrsche („divide & conquer“)SteckbriefDie Aufgabe wird in mindestens einem Fall in ≥ 2 Teile zerlegt.

• kaskadierte Rekursion parallelisierbar?

• kombinatorische Explosion exponentieller Aufwand ?

Im Beispiel beträgt die Aufrufbreite im günstigsten Fall — wenn nZweierpotenz ist — Φb

powerGR(n) = 2n − 1.

double powerDC (double x, int n) {return (n == 0) ? 1 :

(n == 1) ? x :powerDC (x, n/2) * powerDC (x, n - n/2);

}

x9

x4

x5

x2

x2

x2

x3

x1

x1

x1

x1

x1

x1

x1

x2

x1

x1

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Dynamische ProgrammierungSteckbriefLösung von Teilaufgaben & Tabellierung und Abruf der Ergebnisse

• Teilaufgaben überschneiden — Zerlegung uneindeutig

• Gedächtnis statt Mehrfachberechnung

• Iteration (Speicher füllen) statt Rekursion

Im Beispiel beträgt die Aufrufbreite ΦbpowerDP(n) = O(n).

double powerDP (double x, int n) {double[] r = new double [n+1];r[0] = 1; r[1] = x;for (int i = 1; i <= n; i++) r[i] = r[i/2] * r[i - i/2];return r[n];

}

x9

x8

x7

x6

x5

x4

x3

x2

x1

x0

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Backtracking oder „trial & error“SteckbriefPulsierendes Berechnen der Zwischenergebnisse bei Bedarf („JIT“)

• nicht alle Teilaufgaben sind zu lösen

• Zerlegungen uneindeutig — konkurrierende Berechnungspfade

Im Beispiel beträgt die Aufrufbreite ΦbpowerBT(n) = O(log2(n)).

double powerBT (double x, int n, double[] r) {if (n == 0) r[0] = 1;else if (n == 1) r[1] = x;else { if (r[n/2]==0) r[n/2] = powerBT (n/2);

if (r[n-n/2]==0) r[n-n/2] = powerBT (n-n/2);r[n] = r[n/2] * r[n - n/2];

}return r[n];

}

x9

x5

x4

x3

x2

x1

x0

Page 12: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Überraschungserfolgkaskadiert linear schlicht iterativ

double powerCas (double x, int n) {return (n==0) ? 1 :

(n%2==1) ? x * powerCas(x,n-1) :powerCas(x,n/2) *powerCas(x,n/2);

}

Kaskadiertxn =

1 n = 0x · x2m n = 2m + 1xm · xm n = 2m

double powerLin (double x, int n) {if (n==0) return 1;if (n%2==1) return x * powerLin(x,n-1);final double USETWICE = powerLin(x,n/2);return USETWICE * USETWICE;

}

Linearxn =

1 n = 0x · x2m n = 2m + 1(xm)2 n = 2m

double powerLoop (double x, int n) {double reval = 1;while (n>0)

if (n%2==1) { reval *= x; n -= 1; }else { x *= x; n /= 2; }

return reval;}

Schlicht & iterativSchleifeninvariante:reval* x*x*...*x︸ ︷︷ ︸

n-mal

= const

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — die maximale TeilsummeMCSSS = „maximum contiguous subsequence sum“

Taggenaue Kurse eines AktienfondsWelche Kombination aus An- und Verkaufdatum ist die rentabelste?Kalendertag 1 2 3 4 5 6 7 8 9 10Gewinn/Verlust +5 −8 +3 +3 −5 +7 −2 −7 +3 +5

Lösung:acht Euro Gewinn bei Kauf vor dem 3. Juli und Verflüssigung nach dem 6. Juli

DefinitionEs sei x = 〈x1, . . . , xn〉 eine reellwertige Zahlenfolge. Der Wert

MCS3(x)def= max

1≤j,k≤nSj,k(x) mit Sj,k(x)

def=

k∑i=j

xi

heißt maximale Teilsumme von x .

(Konvention: die leere Teilsumme ist Null)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Ein kubischer MCS3-AlgorithmusExplizite Berechnung/Vergleich aller Teilsummenmit drei geschachtelten Zählschleifen:

double mcsss3 (double[] x) { //double smax = 0.0; // leere Teilfolgefor (int j = 0; j < x.length; j++) // Anfangsindex

for (int k = j; k < x.length; k++) { // Endeindexdouble summe = 0.0; //for (int i = j; i <= k; i++) // Summationsschleife

summe += x[i]; //if (summe > smax) // Maximumbildung

smax = summe; //} //

return smax; //}

ZeitkomplexitätDie innerste Anweisung summe+=x[i]; wird im Fall n≡ x.length genau1/6n3 + 1/2n2 + 1/3n1 = O(n3) mal ausgeführt.

Page 13: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Ein quadratischer MCS3-AlgorithmusGewinne Zeit — spendiere SpeicherStatt alle Teilfolgensummen getrennt zu berechnen, werden Summen längererFolgen auf Summen kürzerer Folgen zurückgeführt.

Sj,k(x) =

{xj j = kSj,k−1(x) + xk j < k

Kumulative Teilsummenberechnungmit (2×) zwei geschachtelten Zählschleifen: Rechenaufwand O(n2)double mcsss2 (double[] x) {

final int N = x.length;double[][] su = new double [N][N]; // nur superdiagonalfor (int j = 0; j < N; j++) { // Anfangsindex

su[j][j] = x[j]; // Induktionsanfangfor (int k = j+1; k < N; k++) // Endeindex

su[j][k] = su[j][k-1] + x[k]; // Induktionsschritt}double smax = 0.0;for (int j = 0; j < N; j++)

for (int k = j; k < N; k++) smax = Math.max (su[j][k], smax);return smax;

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Ein linearer MCS3-AlgorithmusEinbettung mit Zusatzziel — der „hat trick“Rekursionsgleichung für die beste mit xk endende Teilsumme:

Rk(x)def= max

jSj,k(x) =

{0 k = 0max(0,Rk−1(x) + xk) k > 0

Integrierte Summation und Doppelmaximierungmit einer einzigen Zählschleife: Rechenaufwand O(n1)

double mcsss1 (double[] x) {double smax = 0.0; // MCSSS in x[0:i]double rmax = 0.0; // Max. Summe x[?:i]for (int i = 0; i < x.length; i++) {

rmax = Math.max (0, rmax + x[i]); // innere Maximierungsmax = Math.max (smax, rmax); // äußere Maximierung

}return smax;

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Divide & Conquer

Problemreduktion

• Maximale Teilsumme in⟨x1, . . . , xn/2

⟩ rekursiver Aufruf #1

• Maximale Teilsumme, Berechnung mitdie xn/2 und xn/2+1 enthält Aufwand O(n1)

• Maximale Teilsumme in⟨xn/2+1, . . . , xn

⟩ rekursiver Aufruf #2

Exemplarische Zerlegung 〈x1, . . . , x5〉 ◦ 〈x6, . . . , x10〉Kalendertag 1 2 3 4 5 6 7 8 9 10Gewinn/Verlust +5 −8 +3 +3 −5 +7 −2 −7 +3 +5∑← /

∑→ −2 −7 +1 −2 −5 +7 +5 −2 +1 +6

je Aufruf zwei „halbschwere“ UnteraufrufeBestimmung der „grenzüberschreitenden“ MCS3

Aufrufbaum mit circa log2 n Ebenenje Ebene querbeet O(n) Operationen

RechenaufwandO(n · log2 n)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Ein kaskadierter MCS3-Algorithmusdouble mcsssDC (double[] x) { // Treibermethode

return mcsss (x, 0, x.length-1);}double mcsss (double[] x, int l, int r) { // Einbettmethode

if (l == r)return Math.max (0, x[l]); // Trivialfall

final int m = (l+r)/2; // die "Neue Mitte"final double mcsl = mcsss (x, l, m); // 1. Unteraufruffinal double mcsr = mcsss (x, m+1, r); // 2. Unteraufruffinal double mcsm = mcsGoLeft (x, m, l) // <----| max.Summe

+ mcsGoRight (x, m+1, r); // dto. |---->return Math.max (mcsm, Math.max (mcsl, mcsr)); // Rekombination

}double mcsGoLeft (double[] x, int m, int l) {

double reval = 0.0; // die max. Summefor (double sum = 0.0; m >= l; sum += x[m--]) // alle Teilsummen

if (sum > reval) reval = sum;return reval;

}double mcsGoRight (double[] x, int m, int r) {...} // s.o. fohrwerz

Page 14: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Algorithmen mit geometrischer Reduktion

SatzEs sei f ein D&C-Algorithmus mit derCharakteristik

Φbf (n) = α ·Φb

f (n/β) + O(nk)

und α ≥ 1, β > 1. Dann besitzt f die folgendeWachstumsordnung:

Φbf (n) =

O(nlogβ α) α > βk

O(nk log n) α = βk

O(nk) α < βk

Fertilität αWievieleTeilaufgaben?

Skalierung βWelcher Verein-fachungsfaktor?

Overhead kWas kostenReduktion undRekombinati-on?(k-polynomial)

Overhead O(nk)

{ Reduktion

f1 f2 f3 · · · fα{ Rekombination

fi (n/β)

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele — Rechenaufwand von D&C-AlgorithmenMaximale Teilsumme

ΦbmcsssDC(n) = 2 ·Φb

mcsssDC(n/2) + O(n1) = O(n1 log n)

Potenzberechnung

ΦbpowerDC(n) = 2 ·Φb

powerDC(n/2) + O(n0) = O(nlog2 2) = O(n1)

Drei halbe Aufrufe & linearer Overhead

Φbf (n) = 3 ·Φb

f (n/2) + O(n1) = O(nlog2 3) = O(n1.59)

Drei halbe Aufrufe & quadratischer Overhead

Φbf (n) = 3 ·Φb

f (n/2) + O(n2) = O(n2)

Fibonaccizahlen, Fakultätsfunktion ??

β 6> 1

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Algorithmen mit arithmetischer ReduktionSatzEs sei f ein D&C-Algorithmus mit derVerzweigungscharakteristik

Φbf (n) =

k∑`=1

α` ·Φbf (n − β`) n ≥ maxβ`

1 n < maxβ`

mit k ∈ IN und β1, . . . , βk ∈ IN. Dann gilt für dieAnzahl „trivialer“ Unteraufrufe des Aufrufbaums

Φbf (n) = O(ξn) ,

wobei 0 < ξ ∈ IR eine (maximale, reelle, positive)Nullstelle des charakteristischen Polynomsbezeichne:

p(x) =∑`

α` · x−β` − 1

Fertilität kWievieleTeilaufgaben?

Diskont β`Argumentabzugfür den `-tenSelbstaufruf

Kopien α`Vielfachheit des`-tenSelbstaufrufs

Beweis.Wir wählen den Ansatz

Φb(n) = ξn

für eine beliebige reelle, positive Wurzel ξ des charakteristischen Polynoms p(·)und setzen ihn in die rechte Seite der Aufwandsrekursion ein:

k∑`=1

α`Φbf (n − β`) =

k∑`=1

α`ξ(n−β`) = ξn ·

k∑`=1

α`ξ−β` = ξn · 1 = Φb

f (n)

Der Ansatz erfüllt also das Rekursionsgesetz. Auch jedes Vielfache und jedeSumme gültiger Ansätze erfüllen die Rekursionsgleichung, also auch dieLinearkombination

Φbc1,...,ck (n) =

k∑i=1

ci · ξni , ξi Nullstelle von p(x).

Durch passende Wahl der Koeffizienten ci kann nun dafür gesorgt werden, daß

Φbc1,...,ck (n) = 1 (∀0 < n < maxβ`)

gilt. Der Kombinationsansatz ist offenbar von der Ordnung O(ξn) für die größteNullstelle ξ von p(x).

Page 15: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiele — Trivialfallaufrufe arithmetischer Reduktionen

FakultätsfunktionDas Polynom p(x) = x−1 − 1 besitzt die Nullstelle ξ = 1

Φbfak(n) = O(1n) = O(1)

Die lineare Rekursion für die Fakultätsfunktion besitzt einen Aufrufbaumin Kettenform, also — unabhängig vom Parameter n — genau einenBlattknoten.

FibonaccizahlenDas Polynom p(x) = x−1 + x−2−1 besitzt die Nullstellen ξ = 1/2(1±

√5)

Φbfib(n) = O(ξn) = O(Fn)

Die kaskadierte Rekursion besitzt O(ξn) viele terminale Aufrufe, also einevon n in exponentieller Weise abhängige Anzahl. Wie wir aus Kapitel 3wissen, besitzt die Folge ξn = (1/2(1 +

√5))n die Größenordnung der

Fibonacci-Folge selbst!

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Wechselgeld und Gier

WechselgeldaufgabeWieviele Münzen aus dem Währungssystem

C def= {C1, . . . ,CK}

werden zur Bezahlung des Betrages n ∈ INmindestens benötigt?

Tüte Brötchenvom Meisterbäcker69 = 50+ 10+ 5+ 2+ 2︸ ︷︷ ︸

5 Münzen

Gieriger Algorithmus〈Algorithmus〉

1 TRIVIALFALL. Wenn n = 0 dann µ(n) = 02 REDUKTION. Berechne die nächste Zahlmünze:

c∗ def= max {c ∈ C | c ≤ n}

3 REKURSION. Berechne µ(n − c∗)4 REKOMBINATION.

Das Ergebnis ist µ(n) = 1+ µ(n − c∗)〈Algorithmus〉

Gierige Lö-sungversagt seitErfindung deslegendären 23-Cent-Stücks!

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Divide & Conquer I

Symmetrisch reduzierende RekursionEs wird die Aufgabe gemäß n = n0 + n1 zerlegt und über alle möglichenn0 < n minimiert.

µ(n) =

{1 n ∈ Cmin0<i≤n/2 (µ(i) + µ(n − i)) sonst

Beispiel 691 1 6 50 10 5 2 1 682 2 5 50 10 5 2 673 2 1 6 50 10 5 1 664 2 2 5 50 10 5 655 5 5 50 10 2 2 646 5 1 6 50 10 2 1 63... . . . . . .

...33 20 10 2 1 8 20 10 5 1 3634 20 10 2 2 7 20 10 5 35

RechenaufwandErmittlung von µ(n)initiiert (n − 1)Selbstaufrufe µ(i),1 ≤ i < n.

ZerlegungkombinatorischeExplosion vonMehrfachberechnungen

Page 16: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Divide & Conquer II

Asymmetrisch reduzierende RekursionEs wird die Aufgabe gemäß n = n0 + n1 zerlegt und über alle möglichenn0 ∈ C minimiert.

µ(n) =

{1 n ∈ Cmin` (1 + µ(n − c`)) sonst

Beispiel 691 1 vi 50 10 5 2 1 682 2 v 50 10 5 2 675 5 v 50 10 2 2 6410 10 v 50 5 2 2 5920 20 vi 20 20 5 2 2 4950 50 v 10 5 2 2 19

RechenaufwandErmittlung von µ(n)initiiert in der Regel |C|Selbstaufrufe µ(i),i ∈ C.

ZerlegungkombinatorischeExplosion vonMehrfachberechnungen

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Wechselgeldaufgabe mit DPSystematische einmalige Ermittlung aller Zwischenergebnisse µ(1), . . . , µ(n)

int changeDP (int n, int[] coin) {

int[] cmin = new int [n+1]; // Gedächtniscmin[0] = 0; // Leermenge

for (int cents = 1; cents <= n; cents++) { // Iterationint coins = cents; // geht immer

for (int k = 0; k < coin.length; k++) { // Münzvorratif (coin[k] > cents) continue; // zu groß!

final int used =1 + cmin [cents - coin[k]]; // Rekursion

if (used < coins)coins = used; // Bingo!

}cmin[cents] = coins; // Merken ...

}return cmin[n]; // Fazit

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Dynam. Programmierung — keine Mehrfachberechnung

GedächtnisFür jedes Zwischenergebnis wird vorab ein Speicherelementangelegt.

Kontrolle = IterationAlle Teilaufgaben werden nacheinander bearbeitet.• Lösungen wird in den Speicher geschrieben• zulässige Abfolge bei Speichertraversierung !

RekursionsformelSie steuert die Lösung der Teilaufgaben.• alle benötigten Teillösungen liegen bereits im Speicher.• keine Selbstaufrufe !!

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Levenshteindistanz zwischen Zeichenketten

T

R

I

E

B

T I G E R

TRIEBSubstitution

Insertion

Deletion

TIGER

TRIGER

TRIER

T R I E B

T I G E R

DefinitionIst A ein endliches Alphabet undsind x , y zwei Zeichenfolgen ausA?, so bezeichnet derLevenshtein-Abstand dLD(x , y)die minimale Anzahl vonElementaroperationen, mit denen xin y überführt werden kann.

Beispielberechnung� T I G E R

� 0 1 2 3 4 5T 1 0 1 2 3 4R 2 1 1 2 3 3I 3 2 1 2 3 4E 4 3 2 2 2 3B 5 4 3 3 3 3

Page 17: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Dynamische Programmierung

Levenshteinalgorithmus mit 2D-Speicherint levenshtein (String x, String y) {

final int nx = x.length();final int ny = y.length();int[][] d = new int [nx+1][ny+1];

for (int i = 0; i <= nx; i++) d[i][0] = i;for (int j = 0; j <= ny; j++) d[0][j] = j;

for (int i = 1; i <= nx; i++)for (int j = 1; j <= ny; j++) {

final int mismatch = (x.charAt(i-1) == y.charAt(j-1)) ? 0:1;

final int sub = d[i-1][j-1] + mismatch;final int del = d[i-1][j] + 1;final int ins = d[i][j-1] + 1;

d[i][j] = Math.min (sub, Math.min (del, ins));}

return d[nx][ny];}

RechenaufwandO(nx · ny )

SpeicheraufwandO(nx · ny )

SpeicherüberlagerungO(min{nx , ny})

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rundweg des Springers

1 60 39 34 31 18 9 6438 35 32 61 10 63 30 1759 2 37 40 33 28 19 836 49 42 27 62 11 16 2943 58 3 50 41 24 7 2048 51 46 55 26 21 12 1557 44 53 4 23 14 25 652 47 56 45 54 5 22 138×8 Feld 8250733 Aufrufe

RösslsprungaufgabeFinde zulässige Zugfolge, beginnend am Startfeld, ausschöpfend undohne Wiederholungen.

N 3 4 5 6 7 8 9(0,0) * * 8.840 248.169 7.151.179 8.250.733 ??(1,1) * *1.501 781.420 1.243.052 60.698.865 ?? ...

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Beispiel — Backtrackingprivate final static int[] X = {+2,+1,-1,-2,-2,-1,+1,+2};private final static int[] Y = {+1,+2,+2,+1,-1,-2,-2,-1};private static int dim; // BRETTGRÖSSEprivate static int[][] brett; // ZUGFOLGEMATRIXprivate static int calls = 0; // Aufrufzähler

static boolean backtrack // TREIBERAUFRUF:(int kx, int ky, int l) { // backtrack (i,j,1)

calls += 1;brett[kx][ky] = l; // VERSUCH ...if (l == dim*dim) return true; // TRIVIALFALL: FERTIG!

for (int move = 0; move < X.length; move++) {final int KX = kx + X[move]; // NEUE VERTIKALPOSITIONfinal int KY = ky + Y[move]; // NEUE HORIZONTALPOSITIONif (0 <= KX && 0 <= KY // ? Nord+Westgrenze

&& KX < dim && KY < dim // ? Süd+Ostgrenze&& brett[KX][KY] == 0 // ? freies Feld&& backtrack (KX, KY, l+1) // ? Fortsetzung

) return true; // ERFOLG!}brett[kx][ky] = 0; // ... UND IRRTUM:return false; // Geordneter Rückzug

}

Page 18: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Backtracking — keine überflüssigen Berechnungen

GedächtnisZwischenergebnisse und Suchraumposition• Teillösungen in dynamisch erzeugten Speicherstellen• Position im Aufrufbaum liegt im Laufzeitkeller

Kontrolle = RekursionAlle Teilaufgaben werden verschachtelt bearbeitet.• Lösungen wird in den Speicher geschrieben• Abfolge gesteuert durch Rekursionsgleichung

TeilaufgabeRekursionsgleichung auswerten unter Rückgriff auf Teillösungen• per Speicherabruf oder Selbstaufruf

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Gieriges Sortieren — durch AuswählenReduktion · Rekombination

Rekursiv mit Listen

public static IntNode selectSort (IntNode list) {if (list.next == null) return list; // TRIVIALFALLfinal IntNode XMIN = list.minElement (); // KLEINE HÄLFTElist = list.erase (XMIN); // GROSSE HÄLFTElist = selectSort (list); // REKURSIONXMIN.next = list; // REKOMBINATIONreturn XMIN;

}

Iterativ mit Listenrr s s r s

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Gieriges Sortieren — durch EinfügenReduktion · Rekombination

Rekursiv mit Listen

public static IntNode insertSort (IntNode list) {if (list.next == null) return list; // TRIVIALFALLfinal IntNode HEAD = list; // KLEINE HÄLFTEfinal IntNode TAIL = list.next; // GROSSE HÄLFTElist = insertSort (TAIL); // REKURSIONreturn list.insert (HEAD); // REKOMBINATION

}

Iterativ mit Listens r rr ss

Page 19: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Gieriges Sortieren

ReduktionKleine Hälfte (Einzelelement)große Hälfte (der Rest)

SpeicheraufwandO(n) ZusatzspeicherO(1) für „in-place“-Variante

RechenaufwandO(n2) für

{rekursivesiteratives

}Sortieren durch

{AuswählenEinfügen

}• (n − 1) Aufrufe/Schritte bis zum Trivialfall

• O(n) für das Auswählen des kleinsten ElementsO(n) für das Einfügen eines beliebigen Elements

• O(1) für den Zugriff auf das nächste ElementO(1) für das Anhängen des nächstkleineren Elements

Iteratives Sortieren durch Auswählen mit Feldern

1 2 i−1 i i+1 m. . . . . . n. . . . . .

maxindex

bereits sortiert noch nicht sortiert

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teile & Herrsche — durch MischenReduktion · Rekombination

Rekursiv mit Listen

public static IntNode mergeSort (IntNode list) {if (list.next == null) return list; // TRIVIALFALLfinal IntNode BELLY = list.center (); // REDUKTIONfinal IntNode TOP = mergeSort (BELLY.next); // UNTERAUFRUF 1BELLY.next = null;final IntNode BOT = mergeSort (list); // UNTERAUFRUF 2return IntNode.merge (BOT, TOP); // REKOMBINATION

}

rekursiver Abstieg

MischenHalbieren

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teile & Herrsche — durch MischenMischmethode für die Rekombination

Mischen zweier geordneter Listennach dem Reißverschlußprinzip in linearer Rechenzeit:

public static IntNode merge (IntNode r, IntNode s) {IntNode reval;if (r.data < s.data) { reval = r; r = r.next; }

else { reval = s; s = s.next; }reval.next = (r == null) ? s

: (s == null) ? r: IntNode.merge (r,s) ;

return reval;}

Rechenaufwand für das Sortieren durch MischenFertilität α = 2, Skalierung β = 2, Overhead k = 1

• O(1) Zerlegen und O(n) Mischen

O(n1 log n) wegen α = βk

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teile & Herrsche — durch QuicksortReduktion · Rekombination

Rekursiv mit Listen

rekursiver Abstieg

Triage VerkettenPivot

Rechenaufwand für den Quicksort-AlgorithmusFertilität α = 2∗, Skalierung β = 2∗, Overhead k = 1

• O(n) Pivot-Triage und O(1) Rückverketten

O(n1 log n) wegen α = βk

O(n2) Schlechtfallaufwand bei systematisch randständigen Angelpunkten

Rekursiv mit Feldern

1 2 i−1 i i+1 m. . . . . . n. . . . . .

bereits sortiert noch nicht sortiert bereits sortiert

Page 20: STRUKTURIERTES [height=4ex]img/javalogo PROGRAMMIEREN · RekursionsformenEffizienzEntwurfstechnikenD&CDPBTSortieren Korrekte,terminierende&effizienteRekursion 4+1goldeneRegelnrekursiverProgrammierung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Teile & Herrsche — durch Quicksort

Quicksort-Algorithmus mit Listenpublic static IntNode quickSort (IntNode list) {

if (list.next == null) return list; // TRIVIALFALLIntNode lo = null, eq = null, hi = null; // TRIAGE VIA ...final int pivot = list.data; // ANGELPUNKTfor ( ; list != null; list = list.next) // O(n)

if (list.data < pivot) lo = new IntNode (list.data, lo);else if (list.data > pivot) hi = new IntNode (list.data, hi);

else eq = new IntNode (list.data, eq);if (lo != null) lo = quickSort (lo); // UNTERAUFRUF 1if (hi != null) hi = quickSort (hi); // UNTERAUFRUF 2if (hi != null) eq.back().next = hi; // VERKETTE =+>if (lo != null) { // VERKETTE <+=+>

lo.back().next = eq;return lo;

} elsereturn eq;

}

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Rekursionsformen

Effizienz

Entwurfstechniken

Teile & Herrsche

Dynamische Programmierung

Backtracking (Trial & Error)

Sortieren

Zusammenfassung

Rekursionsformen Effizienz Entwurfstechniken D&C DP BT Sortieren Σ

Zusammenfassung

1. Funktionsdeklarationen mit Selbstaufrufen heißen rekursiv.

2. Je nach Struktur des Aufrufbaums unterscheiden wir schlichte, lineare,kaskadierte, geschachtelte und verschränkte Rekursion.

3. Durch die Einbettungstechnik lassen sich viele Aufgabenstellungen ineinfachere Formen (speziell Iteration) transformieren.

4. Der Rechen- und Speicheraufwand eines Algorithmus wird asymptotischdurch Landaus Komplexitätsklassen beschrieben.

5. Die Terminierung eines Algorithmus wird mit dem Majorantenkriteriumnachgewiesen.

6. Gierige Rekursion ist schnell, aber verfehlt u.U. das Optimalergebnis.

7. Teile&Herrsche-Rekursion ist wegen kombinatorischer Explosion desAufrufbaums (O(2n)) oft nicht die effizienteste Lösung.

8. Dynamische Programmierung verhindert zeitraubendeMehrfachberechnung durch iteratives Speichern der Zwischenergebnisse.

9. Backtracking verhindert das Bearbeiten überflüssiger Teilaufgaben durchKopplung von Zwischenspeicherung und rekursivem Abstieg.