Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Suchen und Sortieren Klaus Becker 2016. 2 Suchen und Sortieren Maria Paul Julia Tara Noah Luis Anna Cem.

Ähnliche Präsentationen


Präsentation zum Thema: "Suchen und Sortieren Klaus Becker 2016. 2 Suchen und Sortieren Maria Paul Julia Tara Noah Luis Anna Cem."—  Präsentation transkript:

1 Suchen und Sortieren Klaus Becker 2016

2 2 Suchen und Sortieren Maria Paul Julia Tara Noah Luis Anna Cem

3 3 Teil 1 Einen Datenbestand durchsuchen

4 4 Krause,Stefanie,Brandenburgische Str. 20,74343,Sachsenheim Brandt,Mandy,Scharnweberstrasse 84,68199,Mannheim Almenhof Möller,Jens,Schoenebergerstrasse 47,08313,Bernsbach Herzog,Marco,Scharnweberstrasse 90,61130,Nidderau Schmitz,Andreas,Meininger Strasse 84,66539,Neunkirchen Ludwigsthal Ebersbacher,Michelle,Alt-Moabit 10,06691,Zeitz Koertig,Christine,Hardenbergstraße 82,66887,Niederalben Schmidt,Vanessa,Paderborner Strasse 44,86359,Gersthofen Meister,Stephan,Fasanenstrasse 17,22605,Hamburg Othmarschen... gesucht: Katja Herrmann Aufgabe: Probiere das selbst aus. (Quelle: adressen_unsortiert.csv) Entwickle einen Algorithmus, mit dem man in der gezeigten Datenliste nach einer Person mit einem vorgegebenen Nachnamen suchen kann.

5 5 Lineare Suche - unsortierte Liste Suche: GaErgebnis: -1 Suche: KoErgebnis: 5 GrLoBrMiScKoFrBeKeNaEbKrWiScHe GrLoBrMiScKoFrBeKeNaEbKrWiScHe

6 6 Lineare Suche - unsortierte Liste Aufgabe: Entwickle eine Funktion, mit der man einen übergebenen Namen in einer übergebenen Namensliste suchen kann. Wenn der übergebene Name in der Namensliste vorkommt, dann soll der Index des zugehörigen Datensatzes zurückgegeben werden. Kommt der Name mehrfach vor, dann soll der Index des ersten passenden Listenelements zurückgegeben werden. Kommt der Name in der Namensliste nicht vor, dann soll der Index -1 zurückgegeben werden. def suchen(name, liste): """ >>> suchen('Ko', ['Gr', 'Lo', 'Br', 'Mi', 'Sc', 'Ko', 'Fr', 'Be', 'Ke', 'Na', 'Eb', 'Kr', 'Wi', 'Sc', 'He']) 5 >>> suchen('Ga', ['Gr', 'Lo', 'Br', 'Mi', 'Sc', 'Ko', 'Fr', 'Be', 'Ke', 'Na', 'Eb', 'Kr', 'Wi', 'Sc', 'He']) -1 >>> suchen('Sc', ['Gr', 'Lo', 'Br', 'Mi', 'Sc', 'Ko', 'Fr', 'Be', 'Ke', 'Na', 'Eb', 'Kr', 'Wi', 'Sc', 'He']) 4 """ …. return …

7 7 Einen Datenbestand durchsuchen Aufgabe: Benutze die Hilfsfunktionen aus der Datei listenoperationen_zum_laden_und_speichern.py, um die Daten aus der Datei adressdaten_unsortiert.csv in das Listenformat zu übertragen. Passe die Funktion “suchen” so an, dass der Datenbestand hiermit durchsucht werden kann. def suchen(name, vorname, liste): … return … # Test from listenoperationen_zum_laden_und_speichern import * text = textAusDatei('adressdaten_unsortiert.csv') listeDaten = tupelListeAusText(text) print(suchen('Herrmann', 'Katja', listeDaten))

8 8 Einen Datenbestand durchsuchen gesucht: Katja Herrmann Aufgabe: Probiere das nochmal selbst aus. (Quelle: adressen_sortiert.csv) Warum ist das hier viel einfacher? Wie würde man bei der Suche (als Mensch / als Maschine) geschickt vorgehen? Aachen,Anke,Reeperbahn 11,18201,Bad Doberan Aachen,Dirk,Schmarjestrasse 80,33619,Bielefeld Innenstadt Aachen,Anne,Gotzkowskystraße 77,75179,Pforzheim Nordweststadt Abend,Kerstin,Lietzensee-Ufer 71,91217,Hersbruck Abend,Kristin,Marseiller Strasse 44,21775,Steinau Abend,Niklas,Knesebeckstraße 24,45770,Marl Abend,Stephanie,Albrechtstrasse 42,55469,Oppertshausen Abend,Annett,Ufnau Strasse 29,87640,Biessenhofen Abend,Alexander,Budapester Straße 12,18273,Gleviner Burg...

9 9 Lineare Suche – (un)sortierte Liste Suche: GaErgebnis: -1 Suche: TaErgebnis: -1 Suche: KoErgebnis: 7 BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi Suche: GaErgebnis: -1 Suche: KoErgebnis: 5 GrLoBrMiScKoFrBeKeNaEbKrWiScHe GrLoBrMiScKoFrBeKeNaEbKrWiScHe unsortiert sortiert

10 10 Lineare Suche - sortierte Liste Aufgabe: Ändere die Implementierung geeignet ab. def suchen(name, liste): """ >>> suchen('Ko', ['Be', 'Br', 'Eb', 'Fr', 'Gr', 'He', 'Ke', 'Ko', 'Kr', 'Lo', 'Mi', 'Na', 'Sc', 'Sc', 'Wi']) 7 >>> suchen('Ga', ['Be', 'Br', 'Eb', 'Fr', 'Gr', 'He', 'Ke', 'Ko', 'Kr', 'Lo', 'Mi', 'Na', 'Sc', 'Sc', 'Wi']) """ …. return …

11 11 Lineare Suche – unsortierte Liste ALGORITHMUS suchen Übergabe: name, liste # unsortiert indexErgebnis = -1 gefunden = False i = 0 SOLANGE name nicht gefunden und i liegt im Indexbereich : WENN name mit Listenelement an der Position i übereinstimmt: gefunden = True indexErgebnis = i SONST: i = i+1 Rückgabe: indexErgebnis

12 12 Lineare Suche – sortierte Liste ALGORITHMUS suchen Übergabe: name, liste # sortiert indexErgebnis = -1 gefunden = False i = 0 SOLANGE name nicht gefunden und i liegt im Indexbereich und name noch nicht übergangen : WENN name mit Listenelement an der Position i übereinstimmt: gefunden = True indexErgebnis = i SONST: i = i+1 Rückgabe: indexErgebnis

13 13 Binäre Suche - sortierte Liste Suche: Ga Ga, BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi

14 14 Binäre Suche - sortierte Liste Suche: Ta Ta, BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi

