Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido

Ähnliche Präsentationen


Präsentation zum Thema: "EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido"—  Präsentation transkript:

1

2 EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido moraga@cs.uni-dortmund.de

3 Kap 12: HeapVorl EINI-I" 2 1.2.2001 Gliederung Kapitel 12 Zum Datentyp Heap –Beispiel eines Heaps –Eigenschaften eines Heaps –Definition des Heaps –Datentyp Heap –Zur Implementierung mittels eines Feldes Anwendungen –Heapsort –Prio-Warteschlangen, mit Heaps implementiert

4 Kap 12: HeapVorl EINI-I" 3 1.2.2001 Beispiel: Heap 3 6 12 7 13 18 9 10 21 13 14 20 Inhalt der Knoten 1 2 3 45 89101112 67 Platznummer der Knoten

5 Kap 12: HeapVorl EINI-I" 4 1.2.2001 Eigenschaften eines Heaps Ein Heap (Haufen) ist ein knotenmarkierter binärer Baum, so daß 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.

6 Kap 12: HeapVorl EINI-I" 5 1.2.2001 Definition: Heap 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 (Knoten 1) steht das kleinste/eines der kleinsten Element(e).

7 Kap 12: HeapVorl EINI-I" 6 1.2.2001 Grobidee zum ADT Heap Datenstruktur Operationen –Init –Einfügen eines Elementes in einen Heap –Entfernen eines der kleinsten Elemente/des kleinsten Elementes aus dem Heap und Hinterlassen eines Rest-Heaps –Zudem: Heap ist leer ?/ Heap ist voll ? Drucken.....

8 Kap 12: HeapVorl EINI-I" 7 1.2.2001 Implementierung über Feld 623471826 17 623471826 1 2 3 456 7 1234567 Binärer Baum: Feld: Darstellung: Binärer Baum Feld

9 Kap 12: HeapVorl EINI-I" 8 1.2.2001 Implementierung über Feld 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

10 Kap 12: HeapVorl EINI-I" 9 1.2.2001 Implementierung über Feld Ein Feld a mit n ganzen Zahlen realisiert einen Heap, falls a[i/2] < a[i] für alle i= 1,...., n gilt. –Dabei ist "/" als ganzzahlige Division zu verstehen. z.B. 5/2 = 2 In einem (Minimum-)Heap, realisiert durch das Feld a, steht das kleinste Element immer in a[1].

11 Kap 12: HeapVorl EINI-I" 10 1.2.2001 Operation Einfügen: Idee Einfügen von 11 in unseren Heap 3 6 12 7 13 18 9 10 21 15 14 20 neuer Knoten 11 Vergleich 18 11 Vergleich 11 12 Vergleich Beispiel:

12 Kap 12: HeapVorl EINI-I" 11 1.2.2001 Operation Einfügen: Algorithmus 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.

13 Kap 12: HeapVorl EINI-I" 12 1.2.2001 Operation Einfügen "An richtige Stelle einsortieren" - Idee: einsortieren(k) : 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. Hier ist nämlich die Heap-Bedingung verletzt. Anmerkungen: k/2 ganzzahlige Division k = 0 wird ausgelassen !

14 Kap 12: HeapVorl EINI-I" 13 1.2.2001 Operation Einfügen void Heap::einsortieren(int Knoten_Nr) { if (Knoten_Nr > 1) { int DerVater_Nr = Knoten_Nr/2; if (HeapalsFeld[Knoten_Nr] < HeapalsFeld[DerVater_Nr]) { Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[DerVater_Nr]); einsortieren(DerVater_Nr); } } } In das Feld HeapalsFeld wird richtig einsortiert gemäß:

15 Kap 12: HeapVorl EINI-I" 14 1.2.2001 Operation Entfernen 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, daß vor dem Entfernen des kleinsten Elements ein Heap vorliegt. Idee einer effizienteren Lösung: –Verwende genau diese Information

16 Kap 12: HeapVorl EINI-I" 15 1.2.2001 // Heap als ADT // JW: 3.2.2000 V1.0 // Vorlage gemaess EED-Quelltext #include #include // für double pow (double d, int i) #include // fuer INT_MIN const int maxKnoten = 70; const int unDef=INT_MIN; struct Heap { public: void Init(); void Einfuegen(int); int Entfernen(); bool IstLeer(); bool IstVoll();int Kopf(); void Druck(); private: int HeapalsFeld[maxKnoten + 1]; // Heap ´//beginnt mit Index 1, Index 0 wird nicht verwendet! int AnzahlKnoten; void einsortieren(int); void Tausche(int *, int *); };

