Beim Logarithmischen Kostenmaß wird, im Gegensatz zum EKM, die Stelligkeit der Werte berücksichtigt und mit in die Laufzeit eingerechnet. Beispiel: R1 := R2 ∗ (R3), wobei R2 den Wert 5, R3 den Wert 10 und R10 den Wert 1000 hat. Sei L die Länge der Binärdarstellung, so ergibt sich die Laufzeit im Logarithmischen Kostenmaß: L(5) + L(10) + L(1000) = 3 + 4 + 10 = 17. Es werden also 17 Zeiteinheiten benötigt. Allgemein kostet ein Register mit dem Inhalt k L(k) Platzeinheiten. Wir betrachten jetzt Laufzeit und Speicherplatz einer Registermaschine bei einer Eingabe x ∈ Z∗ . Hierbei steht die Eingabefolge von ganzen Zahlen in den ersten Registern. Definition 1.2.3. Die Laufzeit einer RAM bei Eingabe x ∈ Z∗ , t(x), ist die Summe der Zeitkosten aller ausgeführten Befehle bis die Maschine hält. Den Speicherplatz bei der Eingabe von x, s(x), erhält man, indem man in einem Schritt die Summe der Kosten für alle benutzten Register berechnet und dann das Maximum über alle Schritte nimmt. Üblicherweise wird nicht mit t und s für jede einzelne Eingabe gerechnet, sondern jeder Eingabe x wird als Funktion die Größe der Eingabe g(x) = n, n ∈ N zugeordnet. Beispiel: Beim Sortieren von n Zahlen wird als Größe der Eingabe g(x) die Anzahl der Zahlen in x genommen. Das wurde bereits bei den bisherigen Beispielen für Sortieralgorithmen berücksichtigt. Alternativ kann man die Summe der Längen der Binärdarstellungen aller Eingabezahlen als Größe der Eingabe betrachten. Komplexität Komplexität ist der Überbegriff für die unterschiedlichen Komplexitätsmaße wie Laufzeit, Speicher u.a. Wir unterscheiden 3 Fälle: 1. Im schlechtesten Fall: Um die Komplexität im schlechtesten Fall zu bestimmen, betrachten wir alle Eingaben der Größe n und nehmen über alle diese Eingaben das Maximum. T (n) = max t(n) g(x)=n S(n) = max s(n) g(x)=n Die Komplexität der Sortieralgorithmen entspricht der Anzahl der nötigen Vergleiche. Die für die Algorithmen Mergesort, Sortieren durch Auswahl und mittels Permutationen bereits angegebenen Schranken gelten auch im schlechtesten Fall. 2. Im Mittel: Hier gilt, daß T (n) der Erwartungswert von t(x) ist, wobei x eine Eingabe der Länge n ist. Dazu ist eine Wahrscheinlichkeitsverteilung auf 12 der Menge der Eingaben notwendig. Bei der Analyse vom deterministischen Quicksort-Algorithmus nehmen wir an, dass jede Permutation der Eingabefolge gleichwahrscheinlich ist. 3. Erwartete Laufzeit bei Zufallsalgorithmen: Zufallsalgorithmen werden auch probabilistische oder randomisierte Algorithmen genannt. Ein solcher Algorithmus trifft Entscheidungen, die vom Zufall abhängen. Er benutzt dazu einen Zufallsgenerator. Die Registermaschine RAM benutzt den Operator RAN D(n), der eine gleichverteilte Zufallszahl zwischen 1 und n liefert. Die erwartete Laufzeit für die Eingabe x wäre dann der Erwartungswert der Laufzeit, gebildet bezüglich der Zufallsentscheidung. Wir betrachten den Sortieralgorithmus Quicksort bezüglich der mittleren und der erwarteten Laufzeit. 1. Quicksort ist deterministisch, wenn das Pivot-Element deterministisch gewählt wird, z.B. immer das erste Element der Folge. Die mittlere Laufzeit, d.h., die über alle Eingabefolgen gemittelte Laufzeit, beträgt Θ(n log n). 2. Beim randomisierten Quicksort ist die erwartete Laufzeit für jede Eingabe Θ(n log n). Man erhält also diese Laufzeit, unabhängig davon, wie “schlecht“ die Eingabefolge aussieht. Für gleiche Eingaben kann es unterschiedliche Laufzeiten geben. 1.2.2 Turingmaschine Die Turingmaschine stellt ein weiteres Berechnungsmodell dar. Die Laufzeit ist gleich der Anzahl der Schritte, der Speicherplatz gleich der Anzahl der benutzten Zellen. Man muss hier nicht über EKM oder LKM nachdenken, da jeder Schritt (die gleiche) konstante Zeit braucht, weil in jedem Schritt der Kopf um eine Stelle nach rechts oder links bewegt werden kann und jede Speicherzelle den gleichen konstanten Platz braucht. Satz 1.2.4. Zu einem Algorithmus der Laufzeit T (n)im Logarithmischen Kostenmaß (LKM) auf einer Registermaschine existiert eine äquivalente Turingmaschine der Laufzeit O(T (n)5 ). Beispiel. Ein Algorithmus mit der Laufzeit O(n2 ) im LKM auf einer RAM könnte auf einer Turingmaschine mit der Laufzeit O(n10 ) implementiert werden. Die Laufzeit steigt zumindest nicht exponentiell. Man sagt dazu auch, dass die Laufzeit auf einer Registermaschine im LKM und auf der Turingmaschine sind polynomiell verwandt (sie stehen in polynomieller Beziehung). Insbesondere gilt: 13 Ein Problem, dass in polynomieller Zeit (d.h. Zeit O(nk ) für festes n ∈ N)) auf RAM im LKM lösbar ist, ist auch auf einer Turingmaschine in polynomieller Zeit lösbar. Probleme, die auf einer Turingmaschine in polynomieller Zeit lösbar sind, gehören zur Klasse P. Darstellung der Algorithmen 1. Man verwendet eine Art höherer Programmiersprache mit if-, whileu.a. Anweisungen sowie Rekursionen. 2. Oft werden Algorithmen auch umgangssprachlich beschrieben. 3. Man verwendet eine Mischung aus höherer Programmiersprache und Umgangssprache, den so genannten “Pseudocode“. Von Vorteil ist, daß es weniger Arbeit macht, wenn das Problem nicht exakt in eine Programmiersprache umgesetzt wird. Weiterhin wird die Lesbarkeit erhöht. Platzbedarf und Laufzeit lassen sich auch für so angegebene Algorithmen definieren oder zumindest diskutieren. Meist ist die Komplexität auch ohne eine Übersetzung in RAM-Code analysierbar in Form von O oder Θ. Typische Funktionen Es handelt sich um Funktionen, die häufig bei der Komplexitätsanalyse auftreten. Sie sind aufsteigend geordnet. log log n log n √ n n n log n n2 n3 n4 2n n! 2 2n “logarithmisch“ “linear“ polynomiell “quadratisch“ “kubisch“ “biquadratisch“ exponentiell Fakultät Anmerkung 1: exponentiell n n2 2 ≤ n! ≤ nn = 2n log n Anmerkung 2: log n wächst schwächer als jedes nα , α = 0, das gilt auch für α = 21 . 14 Kapitel 2 Sortieren, Suchen 2.1 Bemerkungen zum Sortieren Der Vergleich der bisher besprochenen Sortieralgorithmen bezüglich Zahl der Vergleiche und RAM-Laufzeit ergibt: Maximum Auswahl Mergesort rand. Quicksort Anzahl der Vergliche ∼ 12 n2 ∼ n log n ∼ 1,38 · n log n RAM-Laufzeit (EKM) 2,5 · n2 12 · n log n 9 · n log n Die höheren Werte bei der RAM-Laufzeit ergeben sich aus dem Auflösen der Rekursionen. Dazu wird ein Laufzeitstack angelegt. Dieser zusätzlich benötigte Platz ist die Größe des Laufzeitstacks und damit gleich der Tiefe der Rekursionen. Definition 2.1.1 (Allgemeine Sortieralgorithmen). Allgemeine Sortieralgorithmen sind solche, die nur auf Vergleichen zwischen Elementen der Eingabefolgen beruhen. Beispiele sind die bisher besprochenen Sortieralgorithmen. Als Beispiel für einen nicht algorithmischen Sortieralgorithmus betrachten wir eine Folge bestehend aus 1000 Bit. Hier wird natürlich nicht wie bisher beschrieben sortiert. Stattdessen wird die Folge durchlaufen, die Anzahl der Nullen und Einsen gezählt und die entsprechenden Anzahlen ausgegeben. Elemente werden nicht verglichen. Die Laufzeit ist O(n). Der Vorteil der allgemeinen Sortieralgorithmen liegt darin, dass man sie für alle Daten aus jedem beliebigen, linear geordneten Universum (Datenbereich) (U, ≤) nutzen kann. Darstellung durch einen Vergleichsbaum Allgemeine Sortieralgorithmen sind darstellbar durch einen Vergleichsbaum. 15 ai < aj al< ak ar < at ... Der Vergleichsbaum endet bei dem Blatt,das der Permutation der Eingabefolge entspricht. Die richtige Permutation stellt der Vergleichsbaum durch Folge der Abfragen fest. Beispiel für Mergesort für n=3 a1 | a2 a3 Zunächst werden Teilfolgen gebildet. 1. Vergleich: Wenn ja, geht a2 a3 a2 ≤ a3 als gemischte Teilfolge zurück. ja nein a1 ≤ a2 ja a1 ≤ a3 nein ja a1 ≤ a3 1 2 3 ja 2 1 3 nein a1 ≤ a2 1 3 2 ja nein 3 1 2 2 3 1 16 nein 3 2 1 Die inneren Knoten im Baum entsprechen den Vergleichen, die ein Algorithmus durchführt. Ein Blatt entspricht einer Permutation der Eingabefolge. Für n Elemente erhält man somit n! Blätter. Definition 2.1.2 (Untere Schranke). Eine untere Schranke entspricht einer Aussage der Form: Jeder Algorithmus braucht mindestens T (n) Zeit (oder S(n) Platz), um das Problem X für eine Eingabe der Größe n zu lösen. Beispiel: Sei das Problem X das Finden des Maximum in einer Eingabe der Länge n. Um die untere Schranke zu bestimmen stellt sich die Frage: Wie viele Vergleiche braucht jeder Algorithmus, um das Maximum zu bestimmen? Beim Standardalgorithmus benötigt man n − 1 Vergleiche. (Das aktuelle Maximum wird festgehalten und immer mit dem nächsten Element verglichen.) (n − 1) ist auch die untere Schranke, das es keinen Algorithmus gibt, der das schneller erledigt. Folgende Überlegung gibt uns eine intuitive Begründung dafür: Bei einem Sportwettkampf werden Zweikämpfe ausgetragen (vielleicht Tennis), um den Sieger zu ermitteln. Jemand, der nie ein Spiel verloren hat, erwartet dann auch der Gesamtsieger zu sein. Alle anderen müssen also jeweils mindestens ein Spiel verloren haben. Es müssen also (n − 1) Spiele stattfinden. Eine vergleichsbasierte Maximumsuche braucht also mindestens (n − 1) Vergleiche. 17