15 15 Binäre Suche - iterativ ALGORITHMUS suchen Übergabe: name, liste indexErgebnis = -1 gefunden = False setze linkeMarke und rechteMarke an die Ränder SOLANGE name nicht gefunden und linkeMarke liegt links von rechteMarke: bestimme die Position mitte als Mitte der Marken WENN name mit Listenelement an der Position mitte übereinstimmt: gefunden = True indexErgebnis = mitte SONST WENN name < Listenelement an der Position mitte: rücke rechteMarke eine Einheit links von mitte SONST: rücke linkeMarke eine Einheit rechts von mitte Rückgabe: indexErgebnis Aufgabe: Implementiere den Algorithmus als Funktion. Teste gründlich. Passe die Funktion so an, dass Datensätze nach Name und Vorname sortiert werden können.

16 16 Aufwand beim Suchen Aufgabe: Es liegen 1000 bzw sortierte Datensätze vor. Wie viele Vergleiche benötigt man im ungünstigsten Fall, wenn man einen Algorithmus zur linearen Suche bzw. binären Suche verwendet?

17 17 Binäre Suche - rekursiv Suche: Ga Ga, BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi BeBrEbFrGrHeKeKoKrLoMiNaSc Wi def suchen(name, liste, start, ende): if ende < start: return -1 else: mitte = (start + ende) // 2 if liste[mitte] == name: return mitte elif liste[mitte] < name: return suchen(name, liste, mitte+1, ende) else: return suchen(name, liste, start, mitte-1)

18 18 Binäre Suche - rekursiv Aufgabe: Teste die rekursive Implementierung. Füge Bildschirmausgaben ein, mit denen man den Suchablauf mitverfolgen kann.

19 19 Teil 2 Einen Datenbestand sortieren

20 20 Das Sortierproblem Krause,Stefanie,Brandenburgische Str. 20,74343,Sachsenheim Brandt,Mandy,Scharnweberstrasse 84,68199,Mannheim Almenhof Möller,Jens,Schoenebergerstrasse 47,08313,Bernsbach Herzog,Marco,Scharnweberstrasse 90,61130,Nidderau Schmitz,Andreas,Meininger Strasse 84,66539,Neunkirchen Ludwigsthal... Aachen,Anke,Reeperbahn 11,18201,Bad Doberan Aachen,Dirk,Schmarjestrasse 80,33619,Bielefeld Innenstadt Aachen,Anne,Gotzkowskystraße 77,75179,Pforzheim Nordweststadt Abend,Kerstin,Lietzensee-Ufer 71,91217,Hersbruck Abend,Kristin,Marseiller Strasse 44,21775,Steinau... Das Sortierproblem besteht darin, Verfahren zu entwickeln, die eine sortierte Anordnung von Datensätzen automatisiert erzeugen. Die einzige Voraussetzung, die die Daten erfüllen müssen, besteht darin, dass man sie nach einem Kriterium vergleichen kann. Es soll also möglich sein, bei zwei Daten D1 und D2 (der Ausgangsdatenliste) zu entscheiden, ob D1 bzgl. des Vergleichskriteriums kleiner als D2 oder D2 kleiner als D1 ist oder ob D1 und D2 bzgl. des Vergleichskriterium gleichwertig sind.

21 21 Entwicklung von Sortierverfahren Aufgabe ist es im Folgenden, ein (oder mehrere) Sortierverfahren zu entwickeln. Für die Entwicklung von Sortierverfahren spielt die Komplexität der Daten keine zentrale Rolle. Wir gehen daher im Folgenden von einfachen Daten (hier Zahlen) aus

22 22 Entwicklung von Sortierverfahren Zum Experimentieren benutzen wir die Waage-Animation von M. Jakobs.

23 23 Sortieren mit der Waage-Animation AZ: Die Gewichte sind nicht bekannt. ZZ: Die Gewichte sollen aufsteigend sortiert werden. Das leichteste Gewicht soll am weitesten links liegen.

24 24 Sortieren mit der Waage-Animation Man kann 2 Gewichte miteinender vergleichen. Man kann Gewichte irgendwo zwischenlagern. Man kann Bereiche festlegen.

25 25 Ein Verfahren entwickeln Entwickle ein Verfahren, mit dem man Gewichte sortieren kann. Teste das Verfahren mit verschiedenen Gewichtskonstellationen. Formuliere das Verfahren (und die zu Grunde liegende Idee) in Alltagssprache.

26 26 Den Algorithmus formulieren Formuliere den Algorithmus. Benutze Variablen zur Datenverwaltung und Kontrollstrukturen zur Ablaufbeschreibung. Benutze zur Darstellung ein Struktogramm oder eine Pseudo- Programmiersprache (z.B. mit Einrückungen zur Verdeutlichung von Blockstrukturen).

27 27 Teil 3 Sortieralgorithmen

28 28 Sortierverfahren Es gibt zahlreiche Verfahren, um Datensätze zu sortieren. Wir werden uns im Folgenden auf 4 Standardverfahren konzentrieren.

29 29 Selectionsort (Sortieren d. Auswählen) Idee: Suche jeweils das kleinste Element im unsortierten Bereich und lege es am Ende des sortierten Bereichs ab.

30 30 Selectionsort (Sortieren d. Auswählen) Realisierung mit 2 Listen ALGORITHMUS selectionsort Übergabe: Liste L unsortierter Bereich ist die gesamte Liste L der sortierte Bereich ist zunächst leer SOLANGE der unsortierte Bereich noch Elemente hat: suche das kleinste Element im unsortierten Bereich entferne es im unsortierten Bereich füge es im sortierten Bereich an letzter Stelle an Rückgabe: sortierter Bereich

31 31 Selectionsort (Sortieren d. Auswählen) Realisierung mit 1 Liste ALGORITHMUS selectionsort Übergabe: Liste L unsortierter Bereich ist die gesamte Liste L der sortierte Bereich ist zunächst leer SOLANGE der unsortierte Bereich noch Elemente hat: suche das kleinste Element im unsortierten Bereich entferne es im unsortierten Bereich füge es im sortierten Bereich an letzter Stelle an Rückgabe: sortierter Bereich

32 32 Selectionsort (Sortieren d. Auswählen) Aufgabe Entwickle eine Implementierung zum Sortierverfahren Selectionsort. def selectionsort(L):.... return...

33 33 Insertionsort (Sortieren d. Einfügen) Idee: Füge jeweils das erste Element des unsortierten Bereichts an der richtigen Stelle im sortierten Bereich ein

34 34 Insertionsort (Sortieren d. Einfügen) Realisierung mit 2 Listen ALGORITHMUS insertionsort Übergabe: Liste sortierter Bereich besteht aus dem ersten Element der Liste unsortierter Bereich ist die Restliste (ohne das erste Element) SOLANGE der unsortierte Bereich Elemente hat: entferne das erste Element aus dem unsortierten Bereich füge es an der richtigen Stelle im sortierten Bereich ein Rückgabe: sortierter Bereich

