Christian Mansky mansky@wist.uni-linz.ac.at Design - Fallstudien Christian Mansky mansky@wist.uni-linz.ac.at
Übersicht Das erste Problem und ein einfacher Algorithmus erster Lösungsversuch mit quadratischer Laufzeit mit linearer Laufzeit Suche in Zeichenfolgen: Aufgabenbeschreibung Brute Force Der Boyer-Moore Algorithmus (1) Der Boyer-Moore Algorithmus (2) Der Binomialkoeffizient: Die Aufgabenstellung Ein rekursiver Algorithmus Ein iterativer Algorithmus Ein linearer iterativer Algorithmus
Das Problem und ein einfacher Algorithmus Gegeben ist ein Eingabevektor x mit n Elementen (vom Typ Float). Gesucht ist die maximale Summe die in einem zusammenhängenden Subvektor der Eingabe gefunden werden kann.
Ein erster Lösungsversuch maxsofar = 0 for i= [0,n) for j= [i,n) sum = 0 for k= [i,j] sum += x[k] /* sum is sum of x[i..j] */ maxsofar = max (maxsofar, sum) Der Algorithmus hat kubische Laufzeit. Messungen auf meinem Computer: Bei n= 10.000 beträgt die Laufzeit ca. 14,5 Minuten. Bei n= 100.000 beträgt die Laufzeit schon ca. 10 Tage.
Ein Algorithmus mit quadratischer Laufzeit maxsofar = 0 for i= [0,n) sum = 0 for j= [i,n) sum += x[j] /* sum is sum of x[i..j] */ maxsofar = max (maxsofar, sum) Der Algorithmus hat quadratische Laufzeit. Das bedeutet bei n = 10.000 läuft der Algorithmus 797 ms. Bei n = 100.000 hat der Algorithmus eine Laufzeit von ca. 1,3 Minuten.
Ein Algorithmus mit linearer Laufzeit maxsofar = 0; maxendinghere = 0; for i= [0,n) maxendinghere = max (maxendinghere+x[i], 0); maxsofar = max (maxsofar, maxendinghere); Angenommen das Problem ist für x[0..i-1] gelöst: Das maximale Subarray in den ersten i Elementen befindet sich entweder in den ersten i-1Elementen (gespeichert in maxsofar), oder oder es endet auf Position i (gespeichert in maxendinghere) Die Laufzeit bei n= 1.000.000 Elementen beträgt 32 ms!
Suche in Zeichenfolgen: Aufgabenbeschreibung Gegeben: String text = „A string consisting ...“ String pattern =„sting“ Gesucht: int pos = 15
Suche in Zeichenfolgen: Brute Force i=1; pos = 0; while (i<length(text)-length(pattern)+1) & (pos=0) j=1 while (j<=length(pattern)) & (text[i+j-1] = pattern[j]) j=j+1 end if (j>length(pattern)) pos=i end; i:=i+1 /* Ergebnis in pos */ Laufzeitkomplexität: O(n^2)
Suche in Zeichenfolgen: Der Boyer-Moore Algorithmus (1) shift[s] = length(pattern)-1 shift[t] = length(pattern)-2 shift[i] = length(pattern)-3 shift[n] = length(pattern)-4 shift[g] = length(pattern)-5
Suche in Zeichenfolgen: Der Boyer-Moore Algorithmus (2) for i=[0,MAXCHAR] shift[i]=length(pattern) for j=[1,length(pattern)] shift[ORD(pattern[j])]= length(pattern) - j i = j = length (pattern) repeat if text[i]=pattern[j] i--; j--; else h=shift[ORD(text[i])] if (h>=length(pattern)-j+1) i=i+h else i=i+length(Pattern)-j+1 j = m; until (j=0) | (i>length(text)) If (j=0) pos=i+1; else pos=-1; return pos;
Der Binomialkoeffizient: Die Aufgabenstellung
Der Binomialkoeffizient: Ein rekursiver Algorithms binCoeff (int n, int k) { if (k==0 || k==n) return 1; else return binCoeff (n-1,k-1) + binCoeff (n-1, k); } + Einfacher Algorithmus - Ergebnisse die bereits berechnet wurden, werden nochmals berechnet - Sehr Laufzeitkomplex: O(2^n/n)
Der Binomialkoeffizient: Ein iterativer Algorithms /*Invariante: bc[n+1][k+1] wird mit 0 initialisiert*/ for i=[0, n] bc[i][0] = 1; bc[i][1] = i; for i=[1,n] for j=[2,k] bc [i][j] = bc[i-1][j-1]+bc[i-1][j]; } /*Ergebnis in bc[n][k]*/ Die Zeitkomplexität beträgt O(n*k)
Der Binomialkoeffizient: Ein linearer iterativer Algorithms nenner = zaehler1 = zaehler2 = 0 for i=[1,n] nenner *= i for j=[1,k] zaehler1 *= j for h=[1,n-k] zaheler2 *= h bc = i/(zahler1*zahler2) Verzicht auf Rekursion, wenn eine offensichtliche iterative Lösung existiert. Umgehe aber Rekursion nicht um jeden Preis! Probleme die ihrem Wesen nach eher rekursiv sind, können auch rekursiv implementiert werden.
Danke für die Aufmerksamkeit!