Algorithmen und Datenstrukturen 1 1. Vorlesung Ralf Der Universität Leipzig Institut für Informatik [email protected] aufbauend auf den Kursen der letzten Jahre von E. Rahm, G. Heyer, G. Brewka ,Uwe Quasthoff Inhaltsverzeichnis 1. Einführung • Typen von Algorithmen • Komplexität von Algorithmen 2. Einfache Suchverfahren in Listen 3. Verkette Listen, Stacks und Schlangen 4. Sortierverfahren • Elementare Verfahren • Shell-Sort, Heap-Sort, Quick-Sort • Externe Sortierverfahren 5. Allgemeine Bäume und Binärbäume • Orientierte und geordnete Bäume • Binärbäume (Darstellung, Traversierung) 6. Binäre Suchbäume 7. Mehrwegbäume Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 2 Leistungsbewertung Zum Erwerb des Übungsscheins ADS1 (unbenotet) • Übungsschein bei erfolgreicher Teilnahme an der Klausur. Diese findet zum Termin der letzten (eventuell vorletzten) Vorlesung statt. Lösung der Übungsaufgaben ist nicht Bedingung für Zulassung zur Klausur. Informatiker (Diplom), 3. Semester • • Übungsschein ADS1 ist zu erwerben (Voraussetzung für Vordiplomsklausur) Klausur über Modul ADS (= ADS1+ADS2) im Juli als Teilprüfung zur Vordiploms-Fachprüfung "Praktische Informatik" Mathematiker / Wirtschaftsinformatiker • Übungsschein ADS1 erforderlich Magister mit Informatik als 2. Hauptfach • • kein Übungsschein erforderlich, Erwerb ist aber möglich. (Nur ein ÜS aus Dig Inf. oder Progr.Progr.Sprachen oder ADS1 erforderlich) Prüfungsklausur zu ADS1 + ADS2 im Juli Magister mit Informatik im Nebenfach und Bachelor Studenten • • Prüfungsleistung (benotet) zu ADS1 wird durch die Klausur (s.o.) erbracht. Bemerkung für NF Magister: Besser Kurs Dig.Inf. für Wirtschaftsinformatiker (über zwei Semester) bei Dr. Richter besuchen. Dieser ist äquivalent zu unseren Kursen Dig. Inf. + ADS 1. Wenn Sie die Vorlesungen bei den Diplominformatikern besuchen, dann müssen Sie die Klausur zu ADS1 als Prüfungsleistung schreiben. Andere Nebenfächler wie NF-Magister Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 3 ¼bungsaufgaben • Es sind fünf Serien von Übungsaufgaben zu bearbeiten. • Diese finden sich im Zweiwochenrhythmus auf den Seiten im Netz. http://wortschatz.informatik.uni-leipzig.de/asv/lehre/ws-0506/Der-ADS1-Inh-ws-0506.html • Nur die Serien 2 und 4 werden zu Ihrer Information korrigiert. Bearbeitungszeit 2 Wochen. Abgabe vor der Vorlesung hier. • Musterlösungen für alle Serien werden im Netz zur Verfügung gestellt. • Bearbeitung aller Übungsaufgaben ist optional, wird aber dringend empfohlen. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 4 ¼bungen Übungen finden im 2-Wochenrhythmus statt (A bzw. B Woche). Es gibt 8 Übungsgruppen. Zeit und Ort s. „Stundenplan“: http://www.informatik.unileipzig.de/stdplan/stdplan.phtml?cmd=sem_plan&new_sem=20052006&cmdtype=2 Beginn am 11. 10. 05. Einteilung in die Übungsgruppen durch „Selbstorganisation“. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 5 Literatur T. Ottmann, P. Widmayer: Algorithmen und Datenstrukturen, Reihe Informatik, Band 70, BI-Wissenschaftsverlag, 3. Auflage, Spektrum-Verlag, 1996 M.A. Weiss: Data Structures & Algorithm Analysis in Java. Addison-Wesley 1999, 2. Auflage 2002 Weitere Bücher V. Claus, A. Schwill: Duden Informatik, BI-Dudenverlag, 2. Auflage 1993 D.A. Knuth: The Art of Computer Programming, Vol. 3, Addison-Wesley, 1973 R. Sedgewick: Algorithmen. Addison-Wesley 1992 G. Saake, K. Sattler: Algorithmen und Datenstrukturen - Eine Einführung mit Java. dpunkt-Verlag, 2002 A. Solymosi, U. Gude: Grundkurs Algorithmen und Datenstrukturen. Eine Einführung in die praktische Informatik mit Java. Vieweg, 2000, 2. Auflage 2001 Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 6 EinfÜhrung Algorithmen stehen im Mittelpunkt der Informatik Wesentliche Entwurfsziele bei Entwicklung von Algorithmen: • Korrektheit • Terminierung • Effizienz Unser Schwerpunkt Wahl der Datenstrukturen v.a. für Effizienz entscheidend Abstrakte Datentypen (ADTs): Zusammenfassung von Algorithmen und Datenstrukturen Vorlesungsschwerpunkte: • Entwurf von effizienten Algorithmen und Datenstrukturen • Analyse ihres Verhaltens Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 7 Wozu Gedanken Über Datenstrukturen? Funktional gleichwertige Algorithmen weisen oft erhebliche Unterschiede in der Effizienz (Komplexität) auf. Algorithmen verarbeiten Daten. Bei der Verarbeitung soll effektiv mit den Daten umgegangen werden. Mögliche Aufgaben sind: • Schnell den richtigen Datensatz ermitteln (z. B. Nachschlagen im Telefonbuch) • Hinzufügen und Löschen von Datensätzen • Sortieren eines Datenbestandes. Die Effizienz hängt bei großen Datenmengen ab von • der internen Darstellung der Daten und • dem verwendeten Algorithmus. Möglicherweise hängen beide Teilfragen eng zusammen. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 8 Beispiel: Telefon-CD Speicherplatz auf der CD-ROM: ca. 700 MB Suchmöglichkeiten: kombiniert nach Name und Ort Abschätzung des Rohdatenvolumens: • 40 Millionen Einträge zu je 35 Zeichen, d.h. ca. 1.4 GB ASCII-Text ALSO: Wir brauchen eine Datenstruktur, • die einen schnellen Zugriff (über einen sog. Index) erlaubt und • zusätzlich die Daten komprimiert. Außerdem gilt es zu beachten, dass der Zugriff auf die CD-ROM wesentlich länger dauert als ein Zugriff auf die Festplatte. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 9 Beobachtungen zur Telefon-CD Zum Nachschlagen könnte man ein Programm benutzen, welches die vollständige Verwaltung der Einträge erlaubt: Suchen, Einfügen und Löschen. Die zusätzlich vorhandenen Funktionen werden einfach nicht angeboten. Aber: Weil sowieso nur das Suchen erlaubt ist, können wir vielleicht eine Datenstruktur verwenden, die zwar extrem schnelles Suchen in einer komprimierten Datei erlaubt, aber möglicherweise kein Einfügen. Schlussfolgerung: Soll unsere Datenstruktur nur bestimmte Operationen erlauben, so lohnt die Suche nach Strukturen mit hoher Effizienz. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 10 Effizienz: Zeit und Speicher Die Abarbeitung von Programmen (Software) beansprucht 2 Ressourcen: Zeit und Hardware (wichtig: Speicher). Wie steigt dieser Ressourcenverbrauch bei größeren Problemen (d.h. mehr Eingabedaten)? Es kann sein, dass Probleme ab einer gewissen Größe praktisch unlösbar sind, weil • Ihre Abarbeitung zu lange dauern würde (z.B. >100 Jahre) oder • Das Programm mehr Speicher braucht, als zur Verfügung steht. Wichtig ist auch der Unterschied zwischen RAM und externem Speicher, da der Zugriff auf eine Festplatten ca. 100.000 mal langsamer ist als ein RAM-Zugriff. Deshalb werden manche Algorithmen bei Überschreiten des RAM so langsam, dass sie praktisch nutzlos sind. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 11 KomplexitÄt von Algorithmen Wesentliche Maße: • • Rechenzeitbedarf (Zeitkomplexität) Speicherplatzbedarf (Speicherplatzkomplexität) Programmlaufzeit von zahlreichen Faktoren abhängig • • • • Eingabe für das Programm Qualität des vom Compiler generierten Codes und des gebundenen Objektprogramms Leistungsfähigkeit der Maschineninstruktionen, mit deren Hilfe das Programm ausgeführt wird Zeitkomplexität des Algorithmus, der durch das ausgeführte Programm verkörpert wird Bestimmung der Komplexität • • • Messungen auf einer bestimmten Maschine Aufwandsbestimmungen für idealisierten Modellrechner (Bsp.: Random-Access-Maschine oder RAM) Abstraktes Komplexitätsmaß zur asymptotischen Kostenschätzung in Abhängigkeit zur Problemgröße (Eingabegröße) n Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 12 Asymptotische Kostenma¿e Festlegung der Größenordnung der Komplexität in Abhängigkeit der Eingabegröße: Best Case, Worst Case, Average Case Meist Abschätzung oberer Schranken (Worst Case): Groß-Oh-Notation Zeitkomplexität T(n) eines Algorithmus ist von der Größenordnung n, wenn es Konstanten n0 und c > 0 gibt, so daß für alle Werte von n > n0 gilt: T(n) ≤ c · n man sagt "T(n) ist in O(n)" bzw. "T(n)∈O(n)" oder "T(n) = O(n)" Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 13 Allgemeine Definition: O Klasse der Funktionen O(f), die zu einer Funktion (Größenordnung) f gehören ist O(f) = {g | ∃c > 0 ∃n0 > 0: ∀n ≥ n0 : g(n) ≤ c · f(n)} Beispiel: 6n4 + 3n3 - 7 n ∈ O(n4) zu zeigen: 6n4 + 3n3 - 7 ≤ c n4 für ein c und alle n > n0 -> 6 + 3/n - 7 / n4 ≤ c Wähle also z.B. c = 9, n0 = 1 Ein Programm, dessen Laufzeit oder Speicherplatzbedarf O(f(n)) ist, hat demnach eine Wachstumsrate ≤ f(n) Beispiel: g(n) = O(n2) oder g(n) = O(n · log n) ? g(n) = O(n log n) -> g(n) = O(n2) , jedoch gilt natürlich O(n log n) ≠ O(n2) Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 14 Gro¿-Omega-Notation: g ∈Ω (f) oder g = Ω (f) drückt aus, dass f mindestens so stark wächst wie g (untere Schranke) Definition: Ω (f) = {h | ∃ c > 0 : ∃ n0 > 0 : ∀ n ≥ n0 : h(n) ≥ c f(n)} alternative Definition (u.a. Ottmann/Widmayer): Ω (f) = {h | ∃ c > 0 : ∃ unendlich viele n: h(n) ≥ c f(n)} Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 15 Exakte Schranke gilt für eine Funktion g sowohl g ∈ O(f) als auch g ∈ Ω (f), so schreibt man g ∈ Θ(f) g aus Θ(f) bedeutet also: die Funktion g verläuft ab einem Anfangswert n0 im Bereich [c1f, c2f] für geeignete Konstanten c1, c2 Merke: Ist T(n) ein Polynom vom Grade p dann ist T(n) ∈ Θ(np), d.h. die Wachtsumsordnung ist durch die höchste Potenz im Polynom gegeben. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 16 Polynomiales Wachstum Ist T(n) ein Polynom der Ordnung p dann gilt: ( ) T(n) = (np) Beweis O n p : Sei p T (n ) = ∑ ak n k = a p n p + ... + a0 . n p ausklammern : k =0 1 1 T (n ) = n U (n ) mit U (n ) = a p + a p-1 + ... + a 0 p und lim U (n ) = a p n →∞ n n Für ein beliebiges ε > 0 wählen wir c = a p + ε p Es läßt sich damit immer ein n0 > 0 finden so dass T (n ) < cn p ∀ n > no . ( ) Beweis Ω n p analog. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 17 Wichtige Wachstumsfunktionen Kostenfunktionen O (1) O (log n) O (n) O (n log n) O (n2) O (n3) O (2n) Ralf Der konstante Kosten logarithmisches Wachstum lineares Wachstum n-log n-Wachstum quadratisches Wachstum kubisches Wachstum exponentielles Wachstum Algorithmen und Datenstrukturen 1-WS05 / 06 18 Wachstumsverhalten Ressourcenverbrauch in Anhängigkeit von der Problemgröße n bei verschiedenen Kostenfunktionen Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 19 ProblemgrÖ¿e bei vorgegebener Zeit Welche Problemgröße kann bei verschiedenen Kostenfunktionen in vorgegebener Zeit bearbeitet werden? Annahme: Zeit für Problem der Größe n = 1 ist 1 ms. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 20 ProblemgrÖ¿e in AbhÄngigkeit der Rechengeschwindigkeit Welche Problemgröße kann bei verschiedenen Kostenfunktionen mit Rechnern verschiedener Geschwindigkeit bearbeitet werden? Für Problem der Größe n seien die Rechengeschwindigkeiten T(n ) bzw. TK (n ) (K - fache Geschwindigkeit), also T (n ) = K TK (n ) Bei gleicher Rechenzeit löst Rechner 2 Problem der Größe n K Es gilt also T (n ) = TK (nK ) und KT (n ) = T (nK ) Explizite Lösung : Ralf Der nK = T −1 (KT (n )) Algorithmen und Datenstrukturen 1-WS05 / 06 21 ProblemgrÖ¿e und Rechnergeschwindigkeit Rechenbeis piel : Gesuchte Problemgrö ße n K ergit sich aus KT (n ) = T (n K ) Beispiel 1 : T (n ) = n m so dass Kn m = n K . Lösung : m 1 m n K = K n = m K n. Rechenbeis piel : m = 3 und K = 1000. Ergebnis : Faktor 1000 in der Rechengesc hwindigkei t bringt nur Faktor 10 in der Problemgrö ße. Beispiel 2 : T (n ) = 2 n so dass K 2 n = 2 n K . Lösung : n K = n + log 2 K Rechenbeis piel : Faktor 1000 in der Rechengesc hwindigkei t bringt nur Summand log 2 (1000 ) ≈ 10 in der Problemgrö ße. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 22 ProblemgrÖ¿e in AbhÄngigkeit der Rechengeschwindigkeit Welche Problemgröße kann bei verschiedenen Kostenfunktionen mit Rechnern verschiedener Geschwindigkeit bearbeitet werden? Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 23 Leistungsverhalten bei kleiner EingabegrÖ¿e Asymptotische Komplexität gilt (vor allem) für große n. Bei kleineren Probleme haben die Faktoren einen wesentlichen Einfluß Verfahren mit besserer (asymptotischer) Komplexität kann schlechter abschneiden als Verfahren mit schlechter Komplexität Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 24 ZeitkomplexitÄtsklassen Drei zentrale Zeitkomplexitätsklassen werden unterschieden Algorithmus A mit Zeitkomplexität T(n) heißt: • linear-zeitbeschränkt, • polynomial-zeitbeschränkt, • exponentiell-zeitbeschränkt, falls T(n) ∈ O(n) falls T(n) ∈ O(nk) falls T(n) ∈ O(kn) Exponentiell-zeitbeschränkte Algorithmen im allgemeinen (größere n) nicht nutzbar. Probleme, für die kein polynomial-zeitbeschränkter Algorithmus existiert, gelten als unlösbar (intractable). Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 25 Berechnung der ZeitkomplexitÄt I elementare Operationen (Zuweisung, Ein-/Ausgabe): O (1) Summenregel: T1 und T2 seien die Laufzeiten zweier Programmfragmente P1 und P2; es gelte T1(n) ∈ O(f(n)) und T2(n) ∈ O(g(n)) Für Hintereinanderausführung von P1 und P2 ist dann T1(n) + T2(n) ∈ O(max(f(n), g(n))) Produktregel, z.B. für geschachtelte Schleifenausführung von P1 und P2: T1(n) · T2(n) ∈ O(f(n) · g(n)) Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 26 Berechnung der ZeitkomplexitÄt II Fallunterscheidung: Kosten der Bedingungsanweisung ( = O(1)) + Kosten der längsten Alternative Schleife: Produkt aus Anzahl der Schleifendurchläufe mit Kosten der teuersten Schleifenausführung rekursive Prozeduraufrufe: Produkt aus Anzahl der rekursiven Aufrufe mit Kosten der teuersten Prozedurausführung Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 27 Beispiel: Berechnung der maximalen Teilsumme Gegeben: Folge F von n ganzen Zahlen. Gesucht: Teilfolge von 0 <= i <= n aufeinander folgenden Zahlen in F, deren Summe maximal ist Anwendungsbeispiel: Entwicklung von Aktienkursen (tägliche Änderung des Kurses). Maximale Teilsumme bestimmt optimales Ergebnis 1. Lösungsmöglichkeit: (bessere Lösungsmöglichkeiten folgen später) Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 28 KomplexitÄtsbestimmung I • • • • • • • • Nenne a.length = n. Der Schleifenkörper der innersten for-Schleife for (k = i; i <= j; k++) wird j - i + 1 mal durchlaufen und dabei jeweils die Aktion (Addition) ausgeführt. Für den nächstinneren Schleifenkörper gilt for (j = i; j < n; j++) {jeweils j - i + 1 Aktionen} also 1 + 2 + 3 + ... + n-i Aktionen. In der Summe sind das (Gaussche Formel) (n-i)(n-i+1)/2 Aktionen. Die äußere Schleife entspricht dann der Aufsummation aller dieser Beiträge über i von i = 0 bis i = n - 1. Insgesamt ist damit die Gesamtzahl der Aktionen = n3/6 + n2/2 + n/3 • Beispiel: n=32: Ralf Der 5984 Additionen Algorithmen und Datenstrukturen 1-WS05 / 06 29 KomplexitÄtsbestimmung II Ein Schleifend urchlauf innen = O (1) Gesamtzahl der Durchläufe : T (n ) = ∑ i = 0 ∑ j = i ∑ k = i 1 = ∑ i = 0 ∑ j = i ( j − i + 1) = ∑ i = 0 ∑ l =1 l n −1 n −1 = ∑ i =0 n −1 j n −1 (n − i )(n − i + 1) = 2 n −1 n −1 n −i k (k + 1) ∑ k =1 2 n 1 3 1 2 1 Mit ∑ k =1 k = n + n + n 3 2 6 n 2 ergibt sich schließlic h Ralf Der 1 3 1 2 1 T (n ) = n + n + n 6 2 3 Algorithmen und Datenstrukturen 1-WS05 / 06 30 Rekursion vs. Iteration I Für viele Probleme gibt es sowohl rekursive als auch iterative Lösungsmöglichkeiten Unterschiede bezüglich • Einfachheit, Verständlichkeit • Zeitkomplexität • Speicherkomplexität Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 31 Rekursion vs. Iteration II: Berechnung der Fibonacci-Zahlen Definition F0 = 0 F1 = 1 Fn = Fn-1 + Fn-2 für n>1 Die rekursive Lösung verursacht exponentiellen Aufwand. --------------------------Die iterative Lösung ist mit linearem Aufwand möglich. Speicherung von Zwischenergebnissen würde die Komplexität bei der rekursiven Lösung verringern. Wie? Ralf Der Int fibRekursiv (int n) { // erfordert n>0 if (n <=0) return 0; else if (n ==1) return 1; else return fibRekursiv (n-2) + fibRekursiv (n-1) } Int fibIterativ (int n) { // erfordert n>0 if (n <=0) return 0; else { int aktuelle=1, vorherige=0, temp=1, for (int i=1; i<n; i++) { temp = aktuelle; aktuelle += vorherige; vorherige = temp;} return aktuelle; } Algorithmen und Datenstrukturen 1-WS05 / 06 32 Herkunft der Fibonacci-Zahlen Modell einer Kaninchenpopulation: F0 = 0, F1 = 1, Fn = Fn-1 + Fn-2 für n>1 Fibonacci stieß auf diese Folge bei der einfachen mathematischen Modellierung des Wachstums einer Kaninchenpopulation nach folgender Vorschrift: 1. Zu Beginn gibt es ein Paar neugeborener Kaninchen. 2. Jedes neugeborene Kaninchenpaar wirft nach 2 Monaten ein weiteres Paar. 3. Anschließend wirft jedes Kaninchenpaar jeden Monat ein weiteres. 4. Kaninchen leben ewig und haben einen unbegrenzten Lebensraum. • Jeden Monat kommt zu der Anzahl der Paare, die im letzten Monat gelebt haben, eine Anzahl von neugeborenen Paaren hinzu, die gleich der Anzahl der Paare ist, die bereits im vorletzten Monat gelebt haben, da genau diese geschlechtsreif sind und sich nun vermehren. Das entspricht aber gerade der oben angegebenen Rekursionsformel. • Quelle: Wikipedia Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 33 Rekursion vs. Iteration III: n! Speicherkomplexität: Die rekursive Lösung verbraucht mehr Speicher als die iterative Lösung. Für genauere Abschätzungen müssen wir wissen, ob der Aufwand für die Multiplikation großer Zahlen mit der Länge der Faktoren wächst. Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 34 Multiplikation zweier n-stelliger Zahlen Schriftliche Multiplikation wie in der Schule: O(n2) Besseres Verfahren: Zerlege die vierstelligen Faktoren in jeweils zwei zweistellige Zahlen: (100A+B) (100C+D) = 10000AC + 100(AD+BC) + BD (vier Multiplikationen mit halber Länge sind nicht besser, aber: ) = 10000AC + 100((A+B)(C+D)-AC-BD) + BD (nur noch drei Multiplikationen!) Wir brauchen nur drei Multiplikationen von Zahlen halber Länge: T(n) = 3T(n/2) der Aufwand für Additionen wird nicht berücksichtigt) Lösung dieser Funktionalgleichung ist T(n) = nlog2 3 (Logarithmus zur Basis 2) ≈ n1.585 ALSO: Verbesserung von O(n2) auf O(n1.585) Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 35 Zusammenfassung • Komplexität / Effizienz wesentliche Eigenschaft von Algorithmen • meist asymptotische Worst-Case-Abschätzung in Bezug auf Problemgröße n – Unabhängigkeit von konkreten Umgebungsparametern (Hardware, Betriebsystem, ...) – asymptotisch "schlechte" Verfahren können bei kleiner Problemgröße ausreichen • wichtige Klassen: O(1), O(log n), O(n), O(n log n), O(n2), ... O(2n) • zu gegebener Problemstellung gibt es oft Algorithmen mit stark unterschiedlicher Komplexität – unterschiedliche Lösungsstrategien – Raum vs. Zeit: Zwischenspeichern von Ergebnissen statt mehrfacher Berechnung – Iteration vs. Rekursion • Bestimmung der Komplexität aus Programmfragmenten Ralf Der Algorithmen und Datenstrukturen 1-WS05 / 06 36