35 35 Insertionsort (Sortieren d. Einfügen) Realisierung mit 1 Liste ALGORITHMUS insertionsort Übergabe: Liste sortierter Bereich besteht aus dem ersten Element der Liste unsortierter Bereich ist die Restliste (ohne das erste Element) SOLANGE der unsortierte Bereich Elemente hat: füge das erste Element des unsortierten Bereichs an der richtigen Stelle im sortierten Bereich ein verkleinere den unsortierten Bereich Rückgabe: sortierter Bereich

36 36 Insertionsort (Sortieren d. Einfügen) Aufgabe Entwickle eine Implementierung zum Sortierverfahren Insertionsort. def insertionsort(L):.... return...

37 37 Bubblesort (Sortieren d. Aufsteigen) Auf YouTube gibt es eines interessantes Video zum Sortieren. Schaue dir das Video genau an. Wie gehen die Lego-Arbeiter beim Sortieren vor? Kannst du die Grundidee des benutzten Sortierverfahrens beschreiben?

38 38 Bubblesort (Sortieren d. Aufsteigen) Idee: Durchlaufe (mehrfach) den gesamten Bereich. Vergleiche jeweils zwei benachbarte Element und vertausche sie, wenn die Reihenfolge nicht stimmt

39 39 Bubblesort (Sortieren d. Aufsteigen) Realisierung mit 1 Liste ALGORITHMUS bubblesort Übergabe: Liste unsortierter Bereich ist zunächst die gesamte Liste SOLANGE der unsortierte Bereich mehr als ein Element hat: duchlaufe den unsortierten Bereich von links nach rechts wenn dabei zwei benachbarte Elemente in der falschen Reihenfolge vorliegen: vertausche die beiden Elemente verkürze den unsortierten Bereich durch Weglassen des letzten Elements Rückgabe: überarbeitete Liste

40 40 Bubblesort (Sortieren d. Aufsteigen) Aufgabe Entwickle eine Implementierung zum Sortierverfahren Bubblesort. def bubblesort(L):.... return...

41 41 Vorbereitung: Eine Gruppe von Personen stellt sich in einer Reihe auf. Jede Person erhält ein Schild, auf dem die Größe eingetragen wird. Ein Sortierspiel Anton 1.74 Britta 1.64 Carlo 1.85 Durs 1.89 Eli 1.74 Fiona 1.67 Greta 1.61 Fabian 1.92 Georg 1.78 Hannah 1.58 Igor 1.70 Jana 1.78

42 42 Ein Sortierspiel Anton 1.74 Britta 1.64 Carlo 1.85 Durs 1.89 Eli 1.74 Fiona 1.67 Greta 1.61 Fabian 1.92 Georg 1.78 Hannah 1.58 Igor 1.70 Jana 1.78 Spielregeln: (1) Eine Person (z.B. die erste in der Reihe) wird als Vergleichsperson ausgewählt. (2) Alle anderen ordnen sich links bzw. rechts von der Vergleichsperson ein - je nachdem, ob sie kleiner oder größergleich als die Vergleichsperson sind. (3) Entsprechend wird jetzt im linken und im rechten Bereich verfahren - sofern in einem Bereich noch mehr als zwei Personen sind.

43 43 Quicksort (Sortieren d. Zerlegen) Eine Person (z.B. die erste in der Reihe) wird als Vergleichsperson ausgewählt. Im vorliegenden Beispiel ist das Anton. Anton 1.74 Britta 1.64 Carlo 1.85 Durs 1.89 Georg 1.78 Fiona 1.67 Greta 1.61 Fabian 1.92 Jana 1.78 Hannah 1.58 Igor 1.70 Eli 1.74 Britta 1.64 Fiona 1.67 Greta 1.61 Hannah 1.58 Igor 1.70 Anton 1.74 Carlo 1.85 Durs 1.89 Georg 1.78 Fabian 1.92 Jana 1.78 Eli 1.74 Alle anderen ordnen sich links bzw. rechts von der Vergleichsperson ein, je nachdem, ob sie kleiner oder größergleich als die Vergleichsperson sind.

44 44 Quicksort (Sortieren d. Zerlegen) Anton bleibt jetzt auf seiner Position. Er nimmt nicht mehr an weiteren Spielrunden teil. Dasselbe Spiel wird jetzt im linken und im rechten Bereich durchgeführt: Eine Person (z.B. die erste in der Reihe) wird wiederum als Vergleichsperson ausgewählt. Wie geht das Spiel weiter? Wann ist das Spiel beendet? Welche Extremfälle können während des Spiels auftreten? Funktioniert das Sortierspiel dann auch noch? Britta 1.64 Fiona 1.67 Greta 1.61 Hannah 1.58 Igor 1.70 Anton 1.74 Carlo 1.85 Durs 1.89 Georg 1.78 Fabian 1.92 Jana 1.78 Eli 1.74

45 45 Quicksort (Sortieren d. Zerlegen) Idee: Ein Element der Liste (z.B. das erste Element) wird ausgewählt. Die Restliste wird dann gemäß dieses Elements in zwei Teillisten aufgeteilt: die Liste der Elemente der Restliste, die kleiner als das ausgewählte Element sind sowie die Liste der Elemente der Restliste, die nicht kleiner (d.h. größer oder gleich) als das ausgewählte Element sind. Dieser Vorgang wird mit den Teillisten völlig analog fortgesetzt Zerlegen Zusammensetzen Zerlegen Zusammens. Zerlegen Zusammens....

46 46 Quicksort (Sortieren d. Zerlegen) ALGORITHMUS quicksort Übergabe: Liste L wenn die Liste L mehr als ein Element hat: # zerlegen wähle als Pivotelement p das erste Element der Liste aus erzeuge Teillisten K und G aus der Restliste (L ohne p) mit: - alle Elemente aus K sind kleiner als das Pivotelement p - alle Elemente aus G sind größergleich als das Pivotelement p # Quicksort auf die verkleinerten Listen anwenden KSortiert = quicksort(K) GSortiert = quicksort(G) # zusammensetzen LSortiert = KSortiert + [p] + GSortiert Rückgabe: LSortiert Aufgabe Entwickle eine Implementierung zum Sortierverfahren Quicksort.

47 47 Quicksort – alternative Version def quicksort(L, anfang, ende): if len(L) > 1: pivot = L[anfang] links = anfang rechts = ende while links <= rechts: while L[links] < pivot: links = links+1 while L[rechts] > pivot: rechts = rechts-1 if links <= rechts: if links < rechts: h = L[links] L[links] = L[rechts] L[rechts] = h links = links+1 rechts = rechts-1 if rechts < anfang: # nicht rechts = anfang # noetig if anfang < rechts: L = quicksort(L, anfang, rechts) if links < ende: L = quicksort(L, links, ende) return L In der Literatur findet man Quicksort meist in der hier dargestellten Form implementiert. Aufgabe Worin besteht der Hauptunterschied zur oben beschriebenen Implementierung?