17 Kap 12: HeapVorl EINI-I" 16 1.2.2001 // Heap als ADT Fortsetzung void Heap::Init() { AnzahlKnoten = 0; } bool Heap::IstLeer() { return (AnzahlKnoten == 0 ? true : false); } bool Heap::IstVoll() { return (AnzahlKnoten >= maxKnoten + 1 ? true : false); // Heap beginnt mit Index 1! } int Heap::Kopf() { return (IstLeer() ? unDef : HeapalsFeld[1]); }

18 Kap 12: HeapVorl EINI-I" 17 1.2.2001 // Heap als ADT Fortsetzung void Heap::Tausche(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void Heap::einsortieren(int Knoten_Nr) { if (Knoten_Nr > 1) { int DerVater_Nr = Knoten_Nr/2; if (HeapalsFeld[Knoten_Nr] < HeapalsFeld[DerVater_Nr]) { Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[DerVater_Nr]); einsortieren(DerVater_Nr); }

19 Kap 12: HeapVorl EINI-I" 18 1.2.2001 // Heap als ADT Fortsetzung void Heap::Einfuegen(int Knotenmarkierung) { if (!IstVoll()) { HeapalsFeld[++AnzahlKnoten] = Knotenmarkierung; /* fuegen den Knoten ganz rechts in der letzten Ebene des Heaps ein*/ einsortieren(AnzahlKnoten); }

20 Kap 12: HeapVorl EINI-I" 19 1.2.2001 // Heap als ADT Fortsetzung int Heap::Entfernen() { /* Löschen eines Elementes durch Einfügen der Elemente 2- AnzahlKnoten in einen Hilfsheap und dann element-weises Einfügen des Hilfsheap in den "echten" Heap */ int Anz=AnzahlKnoten; int HilfsHeapalsFeld[maxKnoten + 1]; int BeschriftungWurzel; BeschriftungWurzel=HeapalsFeld[1]; for (int i = 1; i < Anz; i++) HilfsHeapalsFeld[i] = HeapalsFeld[i + 1]; Init(); for (int i = 1; i < Anz; i++) Einfuegen(HilfsHeapalsFeld[i]); return BeschriftungWurzel; }

21 Kap 12: HeapVorl EINI-I" 20 1.2.2001 // Heap als ADT Fortsetzung void Heap::Druck() { int n=1,x; for (int i = 1; i <= AnzahlKnoten; i++) { cout << HeapalsFeld[i] << " # "; x=(pow (2,n))-1; // Ordnungszahl des letzten Knotens einer Ebene if ((i%x)==0) // letzter Knoten der Ebene n? { cout << endl; n++; // Neue Ebene beginnen } cout << "\n___________________" << endl; }

22 Kap 12: HeapVorl EINI-I" 21 1.2.2001 Wie erzeugt man dann einen Heap? Beobachtung: jedes Blatt erfüllt die Heapbedingung Allgemeinere Situation: Wurzel erfüllt die Heap-Bedingung ? Unterbäume mögen die Heap- Bedingung erfüllen Vorgehen?

23 Kap 12: HeapVorl EINI-I" 22 1.2.2001 Heap-Erzeugung 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.

24 Kap 12: HeapVorl EINI-I" 23 1.2.2001 Beispiel 3 8 10 9 1513 12 18 14 20 Heap-Bedingung verletzt Vergleich 6 68 ok

25 Kap 12: HeapVorl EINI-I" 24 1.2.2001 Code zu "Erzeuge Heap", falls... void Heap::heapify(int Knoten_Nr) { int LinkerSohn_Nr = 2*Knoten_Nr, RechterSohn_Nr = 2*Knoten_Nr + 1, selektierter_Sohn; if (LinkerSohn_Nr <= AnzahlKnoten && RechterSohn_Nr > AnzahlKnoten) // es gibt keinen rechten Sohn {if (HeapalsFeld[LinkerSohn_Nr] < HeapalsFeld[Knoten_Nr]) Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[LinkerSohn_Nr]); } else if (RechterSohn_Nr <= AnzahlKnoten) { // es existieren linker und rechter Sohn selektierter_Sohn = (HeapalsFeld[LinkerSohn_Nr] < HeapalsFeld[RechterSohn_Nr] ? LinkerSohn_Nr : RechterSohn_Nr); /* wähle den Sohn mit der kleineren Markierung aus. Bei Gleichheit wähle den rechten Sohn.*/

