U NIVERSIT ÄT B ERN I NFORMATIK VORLESUNG EI T YP UL B LATT 3 (1/3) AUSGABE HS 08 Lösungsvorschlag Serie 3 – Analyse von Algorithmen 1. (a) Aussage: Ein Grossteil der heute eingesetzten Software ist verifiziert und deshalb korrekt. Diese Aussage ist falsch. Nur ein geringer Anteil der heute verwendeten Software wird formal verifiziert. D.h. von einem Grossteil der eingesetzten Software ist nicht bewiesen, dass sie korrekt ist. (b) Aussage: Dank Tests werden alle in einer Software vorhandenen Fehler identifiziert. Diese Aussage ist falsch. Tests werden entworfen, um das Vorhandensein von Fehlern in ganz spezifischen Konfigurationen nachzuweisen. Tests beweisen jedoch nicht, dass ein System keine weiteren (versteckten) Fehler mehr hat. Die Praxis zeigt, dass selbst bei umfangreichen Tests auch nachträglich immer wieder Fehler gefunden werden. (c) Aussage: Die Worstcase-Zeitkomplexität von Binary Search für ein Array der Grösse n ist TW (n) = O(log n). Diese Aussage ist richtig. Binary Search findet im schlechtesten Fall (Worstcase) einen Wert in einem Array der Grösse n mit blog2 nc + 1 Vergleichen. Nimmt man den Vergleich als primitive Operation, so ergibt sich daraus TW (n) = O(log n). (d) Aussage: Die beiden Algorithmen A und B lösen ein bestimmtes Problem P. Algorithmus A hat die Worstcase-Zeitkomplexität TW (n) = O(n2 ) und Algorithmus B hat die Worstcase-Zeitkomplexität TW (n) = O(n log n). Da die Grössenordnungen der beiden Zeitkomplexitäten bekannt sind, steht fest, dass Algorithmus B für jeden Input zeiteffizienter ausgeführt wird als Algorithmus A. Diese Aussage ist falsch. Die Worstcase-Zeitkomplexitäten sind nur von ihrer Grössenordnung (LandauNotation) her bekannt. D.h. für Inputs ab einer gewissen Grösse, wird Algorithmus B mit TW (n) = O(n log n) im Worstcase effizienter sein als Algorithmus A mit TW (n) = O(n2 ). Für kleine Inputs muss dies allerdings nicht gelten, falls wir z.B. von folgenden exakten Komplexitätsfunktionen ausgehen, ist Algorithmus B erst ab einer Inputgrösse von n ≥ 283 effizienter: Algorithmus A: TW (n) = n2 + 2 = O(n2 ) Algorithmus B: TW (n) = 25n log2 9n + 20 = O(n log n) 2. Das Problem der Prüfung, ob ein Vektor A als Subvektor in einem anderen Vektor B enthalten ist, entstammt dem Fachgebiet der Mustererkennung (engl. pattern recognition). Der in dieser Aufgabe vorgestellte naive Probieralgorithmus löst dieses Problem zwar, ist mit seiner Worst-Case-Zeitkomplexität TW (n, m) = O(n · m) (vgl. untenstehende Herleitung) allerdings sehr ineffizient. Dieser Algorithmus ist daher für die Praxis nur bedingt geeignet. Es gibt Algorithmen, deren Laufzeit auch im ungünstigsten Fall (Worst Case) O(n + m) beträgt. Der sog. KMP-Algorithmus, benannt nach den Erfindern D.E. U NIVERSIT ÄT B ERN I NFORMATIK VORLESUNG EI T YP UL B LATT 3 (2/3) AUSGABE HS 08 Knuth, J.H. Morris und V.R. Pratt, sei hier als ein Beispiel erwähnt. In der Regel interessiert man sich v.a. für eine obere Schranke der Komplexität eines Algorithmus. Deshalb wird oft nur die Komplexität im Worst Case angegeben. Um die Average-Case-Komplexität bestimmen zu können, reicht es oft nicht aus, nur den Algorithmus zu analysieren. Man muss zusätzlich für eine konkrete Anwendung die Inputs und deren Häufigkeiten analysieren, um bestimmen zu können, wie der durchschnittliche Input überhaupt aussieht. Und diese Bestimmung des durchschnittlichen Inputs kann z.T. aufwändig sein. (a) Zeitkomplexität des naiven Probieralgorithmus: Als elementare Operation zählt man den Vergleich von zwei Elementen aus den Vektoren. Im ungünstigsten Fall werden die äussere Schleife (n − m + 1)-mal und die innere Schleife bis zu m-mal durchlaufen. Es gilt also: TW (n, m) = (n − m + 1) · m = nm − m2 + m = O(n · m) Da der Vektor A maximal so gross wie der Vektor B sein kann, sind die beiden Längen m und n voneinander abhängig. Man kann desshalb in diesem Beispiel davon ausgehen, dass m = 12 n gilt und somit: 1 1 1 1 1 1 1 TW (n, m) = (n − n + 1) · n = n2 − n2 + n = n2 + n = O(n2 ) 2 2 2 4 2 4 2 (b) Platzkomplexität des naiven Probieralgorithmus: Um die Platzkomplexität zu bestimmen, muss man zuerst definieren, welche atomaren Variablen man zählt. Die Analyse des Algorithmus ergibt z.B. folgende atomaren Variablen: • • • • • Vektor A mit m atomaren Variablen Vektor B mit n atomaren Variablen Laufvariable i der äusseren Schlaufe als 1 atomare Variable Laufvariable j der inneren Schlaufe als 1 atomare Variable Resultat vom Typ Boolean als 1 atomare Variable Die Speicherplatzkomplexität ist also: S(n, m) = n + m + 3 = O(n + m) Da der Vektor A maximal so gross wie der Vektor B sein kann, sind die beiden Längen m und n voneinander abhängig. Man kann desshalb davon ausgehen, dass maximal m = n gilt und somit: SW (n, m) = n + n + 3 = O(n) 3. Es muss gezeigt werden, dass die Umrechung des Logarithmus zur Basis a in einen Logarithmus zur Basis b nur eines multiplikativen Faktors k > 0 bedarf: Aus der Mathematik weiss man, dass loga x = log1 a · logb x ist (a, b > 1). b Da k = log1 a eine positive Konstante ist, sind loga x und logb x von der gleichen b Grössenordnung. U NIVERSIT ÄT B ERN I NFORMATIK VORLESUNG EI T YP UL B LATT 3 (3/3) AUSGABE HS 08 4. Beispiele für einfache Algorithmen quadratischer Zeitkomplexität: • Bubble-Sort, ein naiver Algorithmus zum Sortieren von n ganzen Zahlen: void Algorithm bubbleSort(int[] array): // Input : Array/Vektor ganzer Zahlen der Grösse n // Output: Input-Array wird als Seiteneffekt sortiert (inplace Sort) // Zweck : Sortiert einen Array ganzer Zahlen aufsteigend for (int i=0; i<n-1; i++) // bubble up i-th record for (int j=n-1; j>i; j--) // bubble to the front if (array[j] < array[j-1]) // records in wrong order? swap(array, j, j-1); // swap the two records Die Inputgrösse sei hier n. Die Zeitkomplexität ist TB (n) = TA (n) = TW (n) = O(n2 ). Es gibt effizientere Algorithmen, weshalb Bubble-Sort für die Praxis nur bedingt geeignet ist. • Matrix-Vektor-Multiplikation: Geht man davon aus, dass die Multiplikation zweier Zahlen eine atomare Operation sei, so ist die bekannte Mulitplikation einer quadratischen nxn-Matrix mit einem Vektor der Grösse n ein Algorithmus mit quadratischer Zeitkomplexität. Vektor Algorithm mult(Matrix M, Vektor v): // Input : Quadratische Matrix der Grösse nxn, Vektor v der Grösse n // Output: Vektor der Grösse n // Zweck : Berechnet das Produkt M*v Vektor result = Nullvektor der Grösse n for (int i=0; i<n-1; i++) for (int j=0; j<n-1; j++) result[i]=result[i]+M[i,j]*v[i] return result Die Inputgrösse sei hier n. Die Zeitkomplexität ist TB (n) = TA (n) = TW (n) = O(n2 ).