48 48 Quicksort – alternative Version ALGORITHMUS quicksort Übergabe: Liste L, Indexbereich wenn die Liste L mehr als ein Element hat: # zerlegen wähle als Pivotelement p (z.B.) das erste Element der Liste aus tausche Elemente innerhalb von L so, dass eine Zerlegung entsteht mit: - L = K + G alle Elemente aus K sind kleinergleich als das Pivotelement p alle Elemente aus G sind größergleich als das Pivotelement p K und G enthalten mindestens ein Element # Quicksort auf die verkleinerten Listen anwenden L = quicksort(L, Indexbereich von K) L = quicksort(L, Indexbereich von G) Rückgabe: L

49 49 Quicksort – alternative Version Eine Person (z.B. die erste in der Reihe) wird als Vergleichsperson ausgewählt. Suche von links eine Person, die größergleich als die ausgewählte Person ist. Suche von rechts eine Person, die kleinergleich als die ausgewählte Person ist. Anton 1.74 Britta 1.64 Carlo 1.85 Durs 1.89 Georg 1.78 Fiona 1.67 Greta 1.61 Fabian 1.92 Jana 1.78 Hannah 1.58 Igor 1.70 Eli 1.75 Wenn "links < rechts": Personen tauschen ihre Position in der Reihe. Zeiger weiterrücken. Igor 1.70 Britta 1.64 Carlo 1.85 Durs 1.89 Georg 1.78 Fiona 1.67 Greta 1.61 Fabian 1.92 Jana 1.78 Hannah 1.58 Anton 1.74 Eli 1.75

50 50 Quicksort – alternative Version Eine Person (z.B. die erste in der Reihe) wird als Vergleichsperson ausgewählt. Suche von links eine Person, die größergleich als die ausgewählte Person ist. Suche von rechts eine Person, die kleinergleich als die ausgewählte Person ist. Wenn "links < rechts": Personen tauschen ihre Position in der Reihe. Zeiger weiterrücken. Igor 1.70 Britta 1.64 Carlo 1.85 Durs 1.89 Georg 1.78 Fiona 1.67 Greta 1.61 Fabian 1.92 Jana 1.78 Hannah 1.58 Anton 1.74 Eli 1.75 usw. Igor 1.70 Britta 1.64 Greta 1.61 Durs 1.89 Georg 1.78 Fiona 1.67 Carlo 1.85 Fabian 1.92 Jana 1.78 Hannah 1.58 Anton 1.74 Eli 1.75

51 51 Quicksort – alternative Version >>> [21, 9, 20, 45, 5, 58, 40, 17] Quicksort [21, 9, 20, 45, 5, 58, 40, 17] [17, 9, 20, 5] [45, 58, 40, 21] Quicksort [17, 9, 20, 5] [5, 9] [20, 17] Quicksort [5, 9] [5] [9] Quicksort [20, 17] [17] [20] Quicksort [45, 58, 40, 21] [21, 40] [58, 45] Quicksort [21, 40] [21] [40] Quicksort [58, 45] [45] [58] [5, 9, 17, 20, 21, 40, 45, 58]

52 52 Quicksort – alternative Version Aufgabe Teste auch die alternative Implementierung des Quicksort-Algorithmus. Füge an geeigneten Stellen Ausgabeanweisungen ein, um den Ablauf zu illustrieren.

53 53 Teil 4 Laufzeitverhalten

54 54 Zielsetzung Algorithmen stellen oft nur einen Zwischenschritt beim Problemlösen dar. In der Praxis ist man meist an Programmen - also Implementierungen von Algorithmen in einer Programmiersprache - interessiert, die von Rechnern real ausgeführt werden können. Dabei spielt der Ressourcenverbrauch (Laufzeitverhalten und Speicherplatzbelegung) der Programme eine zentrale Rolle. Erwünscht sind solche Programme, die mit möglichst wenig Ressourcen auskommen. Wir werden uns im Folgenden auf die Ressource "Rechenzeit" konzentrieren, da Speicherplatz heute für viele Problemlösungen genügend zur Verfügung steht. Laufzeitmessungen liefern wichtige Informationen über die Einsetzbarkeit von Programmen. Programme, bei denen man sehr lange auf Ergebnisse warten muss, sind - je nach Anwendungsgebiet - oft nicht praxistauglich. Ziel der folgenden Untersuchungen ist es, das Laufzeitverhalten von Sortieralgorithmen zu ermitteln und die Ergebnisse genauer zu analysieren.

55 55 from time import * print("Start") t1 = clock() # Ausführung des Programms... t2 = clock() t = t2 - t1 print("Stopp") print("Rechenzeit: ", t) Laufzeitmessungen from time import * from random import randint # Sortieralgorithmus def selectionsort(L):... # Initialisierung der Liste print("Aufbau der Testliste") anzahl = 100 L = [] for i in range(anzahl): L = L + [randint(1, 10*anzahl)] print(L) print("Start des Sortiervorgangs") # Sortierung der Liste t1 = clock() L_sortiert = selectionsort(L) t2 = clock() t = t2 - t1 print("Ende des Sortiervorgangs") # Ausgabe print(L_sortiert) print("Rechenzeit: ", t) Muster Beispiel

56 56 from time import * from random import randint # Sortieralgorithmus... # Initialisierung der Anzahl der Listenelemente anzahl = 1000 while anzahl < 10000: # Erzeugung der Liste L = [] for i in range(anzahl): L = L + [randint(1, 10*anzahl)] # Bestimmung der Rechenzeit t1 = clock() L_sortiert = selectionsort(L) t2 = clock() t = t2 - t1 # Ausgabe des Messergebnisses print("Anz...: ", anzahl, "Rechenzeit: ", t) # Erhoehung der Anzahl anzahl = anzahl Systematische Laufzeitmessungen >>> Anzahl der Listenelemente: 1000 Rechenzeit: Anzahl der Listenelemente: 2000 Rechenzeit: Anzahl der Listenelemente: 3000 Rechenzeit: Anzahl der Listenelemente: 4000 Rechenzeit: Anzahl der Listenelemente: 5000 Rechenzeit: Anzahl der Listenelemente: 6000 Rechenzeit: Anzahl der Listenelemente: 7000 Rechenzeit: Anzahl der Listenelemente: 8000 Rechenzeit: Anzahl der Listenelemente: 9000 Rechenzeit: Beispiel Wir bestimmen die Laufzeit t(n) systematisch in Abhängigkeit der Listenlänge n für wachs- ende Listenlängen (z.B. n = 1000, 2000,...).

57 57 Laufzeitmessungen - Selectionsort Aufgabe: Führe selbst systematische Laufzeitmessungen durch (u.a. für Selectionsort und Quicksort). Versuche, anhand der Messwerte Gesetzmäßigkeiten aufzudecken (z.B.: Wie ändert sich t(n), wenn man n verdoppelt?) Benutze die Gesetzmäßigkeiten, um Vorhersagen zu treffen (z.B.: Wie lange dauert es, um... Listenelemente zu sortieren?). Überprüfe deine Vorhersagen.