26 Kap 12: HeapVorl EINI-I" 25 1.2.2001 Code zu "Erzeuge Heap", falls... // Fortsetzung von void Heap::heapify if (HeapalsFeld[selektierter_Sohn] < HeapalsFeld[Knoten_Nr]) // ist Heap-Bedingung verletzt? { Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[selektierter_Sohn]); heapify(selektierter_Sohn); }}}

27 Kap 12: HeapVorl EINI-I" 26 1.2.2001 // 12_2_ADT_Heap: Heap als ADT // JW: 3.2.2000 V1.0 // Vorlage gemaess EED-Quelltext // #include #include // für double pow (double d, int i) #include // fuer INT_MIN const int maxKnoten = 70; const int unDef=INT_MIN; struct Heap { public: void Init(); void Einfuegen(int); int Entfernen(); bool IstLeer(); bool IstVoll();int Kopf(); void Druck(); private: int HeapalsFeld[maxKnoten + 1]; // Heap // beginnt mit Index 1, Index 0 wird nicht verwendet! int AnzahlKnoten; void einsortieren(int); void Tausche(int *, int *); void heapify(int);};

28 Kap 12: HeapVorl EINI-I" 27 1.2.2001 // Heap als ADT Fortsetzung void Heap::Init() { AnzahlKnoten = 0; } bool Heap::IstLeer() { return (AnzahlKnoten == 0 ? true : false); } bool Heap::IstVoll() { return (AnzahlKnoten >= maxKnoten + 1 ? true : false); // Heap beginnt mit Index 1! } int Heap::Kopf() { return (IstLeer() ? unDef : HeapalsFeld[1]); }

29 Kap 12: HeapVorl EINI-I" 28 1.2.2001 // Heap als ADT Fortsetzung void Heap::Tausche(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void Heap::einsortieren(int Knoten_Nr) { if (Knoten_Nr > 1) { int DerVater_Nr = Knoten_Nr/2; if (HeapalsFeld[Knoten_Nr] < HeapalsFeld[DerVater_Nr]) { Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[DerVater_Nr]); einsortieren(DerVater_Nr); }

30 Kap 12: HeapVorl EINI-I" 29 1.2.2001 // Heap als ADT Fortsetzung void Heap::Einfuegen(int Knotenmarkierung) { if (!IstVoll()) { HeapalsFeld[++AnzahlKnoten] = Knotenmarkierung; /* fuegen den Knoten ganz rechts in der letzten Ebene des Heaps ein*/ einsortieren(AnzahlKnoten); } int Heap::Entfernen() { int WurzelBeschriftung; WurzelBeschriftung = HeapalsFeld[1]; HeapalsFeld[1] = HeapalsFeld[AnzahlKnoten--]; heapify(1); return WurzelBeschriftung; }

31 Kap 12: HeapVorl EINI-I" 30 1.2.2001 // Heap als ADT Fortsetzung void Heap::heapify(int Knoten_Nr) { int LinkerSohn_Nr = 2*Knoten_Nr, RechterSohn_Nr = 2*Knoten_Nr + 1, selektierter_Sohn; if (LinkerSohn_Nr <= AnzahlKnoten && RechterSohn_Nr > AnzahlKnoten) // es gibt keinen rechten Sohn {if (HeapalsFeld[LinkerSohn_Nr] < HeapalsFeld[Knoten_Nr]) Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[LinkerSohn_Nr]); }

32 Kap 12: HeapVorl EINI-I" 31 1.2.2001 // Heap als ADT Fortsetzung // Heapify Fortsetzung else if (RechterSohn_Nr <= AnzahlKnoten) { // es existieren linker und rechter Sohn selektierter_Sohn = (HeapalsFeld[LinkerSohn_Nr] < HeapalsFeld[RechterSohn_Nr] ? LinkerSohn_Nr : RechterSohn_Nr); /* wähle den Sohn mit der kleineren Markierung aus. Bei Gleichheit wähle den rechten Sohn.*/ if (HeapalsFeld[selektierter_Sohn] < HeapalsFeld[Knoten_Nr]) // ist Heap-Bedingung verletzt? { Tausche(&HeapalsFeld[Knoten_Nr], &HeapalsFeld[selektierter_Sohn]); heapify(selektierter_Sohn); }}}

