Kurs:Algorithmen und Datenstrukturen/Vorlesung/Heap Sort Analyse




Analyse Bearbeiten

Lemma 1 Bearbeiten

Der Aufruf makeHeap(f) macht aus f einen Heap, das heißt für alle   gilt   und  , wobei   ist.

Beweis Bearbeiten

Der Beweis erfolgt durch Induktion nach i=f.length-1.

i=0: Ein ein-elementiges Array ist stets ein Heap nach Definition

i‐1‐>i: Nach Induktionsvoraussetzung ist f[0..i‐1]  ein Heap. In der Methode  siftUp(f,idx) wird zunächst das neue Element mit seinen Eltern verglichen. Ggfs. werden die Werte getauscht und es wird bottom-up fortgefahren. Da ein Knoten dadurch höchstens einen größeren Wert erhält bleibt die Heap‐Eigenschaft bestehen. 

Lemma 2 Bearbeiten

Ist f[0...i‐1] ein Heap bei dem maximal für den  Wurzelknoten die Heap‐Eigenschaft verletzt ist, so ist  nach reHeap(f,i‐1) das Array f[0...i‐1] ein Heap. 

Beweis Bearbeiten

In reHeap wird zunächst der Wurzelknoten mit seinen  beiden Kindern verglichen. Ist der Wert der Wurzel  nicht kleiner als die Werte beider Kinder, so terminiert  die Methode. Damit ist f[0...i‐1] ein Heap.  Andernfalls wird der Wert der Wurzel mit dem größten  Wert seiner Kinder vertauscht, die Heap‐Eigenschaft ist damit an der Wurzel wiederhergestellt. Anschließend  wird iterativ mit dem vertauschten Kind fortgefahren.  Nach Induktion folgt dann, dass f[0...i‐1] am Ende ein  Heap ist.  

Theorem 1 Bearbeiten

Der Algorithmus heapSort löst das Problem des  vergleichsbasierten Sortierens. 

Beweis Bearbeiten

Folgt direkt aus den vorherigen beiden Lemmata und  der Beobachtung, dass in jedem Schritt der heapSort‐ Methode das größte Element an das Ende des Arrays  getauscht wird und nur noch ein um eins verkleinertes  Array betrachtet wird. 

Theorem 2 Bearbeiten

Der Algorithmus heapSort(f) terminiert für jede  Eingabe f nach endlicher Zeit. 

Beweis Bearbeiten

Die Hauptmethode heapSort verfügt über eine  konstante Anzahl an Schleifendurchläufen. In jedem  rekursiven Aufruf von makeHeap wird der Index echt  verringert, bei Index 0 ist der Rekursionsanfang  erreicht. In reHeap wird die Variable current in jedem Durchgang um mindestens 1 erhöht und bei Erreichen  von „end“ wird abgebrochen.  

Theorem 3 Bearbeiten

Der Algorithmus heapSort hat einen Aufwand von  O(n log n), sowohl für den besten, schlechtesten, und  mittleren Fall. 

Beweis Bearbeiten

Für makeHeap gilt:  Wir fügen jeden der n Knoten dazu   

  • Auf jeden Knoten wird siftUp ausgeführt – möglicherweise bis zum Wurzelknoten 
  • Da der Binärbaum perfekt balanciert ist, benötigt siftUp() auf einem einzelnen Knoten O(log n) Zeit 
  • Weil wir das n‐mal machen, benötigen wir n*O(log n) viel Zeit, d.h. O(n log n) 

Für   

for(int i = f.length - 1; i > 0; i--){
   swap(f,0,i);
   reHeap(f,i-1);

}  

 

gilt:  

  • Die Schleife wird n‐mal (genauer n‐1 mal) durchlaufen,weil wir immer einen der n Knoten entfernen  
  • Entfernen und Ersetzen des Wurzelknotens beansprucht O(1) viel Zeit 
  • Deswegen beträgt die Gesamtzeit n, für das Entfernen und Ersetzen (ohne reHeap) 
  • Um reheap auf den Wurzelknoten auszuführen, müssen wir einen Pfad von der Wurzel bis zu einem Blattknoten verfolgen (eventuell können wir früher aufhören) 
  • Der Binärbaum ist perfekt balanciert 
  • Deswegen ist dieser Pfad O(log n) lang 
    • Und wir führen nur O(1) Operationen auf jedem Knoten aus 
    • Deswegen benötigt reheap O(log n) viel Zeit 
  • Weil wir reheap innerhalb einer while‐Schleife ausführen, benötigen wir hierfür O(n log n) Die Gesamtzeit ist deswegen:  O(n log n) + O(n log n) = O(n log n) 

 

Literatur Bearbeiten

Da die Vorlesungsinhalte auf dem Buch Algorithmen und Datenstrukturen: Eine Einführung mit Java von Gunter Saake und Kai-Uwe Sattler aufbauen, empfiehlt sich dieses Buch um das hier vorgestellte Wissen zu vertiefen. Die auf dieser Seite behandelten Inhalte sind in Kapitel 14.6.1 zu finden.