58 58 Anzahl der Listenelemente: 1000 Rechenzeit: Anzahl der Listenelemente: 2000 Rechenzeit: Anzahl der Listenelemente: 3000 Rechenzeit: Anzahl der Listenelemente: 4000 Rechenzeit: Anzahl der Listenelemente: 5000 Rechenzeit: Anzahl der Listenelemente: 6000 Rechenzeit: Anzahl der Listenelemente: 7000 Rechenzeit: Anzahl der Listenelemente: 8000 Rechenzeit: Anzahl der Listenelemente: 9000 Rechenzeit: Laufzeitmessungen - Selectionsort *2

59 59 Anzahl der Listenelemente: 1000 Rechenzeit: Anzahl der Listenelemente: 2000 Rechenzeit: Anzahl der Listenelemente: 3000 Rechenzeit: Anzahl der Listenelemente: 4000 Rechenzeit: Anzahl der Listenelemente: 5000 Rechenzeit: Anzahl der Listenelemente: 6000 Rechenzeit: Anzahl der Listenelemente: 7000 Rechenzeit: Anzahl der Listenelemente: 8000 Rechenzeit: Anzahl der Listenelemente: 9000 Rechenzeit: Laufzeitmessungen - Quicksort *2 # ALGORITHMUS quicksort(L) wenn die Liste L mehr als ein Element hat: # zerlegen wähle als Pivotelement p das erste Element d. Liste aus erzeuge Teillisten K und G aus "L ohne p" mit - alle Elemente aus K sind kleiner als das Pivotelement p - alle Elemente aus G sind nicht kleiner als p # Quicksort auf die verkleinerten Listen anwenden KSortiert = quicksort(K) GSortiert = quicksort(G) # zusammensetzen LSortiert = KSortiert + [p] + GSortiert # Rückgabe: LSortiert

60 60 Anzahl der Listenelemente: 1000 Rechenzeit: Anzahl der Listenelemente: 2000 Rechenzeit: Anzahl der Listenelemente: 3000 Rechenzeit: Anzahl der Listenelemente: 4000 Rechenzeit: Anzahl der Listenelemente: 5000 Rechenzeit: Anzahl der Listenelemente: 6000 Rechenzeit: Anzahl der Listenelemente: 7000 Rechenzeit: Anzahl der Listenelemente: 8000 Rechenzeit: Anzahl der Listenelemente: 9000 Rechenzeit: Laufzeitmessungen - Quicksort *2 # ALGORITHMUS quicksort(L) Übergabe: Liste L, Indexbereich wenn die Liste L mehr als ein Element hat: # zerlegen wähle ein Pivotelement p tausche Elemente innerhalb von L so, dass: - L = K + G - alle Elemente aus K sind kleinergleich p - alle Elemente aus G sind größergleich p - K und G enthalten mindestens ein Element # Quicksort auf die verkleinerten Listen anwenden L = quicksort(L, Indexbereich von K) L = quicksort(L, Indexbereich von G) Rückgabe: L

61 61 Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Schwierigkeiten bei Laufzeitmessungen Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Start Stopp Rechenzeit: Selectionsort - wiederholte Durchführung einer Laufzeitmessung

62 62 Problematik von Laufzeitmessungen Laufzeitmessungen werden in der Praxis durchgeführt, um das Laufzeitverhalten eines Programms unter Realbedingungen zu ermitteln. Aus systematisch durchgeführten Laufzeitmessungen kann man oft Gesetzmäßigkeiten erschließen, wie die Laufzeit von den zu verarbeitenden Daten abhängt. Bei Laufzeitmessungen muss man aber sehr genau darauf achten, dass sie unter gleichen Bedingungen erfolgen. Ein Wechsel des Rechners führt in der Regel zu anderen Ergebnissen. Auch Änderungen in der Implementierung wirken sich in der Regel auf die Messergebnisse aus. Selbst bei ein und demselben Rechner und derselben Implementierung können sich die Bedingungen ändern, da oft mehrere Prozesse gleichzeitig ablaufen. Ergebnisse von Laufzeitmessungen sind also kaum auf andere Systeme (andere Rechner, andere Programmiersprachen) übertragbar. Um diese Schwierigkeit zu überwinden, soll im Folgenden ein anderer Weg zur Beschreibung der Berechnungskomplexität beschritten werden.

63 63 Teil 5 Aufwandsanalyse

64 64 Zielsetzung Experimentell bestimmte Laufzeiten haben den Nachteil, dass sie vom benutzen Rechner und den Bedingungen auf dem Rechner (Prozesse, die dort laufen) abhängen. Solche Rechenzeiten sind also nur bedingt aussagekräftig. Erschwerend kommt manchmal hinzu, dass Rechenzeiten bei manchen Problemstellungen so groß werden, dass man sie bis heute noch nicht ermitteln konnte. Neben experimentellen Methoden benutzt man in der Informatik daher auch mathematische Methoden zur Einschätzung des Laufzeitverhaltens. Man versucht dabei, das Laufzeitverhalten abzuschätzen und abstrahierend zu beschreiben.

65 65 Kostenabschätzung def selectionsort(L): n = len(L) i = 0 while i < n-1: minpos = i m = i while m < n: if L[m] < L[minpos]: minpos = m m = m+1 h = L[i] L[i] = L[minpos] L[minpos] = h i = i+1 return L Bei der Ausführung des Algorithmus (bei vorgegebenen Problemgröße) spielt es eine Rolle, wie viele Operationen ausgeführt werden müssen. Operationen sind im vorliegenden Algorithmus u.a. das Ausführen eines Vergleichs und das Ausführen einer Zuweisung. Als Kostenmaß zur Beschreibung des zeitlichen Aufwands könnte man also die Gesamtanzahl der auszuführenden Vergleiche und Zuweisungen wählen. Bei der Festlegung eines Kostenmaßes müssen Annahmen über den Aufwand der verschiedenen auszuführenden Operationen gemacht werden. Zwei ganz unterschiedliche Wege kann man dabei bestreiten. Ein Weg besteht darin, unterschiedliche Aufwände von Operationen möglichst genau zu erfassen und im Kostenmaß zu berücksichtigen. Ein anderer Weg beschränkt sich darauf, dominante Operationen auszuwählen und die Kosten nur grob zuzuschätzen. Wir werden hier nur den zweiten Weg beschreiten.

66 66 Kostenabschätzung def selectionsort(L): n = len(L) i = 0 while i < n-1: minpos = i m = i while m < n: if L[m] < L[minpos]: minpos = m m = m+1 h = L[i] L[i] = L[minpos] L[minpos] = h i = i+1 return L Aufgabe: Wie viele Vergleiche von Listenelementen werden bei der Ausführung des Algorithmus / Programms durchgeführt? Ergänze die Funktionsdefinition um einen geeigneten Zähler.