33 Kap 12: HeapVorl EINI-I" 32 1.2.2001 // Heap als ADT Fortsetzung int zweierpotenz(int); void Heap::Druck() { int n=1,x; for (int i = 1; i <= AnzahlKnoten; i++) { cout << HeapalsFeld[i] << " # "; x = zweierpotenz(n) - 1; // Ordnungszahl des letzten Knotens einer Ebene if ((i%x)==0) // letzter Knoten der Ebene n? { cout << endl; n++; // Neue Ebene beginnen } cout << "\n___________________" << endl; }

34 Kap 12: HeapVorl EINI-I" 33 1.2.2001 int zweierpotenz(int n){ int p; for (p = 1; n>0; --n) p = p*2; return p; }

35 Kap 12: HeapVorl EINI-I" 34 1.2.2001 Anmerkung zur Heapkonstruktion 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

36 Kap 12: HeapVorl EINI-I" 35 1.2.2001 Implementierung des ADTs Heap const int maxKnoten = 70;... struct Heap { public: void Init(); void Einfuegen(int); int Entfernen(); bool IstLeer(); bool IstVoll();int Kopf(); void Druck(); private: int HeapalsFeld[maxKnoten + 1]; /* Heap beginnt mit Index 1, Index 0 wird nicht verwendet! */ int AnzahlKnoten; void einsortieren(int); void Tausche(int *, int *); void heapify(int);};

37 Kap 12: HeapVorl EINI-I" 36 1.2.2001 Anwendung 1: Heapsort 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.

38 Kap 12: HeapVorl EINI-I" 37 1.2.2001 // 12_3_Heapsort.PPT #include #include "12_2_ADT_Heap.cpp" main() { Heap * HeapfuerHeapsort = new Heap; int unsortierteFolge[10] = {9, 33, 2, 3, 14, 77, 4, 112, 6, 5}; int Wurzel; HeapfuerHeapsort->Init(); //(*HeapfuerHeapsort).Init( ) cout << "Heap aufbauen" << endl; for (int i=0; i < 10; i++) { HeapfuerHeapsort-> Einfuegen(unsortierteFolge[i]); HeapfuerHeapsort->Druck(); } cout <<"\n\nund jetzt die sortierte Folge: "<< endl; while (!HeapfuerHeapsort->IstLeer()) { Wurzel=HeapfuerHeapsort->Entfernen(); cout << Wurzel << ", ";} cout << endl;}

39 Kap 12: HeapVorl EINI-I" 38 1.2.2001 Anwendung 2: PrioQueue mit Heaps Aufgabe: –Benutze Heap zum Implementieren einer Prioritätswarteschlange.

40 Kap 12: HeapVorl EINI-I" 39 1.2.2001 // 12_4_PQ_mit_Heap.PPT #include #include "12_2_ADT_Heap.cpp" Heap * PQ_Druck (Heap *); // Prototypen // Implementierungen Heap * PQ_Druck (Heap *Warteschlange){ int WurzelBeschriftung; Heap * Warteschlange2 = new Heap; Warteschlange2->Init(); while (!Warteschlange->IstLeer()) { WurzelBeschriftung=Warteschlange->Entfernen(); cout << WurzelBeschriftung << ", "; Warteschlange2->Einfuegen(WurzelBeschriftung); } cout << endl; return Warteschlange2; }

41 Kap 12: HeapVorl EINI-I" 40 1.2.2001 // 12_4_PQ_mit_Heap.PPT - Fortsetzung main() { Heap * Warteschlange = new Heap; int a[7] = {1, 1, 2, 3, 1, 4, 4}; Warteschlange->Init(); for (int i=0; i < 7; i++) { Warteschlange->Einfuegen(a[i]); Warteschlange=PQ_Druck(Warteschlange); } cout << "\n\nund jetzt die Entfernung: " << endl; while (!Warteschlange->IstLeer()) { Warteschlange->Entfernen(); Warteschlange=PQ_Druck(Warteschlange); }

42 Kap 12: HeapVorl EINI-I" 41 1.2.2001 Rückblick binäre Suchbäume Tiefendurchläufe durch einen binären Baum Breitendurchlauf durch einen binären Baum Studium von Warteschlangen, dabei Entdeckung von ADTs ADT Prioritäts- Warteschlange Studium von Heaps Heapsort


Herunterladen ppt "EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido"

Ähnliche Präsentationen


Google-Anzeigen