Dr. Lars Hildebrand EINI I Einführung in die Informatik für Naturwissenschaftler und Ingenieure Vorlesung 2 SWS WS 10/11 Dr. Lars Hildebrand Fakultät für Informatik – Technische Universität Dortmund [email protected] http://ls1-www.cs.uni-dortmund.de EINI Kap. 5 Arrays – Internes Sortieren 1 Thema Dr. Lars Hildebrand Kapitel 5 Algorithmen und Datenstrukturen Konstruktion von Datentypen: Algorithmen: Arrays Sortieren Unterlagen Gumm/Sommer, Kapitel 2.7 & 2.8 Echtle/Goedicke, Einführung in die Programmierung mit Java, dpunkt Verlag, Kapitel 4 Doberkat/Dißmann, Einführung in die objektorientierte Programmierung mit Java, Oldenbourg, Kapitel 3.4 & 4.1 EINI Kap. 5 Arrays – Internes Sortieren 2 Übersicht Dr. Lars Hildebrand Begriffe Spezifikationen, Algorithmen, formale Sprachen, Grammatik Programmiersprachenkonzepte Syntax und Semantik imperative, objektorientierte, funktionale und logische Programmierung Grundlagen der Programmierung imperative Programmierung Verfeinerung, elementare Operationen, Sequenz, Selektion, Iteration, funktionale Algorithmen und Rekursion, Variablen und Wertzuweisungen, Prozeduren, Funktionen und Modularität objektorientierte Programmierung Algorithmen und Datenstrukturen Berechenbarkeit und Entscheidbarkeit von Problemen Effizienz und Komplexität von Algorithmen Programmentwurf, Softwareentwurf EINI Kap. 5 Arrays – Internes Sortieren 3 Gliederung Dr. Lars Hildebrand Arrays Datenstruktur zur Abbildung gleichartiger Daten Deklaration Dimensionierung und Zuordnung von Speicher zur Laufzeit Zuweisung: ganzes Array, Werte einzelner Elemente Speicherfreigabe durch Garbage Collection (Java) oder explizit (C/C++) Algorithmen auf Arrays: Beispiel Sortieren naives Verfahren: Minimum bestimmen, entfernen, Restmenge sortieren Heapsort: ähnlich, nur mit Binärbaum über Indexstruktur Quicksort: divide & conquer, zerlegen in 2 Teilmengen anhand eines Pivotelementes EINI Kap. 5 Arrays – Internes Sortieren 4 Arrays, Felder Dr. Lars Hildebrand Motivation: Schleifen erlauben die Verarbeitung mehrerer Daten auf einen „Schlag“ Eine Entsprechung auf der Variablenseite ist die Zusammenfassung mehrerer Variablen gleichen Typs: -> Arrays oder Felder Beispiele: Zeichenketten/Strings, Arrays aus Character/Zeichen Vektoren, Matrizen: Arrays aus Integer/Float Variablen Abbildung eines Lagerbestandes durch Angabe der Menge für einen Artikel und einen Lagerort – Bei n unterschiedlichen Artikeln und m Orten: – Bestand [1] [5] der Bestand des Artikels 1 am Ort 5 – In Java: Bestand [i] [j] Artikel mit Nummer i und Ort j EINI Kap. 5 Arrays – Internes Sortieren 5 Arrays, Felder Dr. Lars Hildebrand Fragen: Wie werden Arrays deklariert ? Wie werden Daten in Arrays abgelegt, verändert, ausgegeben ? Wie wird die Größe eines Arrays festgelegt ? EINI Kap. 5 Arrays – Internes Sortieren 6 Arrays sind Variablen ... Dr. Lars Hildebrand ... müssen daher auch deklariert werden, bevor sie benutzt werden ... die viele Variablen enthalten, die vom gleichen Typ sind ... die Anzahl der Dimensionen entspricht der Anzahl der Indexausdrücke Deklarationen: int [] x; // ein-dimensional int float [] [] y; // zwei-dimensional float Legen allerdings anders als bei int z; noch keinen Speicherplatz fest EINI Kap. 5 Arrays – Internes Sortieren 7 Arrays Dr. Lars Hildebrand Deklarationen einer Array-Variablen legt nur einen Verweis auf ein Array fest int [] x; x = new int [20]; float [] [] y; y = new float [80][80]; x y 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 1 0 0 .... 79 .... 0 .... .... 79 EINI Kap. 5 Arrays – Internes Sortieren .... .... .... 79 79 .... .... (©M. Goedicke, UGH Essen) 8 Zuweisung an Array - Variable Dr. Lars Hildebrand Array-Größe ist fest nach Ausführung des new-Operators Veränderung der Größe nur durch Umkopieren int [] a,b; a = new int [10]; .... // Zuweisung an die Elemente 0 ..9 b = new int [20]; for (int i=0; i < 10; i++) b[i] = a[i]; a = b; // nun verweisen a und b auf das // gleiche Array! Beachte: Indizes immer 0 .. Anzahl -1 EINI Kap. 5 Arrays – Internes Sortieren 9 Zuweisungen Dr. Lars Hildebrand Bei der Deklaration einer Array-Variablen werden die Standardwerte zugewiesen z.B.: int alles 0 ... Andere Variante: Belegung mit direkt angegebenen Konstanten int [] m = {31,28,31,30,31,30,31,31,30,31,30,31}; Größe und Belegung sind direkt festgelegt keine Erzeugung mittels new notwendig Funktioniert auch für mehrdimensionale Arrays: int [] [] a={{0,1},{11,12},{21,22}}; 0 1 2 0 1 11 12 21 22 a[0][0] == 0 a[0][1] == 1 a[1][0] == 11 ... EINI Kap. 5 Arrays – Internes Sortieren (©M. Goedicke, UGH Essen) 10 Zuweisung von Array-Variablen ... Beispiel (1) Dr. Lars Hildebrand int i = 2; int [] A; A = new int [4]; A [0] = 8; A [i] = 9; A [1] = 7; A [3] = 6; EINI Kap. 5 Arrays – Internes Sortieren 11 Zuweisung von Array-Variablen ... Beispiel (2) Dr. Lars Hildebrand ... A [0] = 8; A [i] = 9; A [1] = 7; A [3] = 6; A = new int [3]; int [] B; B = A; EINI Kap. 5 Arrays – Internes Sortieren 12 Zuweisung von Array-Variablen ... Beispiel (3) Dr. Lars Hildebrand .... B = A; A [0] = 6; B [1] = 7; B [2] = B [0] + 2; i = B [0]; A = new int [5]; A [i - 2] = B [1]; B [i - 4] = A.length; EINI Kap. 5 Arrays – Internes Sortieren 13 Dynamische Größe von Arrays Dr. Lars Hildebrand Falls Größe eines Arrays zum Zeitpunkt der Erstellung nicht bekannt: die Größe könnte z.B. auch eingelesen werden In Java kann durch x.length die Anzahl (!) der Elemente dynamisch bestimmt werden: int Anz = Eingabe(), Anfangsw = 0; int [][] Matrix = new int[Anz][Anz +12]; for (int i = 0; i < Matrix.length; i++) { for (int j=0; j < Matrix[0].length;j++) { Matrix[i][j] = Anfangsw; } } Beachte: Index läuft 0.. Matrix.length -1 EINI Kap. 5 Arrays – Internes Sortieren 14 Berücksichtigung von Typen Dr. Lars Hildebrand strenges Typssystem Für einzelne Elemente eines Arrays, die selbst keine Arrays sind, ist dies klar: int [] a = new int [3]; a[1] = 3; Für Arrays gilt bei Zuweisungen: Typ der Grundelemente und die Anzahl der Dimensionen muss übereinstimmen int [][] a; ... a = b; // klappt nur, wenn b ebenfalls // 2-dimensionales int Array ist EINI Kap. 5 Arrays – Internes Sortieren 15 Komplexe Ausdrücke als Index Dr. Lars Hildebrand Beispiel Bestand der Artikel 3 .. 28 am Ort 4 int Summe = 0; for (int i=3; i<= 28; i++) Summe += Bestand[i] [4]; oder ein einfacher Palindrom-Test: boolean Palindrom = true; for (int i=1; i<=7/2 && Palindrom; i++) { Palindrom = Zeichen[i] == Zeichen[7+1-i]; } 0 1 2 3 4 5 6 7 8 R E N T N E R 1 7 2 6 3 5 (©M. Goedicke, UGH Essen) EINI Kap. 5 Arrays – Internes Sortieren 16 Arrays: Internes Sortieren Dr. Lars Hildebrand Internes Sortieren bringt die Elemente einer Folge in die richtige Ordnung Viele Alternativen bzgl. Sortieren sind entwickelt worden Das einfache interne Sortieren (wie hier vorgestellt) hat geringen Speicherplatzbedarf aber hohe Laufzeit Verfahren: Vertausche Elemente der Folge solange, bis sie in der richtigen Reihenfolge sind Hier wird als Speicherungsstruktur ein Array benutzt EINI Kap. 5 Arrays – Internes Sortieren 17 Zunächst das Einlesen der Werte Dr. Lars Hildebrand public class Sortierung { public static void main (String [] unbenutzt) { int i, j, z, n = Eingabe (); int [] a = new int [n]; // Lies Elemente ein und gib sie dabei sofort // wieder aus: System.out.println ("Die eingegebenen Elemente:"); for (i = 0; i < n; i++) { a [i] = Eingabe (); System.out.print (a [i] + " "); } System.out.println ("\n"); ... EINI Kap. 5 Arrays – Internes Sortieren 18 Nun die eigentliche Sortierung ... Dr. Lars Hildebrand Die Idee: Ausgangspunkt: Element an der Stelle i hat den richtigen Platz, dann müsste eigentlich für alle Elemente an den Stellen j > i gelten, dass a[i] <= a[j] Wenn diese Bedingung nicht gilt: vertausche die Elemente an den Stellen i und j i j Bereits sortiert,d.h. a[k] ≤a[k+1], f. k≤i-1 und a[k] ≤ a[j], f. k≤i-1 und j ∈{i..n} EINI Kap. 5 Arrays – Internes Sortieren 19 Nun die eigentliche Sortierung ... Dr. Lars Hildebrand Diese Schritte müssen für alle Elemente im Array erledigt werden for (i = 0; i < n - 1; i++) { // Prüfe, ob a[i] Nachfolger hat, die kleiner als a[i] sind: for (j = i + 1; j < n; j++) { if (a [i] > a [j]) // Ist ein Nachfolger kleiner? { // Vertausche a[i] mit a[j]: // Ringtausch mit Hilfsvariable z z = a [i]; a [i] = a [j]; a [j] = z; } } } EINI Kap. 5 Arrays – Internes Sortieren 20 Der Ablauf noch einmal tabellarisch Dr. Lars Hildebrand i 0 0 1 2 0 1 3 2 1 3 2 3 j a [0] a [1] a [2] a [3] 81 95 32 60 81 95 32 60 32 95 81 60 32 95 81 60 32 95 81 60 32 81 95 60 32 81 95 60 32 60 95 81 32 60 95 81 32 60 81 95 (©M. Goedicke, UGH Essen) EINI Kap. 5 Arrays – Internes Sortieren 21 Ausgabe Dr. Lars Hildebrand Zum Schluss wird alles noch ausgegeben // Gib sortierte Elemente aus: System.out.println ("Sortierte Elemente:"); for (i = 0; i < n; i++) System.out.print (a [i] + " "); System.out.println ("\n"); // Zeilenvorschub. EINI Kap. 5 Arrays – Internes Sortieren 22 Alternativen Dr. Lars Hildebrand Könnte man die Algorithmus Idee auch anders formulieren? finde Minimum x der aktuellen Menge positioniere x an den Anfang sortiere Restmenge nach Entfernen von x Rekursive Formulierung ? Weitere Fragen: Terminierung Korrektheit Aufwand, Effizienz EINI Kap. 5 Arrays – Internes Sortieren 23 Bemerkungen zum Aufwand Dr. Lars Hildebrand Der Aufwand wird nach Anzahl der Ausführungen von Elementaroperationen betrachtet Im wesentlichen sind das beim Sortieren Vergleiche und Zuweisungen Meist begnügt man sich mit einer vergröbernden Abschätzung Diese Abschätzung wird in der Regel von der Größe des Problems bestimmt: hier die Anzahl der zu sortierenden Elemente Obiges Sortierverfahren: zwei geschachtelte FOR-Schleifen, die im schlimmsten Fall über das gesamte Array der Größe n laufen Daher ist der Aufwand in der Größenordnung von n2 EINI Kap. 5 Arrays – Internes Sortieren 24 Bemerkungen zum Aufwand Dr. Lars Hildebrand Es stellt sich die folgende Frage: Ist es möglich schnellere Algorithmen zu entwerfen, indem man die Ermittelung des Maximums beschleunigt? Antwort nein! Jeder Algorithmus, der nur mit Vergleichen zwischen Schlüsseln arbeitet, benötigt mindestens n − 1 Vergleiche um das Maximum von n Schlüsseln zu finden. Beschleunigung also nicht im Auffinden des Maximums möglich … EINI Kap. 5 Arrays – Internes Sortieren 25 Sortieren Dr. Lars Hildebrand Sortieren: Standardproblem der Informatik Einfach zu verstehende Aufgabenstellung Tritt regelmäßig auf Grundproblem: internes Sortieren Zu sortierende Menge liegt unsortiert im Speicher vor, abhängig von der Datenstruktur zur Mengendarstellung kann (im Prinzip) auf jedes Element zugegriffen werden Es existieren viele Algorithmen, die nach Algorithmusidee, nach Speicherplatz und Laufzeit (Berechnungsaufwand) unterschieden werden Wir brauchen noch ein formales Gerüst, um Speicherplatz und Berechnungsaufwand zu charakterisieren ! EINI Kap. 5 Arrays – Internes Sortieren 26 Sortieren Dr. Lars Hildebrand Sortieren: Standardproblem der Informatik Varianten: Externes Sortieren: Daten liegen auf externem Speichermedium mit (sequentiellem) Zugriff Einfügen in sortierte Menge Verschmelzen von sortierten Mengen ... Im Folgenden: Effiziente Alternative zum letzten (naiven) Algorithmus: Heapsort Verwendung rekursiver Datenstrukturen für rekursive Algorithmen EINI Kap. 5 Arrays – Internes Sortieren 27 Rekursive Datenstrukturen Dr. Lars Hildebrand Rekursion ist nicht nur ein wichtiges Hilfsmittel für die Formulierung von Algorithmen, sondern auch für die Formulierung von Datenstrukturen. Beispiele Eine Liste ist ein Einzelelement, gefolgt von einer Liste, oder die leere Liste. Eine Menge ist leer oder eine einelementige Menge vereinigt mit einer Menge. Oder Bäume (dazu im folgenden mehr). EINI Kap. 5 Arrays – Internes Sortieren 28 Idee von Baum Dr. Lars Hildebrand Künstlerisch Abstrahiert 1 Abstrahiert 2 Die Informatiksicht: EINI Kap. 5 Arrays – Internes Sortieren 29 Binärer Baum Dr. Lars Hildebrand Definition: (Binärer Baum) 1. Der "leere" Baum ∅ ist ein binärer Baum mit der Knotenmenge ∅. 2. Seien Bi binäre Bäume mit den Knotenmengen Ki , i = 1,2. Dann ist auch B = (w, B1, B2) ein binärer Baum mit der Knotenmenge K = {w} ∪∗ K1 ∪∗ K2. (∪∗ bezeichnet disjunkte Vereinigung.) 3. Jeder binäre Baum B lässt sich durch endlich häufige Anwendung von 1.) oder 2.) erhalten. EINI Kap. 5 Arrays – Internes Sortieren 30 Binärer Baum Dr. Lars Hildebrand Sprech-/Darstellungsweisen (im Falle 2.)): Sei B = (w, B1, B2) binärer Baum w heißt Wurzel, B1 linker und B2 rechter Unterbaum. Wurzel w B1 B2 linker Unterbaum rechter Unterbaum EINI Kap. 5 Arrays – Internes Sortieren 31 Binärer Baum Dr. Lars Hildebrand Darstellung eines Beispiels nach Definition: B1 = (k1, ∅, (k2, (k3, ∅, ∅), ∅)). k1 k2 k3 EINI Kap. 5 Arrays – Internes Sortieren 32 Terminologie Binäre Bäume Dr. Lars Hildebrand Wurzel innerer Knoten Blatt EINI Kap. 5 Arrays – Internes Sortieren 33 Knotenmarkierter binärer Baum Dr. Lars Hildebrand Definition: Sei M eine Menge. (B, km) ist ein knotenmarkierter binärer Baum (mit Markierungen aus M) :⇔ 1. B ist binärer Baum (mit Knotenmenge K = K(B)) 2. km: K --> M Abbildung. (Markierung/Beschriftung der Knoten k ∈ K mit Elementen m ∈ M) EINI Kap. 5 Arrays – Internes Sortieren 34 Knotenmarkierter binärer Baum Dr. Lars Hildebrand Beispiel M := , := Menge der ganzen Zahlen Damit existiert auf M eine Ordnung! "Übliche" Darstellung der Knotenbeschriftung km durch "Anschreiben" der Beschriftung an/in die Knoten. 24 16 k2 k1 EINI Kap. 5 Arrays – Internes Sortieren 18 k3 35 Eigenschaften eines Heap Dr. Lars Hildebrand Ein Heap (Haufen) ist ein knotenmarkierter binärer Baum, so dass gilt: Die Markierungsmenge ist geordnet im Beispiel: ganze Zahlen Der binäre Baum ist links-vollständig Alle Ebenen (vgl. Breitendurchlauf) sind vollständig besetzt (bis evtl. auf die letzte); die letzte Ebene ist "von links voll aufgefüllt". Partiell angeordnete Markierungen Auf jedem Pfad von der Wurzel zu einem Blatt ist die Menge der Knotenmarkierungen monoton steigend angeordnet. EINI Kap. 5 Arrays – Internes Sortieren 36 Definition: Heap Dr. Lars Hildebrand Ein Heap (Haufen) ist ein knotenmarkierter binärer Baum, für den gilt: Die Markierungsmenge ist geordnet. Der binäre Baum ist links-vollständig. Die Knotenmarkierung der Wurzel ist kleiner oder gleich der Markierung des linken resp. rechten Sohnes (, sofern vorhanden). Die Unterbäume der Wurzel sind Heaps. An der Wurzel steht das kleinste/eines der kleinsten Element(e). EINI Kap. 5 Arrays – Internes Sortieren 37 Beispiel: Heap Dr. Lars Hildebrand Binärbaum Alle Ebene, bis auf letzte vollständig gefüllt Links-vollständig gefüllt Knotenmarkierung der Wurzel kleiner als die der Kinder EINI Kap. 5 Arrays – Internes Sortieren 38 Grobidee zum ADT Heap Dr. Lars Hildebrand Datenstruktur Operationen Init Einfügen eines Elementes in einen Heap Entfernen eines der kleinsten Elemente/des kleinsten Elementes aus dem Heap und Hinterlassen eines RestHeaps Zudem: – Heap ist leer ?/ Heap ist voll ? – Drucken – ..... EINI Kap. 5 Arrays – Internes Sortieren 39 Implementierung über Feld Dr. Lars Hildebrand Darstellung: Binärer Baum <--> Feld S[1] S[2] S[4] S[8] Array S[1] S[3] S[5] S[6] S[7] S[9] S[10] S[11] S[12] S[13] S[14] S[15] S[2] S[3] S[4] S[12] S[13] S[14] S[15] EINI Kap. 5 Arrays – Internes Sortieren 40 Implementierung über Feld Dr. Lars Hildebrand Beziehung Baum-Feld-Darstellung: Der Inhalt des i-ten Knotens in der Baumdarstellung wird im i-ten Feldelement abgelegt. – Das bedeutet: Baum ebenenweise von links nach rechts eintragen. – Das Feldelement a[0] wird nicht verwendet! Lemma: Die Söhne des Knotens i in einem Heap haben die Knotennummern – 2i : linker Sohn – 2i + 1 : rechter Sohn – Beweis: Induktiv EINI Kap. 5 Arrays – Internes Sortieren 41 Implementierung über Feld Dr. Lars Hildebrand S[1] Ebene 0 S[2] Ebene 1 S[4] Ebene 2 Ebene 3 Array S[8] S[1] S[3] S[5] S[6] S[7] S[9] S[10] S[11] S[12] S[13] S[14] S[15] S[2] S[3] S[4] S[12] S[13] S[14] S[15] In Tiefe i befinden sich die Schlüssel S[2i … 2i+1-1] EINI Kap. 5 Arrays – Internes Sortieren 42 Implementierung über Feld Dr. Lars Hildebrand linker Sohn von S[i] S[2i] rechter Sohn von S[i] S[2i+1] Vater von S[i]S[⌊i/2⌋] Ebene 0 S[3] Ebene 1 S[6] Ebene 2 Ebene 3 Array S[8] S[7] S[9] S[10] S[11] S[12] S[13] S[14] S[15] S[3] S[12] S[13] S[14] S[15] EINI Kap. 5 Arrays – Internes Sortieren 43 Heap-Eigenschaft Dr. Lars Hildebrand Die Heapeigenschaft wird über die Inhalte definiert Ein Feld a mit n ganzen Zahlen realisiert einen Heap, falls a[i/2] ≤ a[i] für alle i= 2, ...., n gilt. Der Wert des Vaters ist höchstens so groß, wie der der Söhne Dabei ist "/" als ganzzahlige Division zu verstehen. z.B. 5/2 = 2 Verzicht auf Floor( )-Funktion ⌊ ⌋ in der Notation In einem (Minimum-)Heap, realisiert durch das Feld a, steht das kleinste Element immer in a[1]. Analog wird der Maximum-Heap definiert EINI Kap. 5 Arrays – Internes Sortieren 44 Beobachtungen Dr. Lars Hildebrand Ein Feld S[1 . . . n] ist ein Heap ab l, wenn der Teilbaum mit Wurzel l ein Heap ist. Jedes Feld ist ein Heap ab ⌊n/2⌋ + 1, denn alle Einträge mit Indices ab ⌊n/2 ⌋ + 1 haben keine Kinder, d.h. der Teilbaum besteht nur aus einer Wurzel Ist S[1 . . . n] ein Heap ab l , so ist S ebenfalls ein Heap ab 2l und 2l + 1. S[1] S[2] S[4] S[8] S[1] S[3] S[5] S[6] S[7] S[9] S[10] S[11] S[12] S[13] S[14] S[15] S[2] S[3] S[4] S[12] S[13] S[14] S[15] EINI Kap. 5 Arrays – Internes Sortieren 45 Operation Einfügen: Algorithmus Dr. Lars Hildebrand Eingabe: Heap a mit n Elementen, neues Element x Ergebnis: Heap a mit n+1 Elementen, x seiner Größe gemäß eingefügt Vorgehensweise: Schaffe neuen Knoten n+1, setze a[n+1] = x Füge also neuen Knoten mit Beschriftung x in den Heap (evtl.noch an falscher Stelle) ein Sortiere an richtige Stelle ein EINI Kap. 5 Arrays – Internes Sortieren 46 Operation Einfügen Dr. Lars Hildebrand "An richtige Stelle einsortieren" - Idee: einsortieren(k) : k bezeichnet Knotennummer ist k=1, so ist nichts zu tun, ist k>1, so geschieht folgendes: – falls a[k/2] > a[k], – vertausche a[k/2] mit a[k], – rufe einsortieren(k/2) auf Verletzung der Heap-Eigenschaft einsortieren ist somit eine rekursive Funktion EINI Kap. 5 Arrays – Internes Sortieren 47 Beispiel Dr. Lars Hildebrand 3 6 Vergleich Vergleich 11 12 18 13 7 11 12 14 Vergleich 9 10 21 15 20 11 18 neuer Knoten Einfügen von 11 in unseren Heap EINI Kap. 5 Arrays – Internes Sortieren 48 Beispiel Dr. Lars Hildebrand Neuer Knoten mit k = 13 einsortieren(13) a[k/2] > a[k] ? a[6] > a[13] ? 18 > 11 ? Ja, also tauschen a[6]a[13] einsortieren(6) a[k/2] > a[k] ? a[3] > a[6] ? 12 > 11 ? Ja, also tauschen a[3]a[6] einsortieren(3) – a[k/2] > a[k] ? a[1] > a[3] ? 3 > 11 ? Nein, fertig EINI Kap. 5 Arrays – Internes Sortieren 49 Code: einsortieren Dr. Lars Hildebrand In das Feld HeapFeld wird richtig einsortiert gemäß: void einsortieren(int Knoten_Nr) { if (Knoten_Nr > 1) { int Vater_Nr = Knoten_Nr/2; if (HeapFeld[Knoten_Nr] < HeapFeld[Vater_Nr]) { Tausche(HeapalsFeld[Knoten_Nr], HeapalsFeld[Vater_Nr]); einsortieren(Vater_Nr); } } } EINI Kap. 5 Arrays – Internes Sortieren 50 Entfernen des kleinsten Elementes Dr. Lars Hildebrand Idee einer Hau-Ruck-Lösung: Entfernen des kleinsten Elements Baue einen neuen Heap ohne das erste Element auf z.B. durch sukzessives Einfügen der Elemente in einen neuen Heap Nachteil Berücksichtigt nicht, dass vor dem Entfernen des kleinsten Elements ein Heap vorliegt Idee einer effizienteren Lösung Verwende genau diese Information EINI Kap. 5 Arrays – Internes Sortieren 51 Erzeugung eines Heaps Dr. Lars Hildebrand Wie behält man in diesem Fall einen Heap? Beobachtung Jedes Blatt erfüllt die Heapbedingung Allgemeinere Situation: Wurzel erfüllt die Heap-Bedingung ? Unterbäume sollen die Heap-Bedingung erfüllen EINI Kap. 5 Arrays – Internes Sortieren 52 Erzeugung eines Heaps Dr. Lars Hildebrand Idee: Lasse „die Wurzel einsinken“ Vergleiche den Eintrag im Knoten k mit denen seiner Söhne (soweit vorhanden) Falls der Eintrag im Knoten k kleiner oder gleich als diejenigen beider Söhne ist o.k. Falls der Eintrag des Knotens k größer als der kleinere Eintrag beider Söhne ist: – Ermittle den Sohn s mit dem kleineren Eintrag, – Vertausche den Eintrag des Knotens k mit demjenigen des Sohnes s, Wiederhole die Überlegungen mit diesem Knoten s. EINI Kap. 5 Arrays – Internes Sortieren 53 Beispiel Dr. Lars Hildebrand Heap-Bedingung verletzt ok 9 12 6 8 Vergleich 86 3 Vergleich 10 15 18 10 13 14 20 EINI Kap. 5 Arrays – Internes Sortieren 54 Code: Heapify Dr. Lars Hildebrand void Heapify(int K) { int LS_Nr = 2*K, RS_Nr = 2*K + 1, sel_Sohn; // Nummer des linken Sohns // Nummer des rechten Sohns // Nummer des selektierten Sohns if (LS_Nr <= AnzahlKnoten && RS_Nr > AnzahlKnoten) { // es gibt keinen rechten Sohn if (HeapFeld[LS_Nr] < HeapFeld[K]) Tausche(HeapFeld[K], HeapFeld[LS_Nr]); } else if (RS_Nr <= AnzahlKnoten) { // es existieren linker und rechter Sohn sel_Sohn=(HeapFeld[LS_Nr]<HeapFeld[RS_Nr] ? LS_Nr : RS_Nr); // wähle den Sohn mit der kleineren Markierung aus. // Bei Gleichheit wähle den rechten Sohn. if (HeapFeld[sel_Sohn] < HeapFeld[K]) { // ist Heap-Bedingung verletzt? Tausche(HeapFeld[K], HeapFeld[sel_Sohn]); Heapify(selektierter_Sohn); } } } EINI Kap. 5 Arrays – Internes Sortieren 55 Anmerkung zur Heapkonstruktion Dr. Lars Hildebrand Heapify kann dazu herangezogen werden, aus einem Feld A mit n Elementen einen Heap zu konstruieren die Blätter sind bereits Heaps, hat Knoten k also Blätter zu Söhnen, so erfüllen seine Unterbäume die Heap-Bedingung, durchlaufe die Knoten rückwärts von n/2 bis 1 und rufe Heapify für jeden Knoten auf, für n >= j >= n/2 ist der Knoten j ein Blatt EINI Kap. 5 Arrays – Internes Sortieren 56 Anwendung 1: Heapsort Dr. Lars Hildebrand Aufgabe: Benutze Heap zum (effizienten) Sortieren. Heapsort arbeitet in zwei Phasen: Aufbau eines Heaps aus einem Feld Schrittweiser Abbau des Heaps – Auslesen des Wurzelelementes und Entfernen desselben – Legen des "letzten" Elementes in die Wurzel – Rekonstruktion der Heap-Bedingung für diese restlichen Elemente. EINI Kap. 5 Arrays – Internes Sortieren 57 Quicksort (nach C.A. Hoare) Dr. Lars Hildebrand Gutes Bsp, dass bessere Algorithmen mehr bringen können als ausgefeilte, systemnahe Programmierung Strategie: divide et impera, teile & herrsche, divide & conquer Idee: wähle einen Wert w des Sortierfeldes aus partitioniere Elemente in 2 Teilmengen, die selbst noch unsortiert sind – A1, deren Elemente <= w sind, – A2, deren Elemente >= w sind sortiere die Teilmengen A1 und A2 (getrennt, rekursiv) A1 w Sortierfeldes A2 nach w Besonderheit: Partitionierung des 1 2 ... k-1 k k+1 ... n EINI Kap. 5 Arrays – Internes Sortieren 58 Quicksort Dr. Lars Hildebrand Teilalgorithmus zur Partitionierung, (vereinfacht) wähle w aus dem Array suche Eintrag an einer Position i von links mit a[i] >= w suche Eintrag an einer Position j von rechts mit a[j] <= w vertausche a[i] mit a[j] wiederhole ab 2. bis i >= j erreicht ist EINI Kap. 5 Arrays – Internes Sortieren 59 Quicksort Dr. Lars Hildebrand Auswahl von w hat Einfluss auf die Güte des Verfahrens warum ? Auswahlverfahren: betrachte a[links], a[(links+rechts)/2], a[rechts] Variante 1: wähle eines der drei Elemente Variante 2: wähle das wertmäßig mittlere Element Erfahrungen: Variante 1 ist bei zufällig verteilten Daten gut Variante 2 ist bei ungünstig verteilten Daten gut EINI Kap. 5 Arrays – Internes Sortieren 60 Quicksort Dr. Lars Hildebrand Variante1 jeweils mitte SORTIERBEISPIEL li=0 mitte=7 re=14 Variante2, vorsortieren li, mitte, re SORTIERBEISPIEL BORTIERLEISPIES BORTIERSEISPIEL BEIIIEELRTSPROS BORLIEREEIIPSST BEIEIEILPTSRROS BOPLIEIEEIRRSST BEEEIIILPORRSTS EINI Kap. 5 Arrays – Internes Sortieren 61 Quicksort Dr. Lars Hildebrand void quicksort(char [] A){ int high = A.length-1 ; rekquicksort(A,0,high) ; } void rekquicksort(char[] A, int low, int high){ int li = low, re = high, mid = (li+re)/2 ; if (A[li] > A[mid]) tausche(A,li,mid) ; //Vorsortieren if (A[mid] > A[re]) tausche(A,mid,re) ; //Vorsortieren if (A[li] > A[mid]) tausche(A,li,mid) ; //Vorsortieren if ((re-li) > 2) { // mehr als 3 Werte char w = A[mid] ; // mittlerer Wert do { while (A[li]<w) li++; // Suche nach while (w < A[re]) re-- ; // Tauschkandidaten if (li <= re) { tausche(A,li,re) ; li++ ; re-- ; } while (li <= re) ; if (low < re) rekquicksort(A,low,re) ; if (li < high) rekquicksort(A,li,high) ; } } EINI Kap. 5 Arrays – Internes Sortieren 62 Testfragen Dr. Lars Hildebrand Quicksort ist ein rekursiver Algorithmus Von welcher Art ist die Rekursion ? Lässt sich die Anzahl rekursiver Aufrufe wie bei Fibonacci durch akkumulierende Parameter reduzieren ? Vergleich der Algorithmen Was ist die Idee/Strategie beim naiven 1. Algorithmus, bei Heapsort, Quicksort? Warum terminiert der 1. Algorithmus, Heapsort, Quicksort ? Warum ist der 1. Algorithmus, Heapsort, Quicksort korrekt ? Welcher Algorithmus ist besser ? – Was spricht für den 1. Algorithmus ? – Was spricht für Heapsort ? – Was spricht für Quicksort ? EINI Kap. 5 Arrays – Internes Sortieren 63 Zusammenfassung Dr. Lars Hildebrand Arrays Datenstruktur zur Abbildung gleichartiger Daten Deklaration Dimensionierung und Zuordnung von Speicher zur Laufzeit Zuweisung: ganzes Array, Werte einzelner Elemente Speicherfreigabe durch Garbage Collection (Java) oder explizit (C/C++) Algorithmen auf Arrays: Beispiel Sortieren naives Verfahren: Minimum bestimmen, entfernen, Restmenge sortieren Heapsort: ähnlich, nur mit Binärbaum über Indexstruktur Quicksort: divide&conquer, zerlegen in 2 Teilmengen anhand eines Pivotelementes Für uns offen: Welches Verfahren ist besser ? EINI Kap. 5 Arrays – Internes Sortieren 64