67 67 Kostenanalyse - Selectionsort | Vergleiche: 11 ^ 6 | ^ 6 8 | ^ | ^ | ^ | ^ | ^ | ^ | ^ | ^... Problemgröße: n Datensätze Kostenmaß: Anzahl der Vergleiche Kostenfunktion: n -> (n-1)+(n-2) Selectionsort

68 68 Kostenanalyse - Insertionsort 25 | Vergleiche: | | | | | Problemgröße: n Datensätze Kostenmaß: Anzahl der Vergleiche Kostenfunktion: n -> ? Insertionsort Aufgabe: Bestimme jeweils die Anzahl der benötigten Vergleiche. Bei welcher Ausgangssituation sind die Kosten besonders ungünstig / günstig? Wie lautet in diesen beiden Fällen die Kostenfunktion?

69 69 Kostenanalyse best case (bester Fall): der Fall, in dem bei der Ausführung des Algorithmus die wenigsten Kosten anfallen worst case (schlechtester Fall): der Fall, in dem bei der Ausführung des Algorithmus die meisten Kosten anfallen average case (durchschnittlicher Fall): eine Mittelung der Kosten über alle Fälle Die Anzahl der Datensatzvergleiche bei der Ausführung eines Sortieralgorithmus hängt manchmal nicht nur von der Problemgröße n (d.h. der Anzahl der Listenelemente) ab, entscheidend ist auch, wie stark die Liste bereits vorsortiert ist. 12 | Vergleiche: | Vergleiche: | Vergleiche: 1... Kostenfunktion: n -> n-1 91 | Vergleiche: | Vergleiche: | Vergleiche: 3... Kostenfunktion: n -> (n-1) Insertionsort – best case Insertionsort – worst case

70 70 Kostenmodellierung als Problem Genauere Analysen zeigen, dass bei längeren Listen die Verwaltung und die Verarbeitung dieser Listen sehr aufwendig ist und bei der Kostenmodellierung nicht vernachlässigt werden kann. # ALGORITHMUS quicksort(L, Indexbereich) wenn die Liste L mehr als ein Element hat: # zerlegen wähle ein Pivotelement p tausche Elemente innerhalb von L so, dass: - L = K + G - alle Elemente aus K sind kleinergleich p - alle Elemente aus G sind größergleich p - K und G enthalten mindestens ein Element # Quicksort auf die verkleinerten Listen anwenden L = quicksort(L, Indexbereich von K) L = quicksort(L, Indexbereich von G) Rückgabe: L # ALGORITHMUS quicksort(L) wenn die Liste L mehr als ein Element hat: # zerlegen wähle als Pivotelement p das erste Element d. Liste aus erzeuge Teillisten K und G aus "L ohne p" mit - alle Elemente aus K sind kleiner als das Pivotelement p - alle Elemente aus G sind nicht kleiner als p # Quicksort auf die verkleinerten Listen anwenden KSortiert = quicksort(K) GSortiert = quicksort(G) # zusammensetzen LSortiert = KSortiert + [p] + GSortiert Rückgabe: LSortiert Problemgröße: n Datensätze Kostenmaß: Anzahl der Vergleiche Problemgröße: n Datensätze Kostenmaß: ???

71 71 Kostenanalyse - Quicksort Vergleiche: 7 ^ | Vergleiche: 3+3 ^ ^ 5 9 | | | Vergleiche: ^ ^ ^ ^ 5 | 9 | 17 | 20 | 21 | 40 | 46 | 58 Vergleiche: Quicksort – best case Vergleiche: 7 ^ | 58 Vergleiche: 6 ^ | Vergleiche: 5 ^ | Vergleiche: 4 ^... Quicksort – worst case T best (n) ≈ log 2 (n)*n T worst (n) = (n-1) + (n-2)

72 72 Fachkonzept Kostenfunktion Die Problemgröße ist eine präzise Beschreibung des Umfangs der zu verarbeitenden Daten, von dem das Zeit- bzw. Speicherverhalten von Lösungalgorithmen maßgeblich beeinflusst wird. Bei der Beschreibung der Zeitkomplexität mit Hilfe einer Kostenfunktion werden in der Regel eine Reihe von Vereinfachungen vorgenommen sowie Annahmen gemacht. Die Festlegung einer Kostenfunktion kann somit als eine Form der Modellierung angesehen werden, weil hier ein Berechnungsmodell entwickelt werden muss, das den Berechnungsaufwand vereinfachend beschreibt. Wie bei jeder Modellierung kann das entwickelte Modell mehr oder auch weniger geeignet sein, um die zu beschreibende Wirklichkeit darzustellen. Bei der Modellierung der Zeitkomplexität kommt es darauf an, „gute" Annahmen über den Aufwand bestimmter, im Algorithmus vorkommender Operationen zu machen. Dass das manchmal schwierig ist, zeigen die Implementierungen des Quicksort- Algorithmus. Ein Kostenmaß legt fest, in welchem Maße welche Operationen bei der Aufwandsbestimmung berücksichtigt werden. Eine Kostenfunktion ordnet der Problemgröße n die vom Algorithmus benötigten Gesamtkosten T(n) bzgl. des vorgegebenen Kostenmaßes zu.

73 73 Kostenanalyse - Ergebnisse Selectionsort: T best (n) = (n-1) + (n-2) = n*(n-1)/2 = n 2 /2 - n/2 T worst (n) = (n-1) + (n-2) = n 2 /2 - n/2 T average (n) = n 2 /2 - n/2 Insertionsort: T best (n) = n-1 T worst (n) = (n-1) = n 2 /2 - n/2 T average (n) ≈ c* n 2 Quicksort: T best (n) ≈ log 2 (n)*n T worst (n) = (n-1) + (n-2) = a*n 2 + b*n + c T average (n) ≈ c* n*log 2 (n)

74 74 Kostenanalyse Aufgabe: Führe eine Kostenanalyse für den Sortieralgorithmus Bubblesort durch.

75 75 Vergleich von Kostenfunktionen Oft gibt es zu einem Problem mehrere Lösungsalgorithmen mit unterschiedlichen Kostenfunktionen. Diese will man natürlich vergleichen. Bevorzugt werden die Algorithmen, die die geringsten Kosten verursachen. Nur, wie vergleicht man Kostenfunktionen? Selectionsort: T best (n) = (n-1) + (n-2) T worst (n) = (n-1) + (n-2) T average (n) = (n-1) + (n-2) Quicksort: T best (n) ≈ log 2 (n)*n T worst (n) = a*n 2 + b*n + c T average (n) ≈ c* n*log 2 (n)

76 76 Vergleich von Kostenfunktionen Algorithmen sind in der Regel so konzipiert, dass sie eine Lösung für beliebige Problemgrößen liefern. Beim Vergleich zugehöriger Kostenfunktionen tritt die Schwierigkeit auf, dass globale Aussagen oft nicht möglich sind. Es kann vorkommen, dass in einem Bereich die eine Kostenfunktion günstiger ist, in einem anderen Bereich die andere Kostenfunktion. T 1 (n) = 0.01*n 2 T 2 (n) = 322*n*log 2 (n)

77 77 Vergleich von Kostenfunktionen Oft ist der Problembereich, für den Algorithmen benötigt werden, nicht klar vorgegeben. Man benötigt dann ein Vergleichsverfahren für Kostenfunktionen, das auch mit Situationen wie in der Abbildung klarkommt. Eine Grundidee des in der Informatik gängigen Vergleichsverfahrens besteht darin, dass kleine Problemgrößen meist von geringerem Interesse sind als große Problemgrößen. Bei kleinen Problemgrößen unterscheiden sich Laufzeiten von Algorithmen z.B. nur im Millisekunden- bereich, während die Unterschiede bei großen Problemgrößen im Sekunden-, Minuten-, Stunden-, Tage- oder gar Jahrebereich liegen können. Verbesserungen von Algorithmen zeigen sich in der Regel insbesondere bei großen Problemgrößen. Mathematisch präzisiert man diese Idee, indem man das Wachstumsverhalten von Kosten- funktionen vergleicht. Dabei idealisiert man, indem man das Grenzwertverhalten für gegen unendlich strebende Problemgrößen betrachtet. T 1 (n) = 0.01*n 2 T 2 (n) = 322*n*log 2 (n) T 2 (n) / T 1 (n) -> 0

78 78 Vergleich von Kostenfunktionen Eine (Kosten-) Funktion f wächst schneller als eine (Kosten-) Funktion g, wenn der Quotient f(n)/g(n) mit wachsendem n gegen unendlich strebt. Eine (Kosten-) Funktion f wächst langsamer als eine (Kosten-) Funktion g, wenn der Quotient f(n)/g(n) mit wachsendem n gegen 0 strebt. Eine (Kosten-) Funktion f wächst genauso schnell wie eine (Kosten-) Funktion g, wenn der Quotient f(n)/g(n) mit wachsendem n gegen eine Konstante c strebt. Selectionsort: T selectionsort (n) = (n-1) + (n-2) = n*(n-1)/2 = n 2 /2 - n/2 Quicksort - average: T quicksort (n) ≈ c* n*log 2 (n) Beispiel: T selectionsort (n) wächst genauso schnell wie T(n) = n 2. T selectionsort (n) / n 2 = 1/2 - 1/(2n) -> 1/2 Beispiel: T quicksort (n) wächst langsamer als T selectionsort (n). T quicksort (n) / T selectionsort (n) = c* n*log 2 (n) / (n*(n-1)/2) = 2*c* log 2 (n) / (n-1) -> 0

79 79 Wachstumsklassen Eine (Kosten-) Funktion f wächst nicht schneller als eine (Kosten-) Funktion g, wenn f genauso schnell oder langsamer als g wächst. Die Klasse aller Funktionen, die nicht schneller wachsen als eine vorgegebene (Kosten-) Funktion f, wird mit O(f) bezeichnet. Man liest das so: "Groß O von f". Beispiel: T selectionsort (n) gehört zur Klasse O(n 2 ). T selectionsort (n) gehört zur Klasse der Funktionen, die nicht schneller als quadratisch wachsen. Beispiel: T quicksort (n) gehört zur Klasse O(n*log 2 (n)). T quicksort (n) gehört zur Klasse der Funktionen, die nicht schneller als logarithmisch-linear wachsen.

80 80 Literaturrecherche

81 81 Teil 7 Die Komplexität des Sortierproblems

82 82 Komplexität von Problemen Der Algorithmus selectionsort hat - im günstigsten wie auch ungünstigsten Fall - eine quadratische Zeitkomplexität. Die zur Beschreibung des Laufzeitverhalten gewählte Kostenfunktion gehört zur Klasse O(n 2 ) der asymptotisch quadratisch wachsenden Funktionen. Der Algorithmus quicksort hat - im günstigsten (und auch durchschnittlichen) Fall - eine logischmisch-lineare Zeitkomplexität. Die zur Beschreibung des Laufzeitverhalten gewählte Kostenfunktion gehört hier zur Klasse O(n*log 2 (n)). Es gibt eine Vielzahl an weiteren Sortieralgorithmen. Die "schnelleren" dieser Algorithmen haben alle eine logischmisch-lineare Zeitkomplexität. Es stellt sich die Frage, ob es nicht noch schnelleren Sortieralgorithmen gibt - z.B. solche mit einer linearen Zeitkomplexität - und, ob es auch eine Art untere Schranke für die Zeitkomplexität gibt, die von keinem Sortieralgorithmus unterschritten werden kann. Diese Fragen betreffen die Komplexität des Sortierproblems. Zur Beschreibung der Komplexität eines Problems muss man folglich Aussagen über alle möglichen Algorithmen zur Lösung des Problems machen, indem man zeigt, dass ein bestimmter Ressourcenverbrauch bei all diesen Algorithmen erforderlich ist und von keinem Algorithmus unterschritten werden kann. Die Schwierigkeit beim Nachweis solcher Aussagen besteht darin, dass man den Nachweis über alle denkbaren - d.h. bis jetzt gefundenen und auch noch nicht bekannten - Algorithmen führen muss. Die (Zeit-)Komplexität eines Problems beschreibt man durch Komplexitätsklassen, die untere Schranken für die Komplexität der Algorithmen, die das Problem lösen, bilden.

83 83 Problem - Sortieren {abcd,abdc,acbd,acdb,adbc,adcb,bacd,badc,bcad,bcda,bdac,bdca, cabd,cadb,cbad,cbda,cdab,cdba,dabc,dacb,dbac,dbca,dcab,dcba} [a, b, c, d] a < b? T: {abcd,abdc,acbd,acdb,adbc,adcb,cabd,cadb,cdab,dabc,dacb,dcab} [a, b, c, d] a < c? T: {abcd,abdc,acbd,acdb,adbc,adcb,dabc,dacb} [a, b, c, d] a < d? T: {abcd,abdc,acbd,acdb,adbc,adcb} [a, b, c, d] b < c?... F:... | ^ 25 | ^ | ^ | 56 Selectionsort Gegeben ist eine Liste L = [a, b, c, d] mit 4 Elementen (z.B. Zahlen) und eine Vergleichsoperation, über die die Listenelemente sortiert werden sollen. Bei einer Liste mit 4 Elementen gibt es 24 verschiedene Möglichkeiten, wie die Listenelemente nach der Sortierung angeordnet sein können: {abcd,abdc,acbd,acdb,adbc,adcb,bacd,badc,bcad,bcda,bdac,bdca, cabd,cadb,cbad,cbda,cdab,cdba,dabc,dacb,dbac,dbca,dcab,dcba} mögliche Ausführungen von Selectionsort als Baumdiagramm

84 84 Problem - Sortieren {abcd,abdc,acbd,acdb,adbc,adcb,bacd,badc,bcad,bcda,bdac,bdca, cabd,cadb,cbad,cbda,cdab,cdba,dabc,dacb,dbac,dbca,dcab,dcba} [a, b, c, d] a < b? T: {abcd,abdc,acbd,acdb,adbc,adcb,cabd,cadb,cdab,dabc,dacb,dcab} [a, b, c, d] a < c? T: {abcd,abdc,acbd,acdb,adbc,adcb,dabc,dacb} [a, b, c, d] a < d? T: {abcd,abdc,acbd,acdb,adbc,adcb} [a, b, c, d] b < c? T: {abcd,abdc,adbc} [a, b, c, d] b < d? T: {abcd,abdc} [a, b, c, d] c < d? T: {abcd} [a, b, c, d] F: {abdc} [a, b, d, c] F: {adbc} [a, d, c, b] c < b? T: {} [a, d, c, b] F: {adbc} [a, d, b, c] F: {acbd,acdb,adcb} | ^ 25 | ^ | ^ | 56 Selectionsort

85 85 Problem - Sortieren... F: {dabc,dacb} [d, b, c, a] b < c? T: {dabc} [d, b, c, a] b < a? T: {} c < a? T: {} F: {} F: {dabc} [d, a, c, b] c < b? T: {} F: {dabc} [d, a, b, c] F: {dacb} [d, b, c, a] c < a? T: {} b < a? T: {} F: {} F: {dacb} [d, a, c, b] c < b? T: {dacb} [d, a, c, b] F: {}... | ^ 25 | ^ | ^ | 56 Selectionsort Wenn ein Sortieralgorithmus die Sortierung nur über Vergleiche von Listenelementen erzeugt, dann lässt sich die Ausführung des Algorithmus bei beliebigen Ausgangslisten über einen Entscheidungsbaum darstellen. Die "Tiefe des Baumes" (erkennbar an den Einrückungen) zeigt dabei, wie viele Entscheidungen im ungünstigsten Fall auszuführen sind. Im Fall des Algorithmus selectionsort beträgt die Tiefe des Baumes 6. Am Entscheidungsbaum zeigt sich also, wie gut oder schlecht ein Algorithmus ist. Wenn die Tiefe des Entscheidungsbaums groß bzw. klein ist, dann ist das worst-case-Verhalten des Algorithmus schlecht bzw. gut.

86 86 {abcd,abdc,acbd,acdb,adbc,adcb,bacd,badc,bcad,bcda,bdac,bdca, cabd,cadb,cbad,cbda,cdab,cdba,dabc,dacb,dbac,dbca,dcab,dcba} a < b? T: {abcd,abdc,acbd,acdb,adbc,adcb,cabd,cadb,cdab,dabc,dacb,dcab} c < d? T: {abcd,acbd,acdb,cabd,cadb,cdab} a < c? T: {abcd,acbd,acdb} b < c? T: {abcd} F: {acbd,acdb} b < d? T: {acbd} F: {acdb} F: {cabd,cadb,cdab} b < d? T: {cabd} F: {cadb,cdab} a < d? T: {cadb} F: {cdab} F: {abdc,adbc,adcb,dabc,dacb,dcab} a < d? T: {abdc,adbc,adcb} b < d? T: {abdc} F: {adbc,adcb} b < c? T: {abdc} F: {adcb} F:... Problem - Sortieren Am Entscheidungsbaum kann auch aufgezeigt werden, wie gut das worst-case-Verhalten eines Sortieralgorithmus überhaupt sein kann: Bei 24 möglichen Anordnungen benötigt man mindestens einen Entscheidungsbaum der Tiefe 5, um alle Anordnungen durch Entscheidungen erzeugen zu können. Das sieht man so ein: Durch 1 Entscheidung erhält man eine Aufteilung der Anordnungen in 2 Teilmengen, durch 2, 3, 4, 5,... Entscheidungen in 4, 8, 16, 32,... Teilmengen. Um alle 24 Anordnungen mittels Entscheidungen auseinander zu bekommen, sind daher mindestens 5 Entscheidungen im Entscheidungsbaum erforderlich. Das Baumdiagramm zeigt, wie man mit 5 geschachtelten Entscheidungen tatsächlich alle Anordnungen erhält.

87 87 Komplexität des Sortierproblems Die Betrachtungen oben verdeutlichen, dass es zu jedem vergleichsbasierten Sortieralgorithmus (für jede Listenlänge) einen zugehörigen Entscheidungsbaum gibt. Die Tiefe des Entscheidungsbaum (in Abhängigkeit der Listenlänge) legt das worst-case-Verhalten des Algorithmus fest. Um eine untere Schranke für das worst-case-Verhalten von Sortieralgorithmen zu gewinnen, schauen wir uns die Tiefe von "optimalen Entscheidungsbäumen" (in Abhängigkeit der Listenlänge) an. Um k verschiedene Anordnungen nur mit Entscheidungen zu erzeugen, benötigt man einem Entscheidungsbaum mit einer Tiefe der Größenordnung log 2 (k). Wenn k = 2m eine Zweierpotenz ist, dann reicht die Tiefe m. Ansonsten benötigt man als Tiefe den Exponenten von der von k aus nächst größeren Zweierpotenz. Wenn beispielsweise k = 24, dann benötigt man eine Tiefe log 2 (32), also die Tiefe 5. Um eine Aussage über Listen beliebiger Länge treffen zu können, muss man wissen, wie viele Anordnungen jeweils möglich sind: Bei n Listenelementen gibt es n! = 1*2*...*n verschiedene mögliche Anordnungen der Listenelemente. Fasst man beide Ergebnisse zusammen, so erhält man folgende Aussage: Um eine Liste mit n Elementen zu sortieren, benötigt man einen Entscheidungsbaum, der eine Tiefe der Größenordnung log 2 (n!) hat.

88 88 Komplexität des Sortierproblems Jeder vergleichsbasierte Sortieralgorithmus hat demnach ein worst-case-Verhalten, das durch die Funktion K(n) = log 2 (n!) abgeschätzt werden kann. Mathematiker haben gezeigt, dass n! ≥ (n/2) (n/2) gilt. Mit dieser Abschätzung erhält man log 2 (n!) ≥ (n/2)*log 2 (n/2). Hieraus ergibt sich, dass jeder vergleichsbasierte Sortieralgorithmus ein worst-case-Verhalten hat, das nach unten durch die Funktion K(n) = (n/2)*log 2 (n/2) abgeschätzt werden kann. Betrachtet man - wie üblich - nur das asymptotische Verhalten, so zeigt dies, dass das worst- case-Verhalten eines beliebigen Sortieralgorithmus von der Ordnung n*log 2 (n) sein muss. Ergebnis - Komplexität des Sortierproblems: Die Komplexität des Sortierproblems ist von der Ordnung n*log2(n) - sofern ein vergleichsbasiertes Berechnungsmodell zu Grunde liegt.


Herunterladen ppt "Suchen und Sortieren Klaus Becker 2016. 2 Suchen und Sortieren Maria Paul Julia Tara Noah Luis Anna Cem."

Ähnliche Präsentationen


Google-Anzeigen