<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Heapsort</id>
	<title>Heapsort - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Heapsort"/>
	<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Heapsort&amp;action=history"/>
	<updated>2026-05-27T05:42:41Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Wikipedia (Deutsch) – Lokale Kopie</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki-de.moshellshocker.dns64.de/index.php?title=Heapsort&amp;diff=24916&amp;oldid=prev</id>
		<title>imported&gt;Darkking3: lf m</title>
		<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Heapsort&amp;diff=24916&amp;oldid=prev"/>
		<updated>2025-04-24T11:20:54Z</updated>

		<summary type="html">&lt;p&gt;lf m&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Datei:Sorting heapsort anim.gif|gerahmt|rechts|Der Heapsort-Algorithmus beim Sortieren eines Arrays aus permutierten Werten. Der Algorithmus besteht aus zwei Schritten; im vorbereitenden Schritt wird das Array zu einem binären Heap umgeordnet, dessen Baumstruktur vor dem eigentlichen Sortierschritt kurz eingeblendet wird.]]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Heapsort&amp;#039;&amp;#039;&amp;#039; („Haldensortierung“) ist ein in den 1960ern von [[Robert W. Floyd]] und {{nowrap|[[J. W. J. Williams]]}} entwickeltes [[Sortierverfahren]]. Seine [[Komplexitätstheorie|Komplexität]] ist bei einem [[Array (Datentyp)|Array]] der Länge &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; in der [[Landau-Symbole|Landau-Notation]] ausgedrückt in &amp;lt;math&amp;gt; \mathcal{O}(n \cdot \log n) &amp;lt;/math&amp;gt; und ist damit asymptotisch optimal für Sortieren per Vergleich. Heapsort arbeitet zwar [[in-place]], ist jedoch nicht [[Stabilität (Sortierverfahren)|stabil]]. Der Heapsort-Algorithmus verwendet einen [[Binärer Heap|binären Heap]] als zentrale [[Datenstruktur]]. Heapsort kann als eine Verbesserung von [[Selectionsort]] verstanden werden und ist mit [[Treesort]] verwandt.&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
&lt;br /&gt;
Die Eingabe ist ein [[Array (Datentyp)|Array]] mit zu sortierenden Elementen. Als erstes wird die Eingabe in einen [[Binärer Heap|binären Max-Heap]] [[Binärer Heap#Build|überführt]]. Aus der [[Binärer Heap#Struktur|Heap-Eigenschaft]] folgt direkt, dass nun an der ersten Array-Position das größte Element steht. Dieses wird mit dem letzten Array-Element vertauscht und die Heap-Array-Größe um 1 verringert, ohne den Speicher freizugeben. Die neue [[Binärbaum|Wurzel]] des Heaps kann die Heap-Eigenschaft verletzen. Die [[Binärer Heap#Heapify|Heapify-Operation]] korrigiert gegebenenfalls den Heap, so dass nun das nächstgrößere bzw. gleich große Element an der ersten Array-Position steht. Die Vertausch-, Verkleiner- und Heapify-Schritte werden so lange wiederholt, bis die Heap-Größe 1 ist. Danach enthält das Eingabe-Array die Elemente in aufsteigend sortierter Reihenfolge. In [[Pseudocode]]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
heapsort(Array A)&lt;br /&gt;
  build(A)&lt;br /&gt;
  assert(isHeap(A, 0))&lt;br /&gt;
  tmp = A.size&lt;br /&gt;
  while (A.size &amp;gt; 1)&lt;br /&gt;
    A.swap(0, A.size - 1)&lt;br /&gt;
    A.size = A.size - 1&lt;br /&gt;
    heapify(A)&lt;br /&gt;
    assert(isHeap(A, 0))&lt;br /&gt;
  A.size = tmp&lt;br /&gt;
  assert(isSorted(A))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einer Sortierung in absteigender Reihenfolge wird statt des Max-Heaps ein Min-Heap verwendet. In einem Min-Heap steht an erster Stelle das kleinste Element. Gemäß der Definition von einem binären Heap wird die Abfolge der Elemente in einem [[Heap (Datenstruktur)|Heap]] durch eine Vergleichsoperation (siehe [[Ordnungsrelation]]) bestimmt, die eine [[totale Ordnung]] auf den Elementen definiert. In einem Min-Heap ist das die &amp;lt;math&amp;gt;&amp;lt;&amp;lt;/math&amp;gt;-Relation und in einem Max-Heap die &amp;lt;math&amp;gt;&amp;gt;&amp;lt;/math&amp;gt;-Relation. Der Pseudocode abstrahiert von der Vergleichsoperation.&lt;br /&gt;
&lt;br /&gt;
Die zu sortierenden Elemente werden auch als [[Nummerung|Schlüssel]] bezeichnet. Pro Index-Position kann das Eingabe-[[Array (Datentyp)|Array]] mehrere Datenkomponenten enthalten. In dem Fall muss eine Komponente als Sortierschlüssel definiert werden, auf der die Vergleichsoperation arbeitet. Die Vertauschoperation vertauscht komplette Array-Einträge.&lt;br /&gt;
&lt;br /&gt;
Die assert-Operation im [[Pseudocode]] dokumentiert, welche Eigenschaften das Array nach welchen [[Algorithmus]]-Schritten korrekterweise erfüllt bzw. erfüllen muss.&lt;br /&gt;
&lt;br /&gt;
== Beispiel ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Heapsort.svg|600px|zentriert|Ein Beispiel für Heapsort an einer Zahlenfolge]]&lt;br /&gt;
&lt;br /&gt;
In der Abbildung wird die Sortierung der Beispielzahlenfolge&lt;br /&gt;
&lt;br /&gt;
  23 1 6 19 14 18 8 24 15&lt;br /&gt;
&lt;br /&gt;
mit dem Heapsort-Algorithmus dargestellt. Die einzelnen Teilbilder sind von links nach rechts und von oben nach unten chronologisch angeordnet. Im ersten Teilbild ist die unsortierte Eingabe und im letzten die sortierte Ausgabe abgebildet. Der Übergang vom ersten zum zweiten Teilbild entspricht der Heapifizierung des Eingabe-Arrays. Die an einer Swap-Operation beteiligten Elemente sind rot und mit unterbrochenen Pfeilen markiert, dicke Doppelpfeile bezeichnen die an einer Heapify-Operation beteiligten Elemente und grün markierte Elemente zeigen den schon sortierten Anteil des Arrays an. Die Element-Indizes sind mit kleinen schwarzen Knoten eingezeichnet, jeweils links unten von dem Element-Wert. Eine blaue Hinterlegung der Array-Elemente indiziert die Laufzeit der Heapsort-Prozedur.&lt;br /&gt;
&lt;br /&gt;
Die Indizes entsprechen einer aufsteigenden Nummerierung nach Level-Order, beginnend mit 0. In einer Implementierung des Algorithmus ist die Baumstruktur implizit und das Array der Elemente zusammenhängend, was durch die Platzierung der Element-Indizes in der Abbildung angedeutet wird.&lt;br /&gt;
&lt;br /&gt;
== Effizienz ==&lt;br /&gt;
&lt;br /&gt;
Man kann zeigen, dass der [[Binärer Heap#Build|Aufbau des Heaps]], in [[Landau-Notation]] ausgedrückt, in &amp;lt;math&amp;gt; \mathcal{O}(n) &amp;lt;/math&amp;gt; Schritten ablaufen kann. In einem großen, zufällig verteilten Datenfeld (100 bis 10&amp;lt;sup&amp;gt;10&amp;lt;/sup&amp;gt; Datenelemente) sind durchschnittlich mehr als 4, aber weniger als 5 signifikante Sortieroperationen pro Element nötig (2,5 Datenvergleiche und 2,5 Zuweisungen). Dies liegt daran, dass ein zufälliges Element mit exponentiell zunehmender Wahrscheinlichkeit einen geeigneten Vaterknoten findet (60 %, 85 %, 93 %, 97 %, …).&lt;br /&gt;
&lt;br /&gt;
Die [[Binärer Heap#Heapify|Heapify-Operation]] benötigt im [[Worst Case|ungünstigsten Fall]] &amp;lt;math&amp;gt; \Theta(\log n) &amp;lt;/math&amp;gt; Schritte. Dies ist bei exakt inverser Reihenfolge der Fall. In dem durchschnittlichen Fall werden etwa die Hälfte der Operationen des ungünstigsten Falls und somit ebenfalls &amp;lt;math&amp;gt; \Theta(\log n) &amp;lt;/math&amp;gt; Schritte benötigt. Günstig ist nur ein Feld, dessen Elemente fast alle den gleichen Wert haben. Sind aber nur weniger als ca. 80 % der Daten identisch, dann entspricht die Laufzeit bereits dem durchschnittlichen Fall. Eine vorteilhafte Anordnung von Daten mit mehreren verschiedenen Werten ist prinzipbedingt unmöglich, da dies der Heapcharakteristik widerspricht.&lt;br /&gt;
&lt;br /&gt;
Den [[Worst Case]] stellen mit &amp;lt;math&amp;gt; \Theta(n \cdot \log n) &amp;lt;/math&amp;gt; weitgehend vorsortierte Daten dar, weil der Heapaufbau de facto eine schrittweise vollständige Invertierung der Sortierreihenfolge darstellt. Der günstigste, aber unwahrscheinliche Fall ist ein bereits umgekehrt sortiertes Datenfeld (1 Vergleich pro Element, keine Zuweisung). Gleiches gilt, wenn fast alle Daten identisch sind.&lt;br /&gt;
&lt;br /&gt;
Auf heterogenen Daten – vorsortiert oder nicht – dominiert Heapify mit wenigstens über 60 % der Zeit, meistens über 80 %. Somit garantiert Heapsort eine [[Laufzeit (Informatik)|Gesamtlaufzeit]] von &amp;lt;math&amp;gt;\mathcal{O}(n \cdot \log n) &amp;lt;/math&amp;gt;. Auch im besten Fall wird eine Laufzeit von &amp;lt;math&amp;gt; \Theta(n \cdot \log n) &amp;lt;/math&amp;gt; benötigt.&amp;lt;ref&amp;gt;Russel Schaffer, Robert Sedgewick: &amp;#039;&amp;#039;The analysis of heapsort.&amp;#039;&amp;#039; In: &amp;#039;&amp;#039;Journal of Algorithms,&amp;#039;&amp;#039; Volume 15,  Issue 1. Juli 1993. S. 76–100, {{ISSN|0196-6774}}&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Bela Bollobas, Trevor I. Fenner, Alan M. Frieze: &amp;#039;&amp;#039;On the best case of heapsort.&amp;#039;&amp;#039; In: &amp;#039;&amp;#039;Journal of Algorithms,&amp;#039;&amp;#039; Volume 20,  Issue 2. März 1996. S. 205–217. {{ISSN|0196-6774}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Variante von Heapsort benötigt im [[Worst Case]] &amp;lt;math&amp;gt;n\cdot\log_{2}(n)+n\cdot\log_{2}(\log_{2}(n)) + n&amp;lt;/math&amp;gt; Vergleiche.&amp;lt;ref&amp;gt;Gu Xunrang, Zhu Yuzhang: [https://www.sciencedirect.com/science/article/pii/0304397595002332 Optimal heapsort algorithm]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Abgrenzung ==&lt;br /&gt;
&lt;br /&gt;
Im Durchschnitt ist Heapsort nur dann schneller als [[Quicksort]], wenn Vergleiche auf den zu sortierenden Daten sehr aufwendig sind und gleichzeitig eine für Quicksort ungünstige Datenanordnung besteht, z.&amp;amp;nbsp;B. viele gleiche Elemente. In der Praxis ist bei unsortierten oder teilweise vorsortierten Daten Quicksort oder [[Introsort]] um einen konstanten Faktor von 2 bis 5 schneller als Heapsort. Dies wird jedoch kontrovers diskutiert und es gibt Analysen, die Heapsort vorne sehen, sowohl aus Implementierungs- wie auch aus informationstheoretischen Überlegungen.&amp;lt;ref&amp;gt;{{cite web| first=Paul |last=Hsieh| title=Sorting revisited.| url=http://www.azillionmonkeys.com/qed/sort.html| date=2004| publisher = azillionmonkeys.com |language=en |accessdate=2024-10-25}}&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;{{cite web| first=David |last=MacKay| title=Heapsort, Quicksort, and Entropy |language=en | url=http://www.aims.ac.za/~mackay/sorting/sorting.html| archiveurl=https://web.archive.org/web/20070607172645/http://www.aims.ac.za/~mackay/sorting/sorting.html| archivedate=2007-06-07| date=2005-12-01 | accessdate=2010-04-26| publisher = aims.ac.za/~mackay}}&amp;lt;/ref&amp;gt; Allerdings spricht das [[Worst Case|Worst-Case]]-Verhalten von &amp;lt;math&amp;gt; \mathcal{O}(n \cdot \log n) &amp;lt;/math&amp;gt; gegenüber &amp;lt;math&amp;gt; \Theta(n^2 ) &amp;lt;/math&amp;gt; bei Quicksort für Heapsort. Introsort ist dagegen in fast allen Fällen schneller als Heapsort, lediglich in entarteten Fällen 20 % bis 30 % langsamer.&lt;br /&gt;
&lt;br /&gt;
== Bottom-Up-Heapsort ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Variante des Heapsort-Algorithmus ist [[Bottom-Up-Heapsort]], das häufig fast die Hälfte der nötigen Vergleichsoperationen einsparen kann und sich folglich besonders da rentiert, wo Vergleiche aufwendig sind.&lt;br /&gt;
&lt;br /&gt;
Bottom-Up-Heapsort ist ein [[Sortierverfahren|Sortieralgorithmus]], der u. a. [[1990]] von [[Ingo Wegener]] vorgestellt wurde und im Durchschnitt besser als [[Quicksort]] arbeitet, falls man Vergleichsoperationen hinreichend stark gewichtet. Es ist eine Variante von Heapsort, die vor allem zur Sortierung sehr großer Datenmengen geeignet ist, wenn (im Vergleich zu den notwendigen Vertauschungsoperationen) ein relativ hoher Aufwand pro Vergleichsoperation erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
Diese Variante wurde allerdings bereits [[1986]] von Svante Carlsson analysiert, der letztlich eine weitere Variante fand, die sogar eine [[Worst Case|Worst-Case]]-[[Laufzeit (Informatik)|Laufzeit]] von nur &amp;lt;math&amp;gt;n\cdot\log_{2}(n) + \mathcal{O}(n \cdot \log_{2}(\log_{2}(n)))&amp;lt;/math&amp;gt; Vergleichen hat. Entdeckt wurde dieser Bottom-Up-Heapsort bereits von [[Robert Floyd|Robert W Floyd]], der aber das Laufzeitverhalten dieser Variante nicht beweisen konnte.&lt;br /&gt;
&lt;br /&gt;
Bottom-Up-Heapsort benötigt zum Sortieren einer Folge von &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; Elementen im [[Worst Case]] &amp;lt;math&amp;gt;\tfrac{3}{2}\cdot n\cdot\log_{2}(n) + 2\cdot n&amp;lt;/math&amp;gt; Vergleiche. Im Durchschnitt sind es &amp;lt;math&amp;gt;n\cdot\log_{2}(n) + \mathcal{O}(n)&amp;lt;/math&amp;gt; Vergleiche.&lt;br /&gt;
&lt;br /&gt;
=== Prinzip der Sortierung ===&lt;br /&gt;
Beim Sortieren mit normalem Heapsort finden beim Absenken eines Elements zwei Vergleiche pro Ebene statt:&lt;br /&gt;
&lt;br /&gt;
{{Überarbeiten|Grund=Aussage ist falsch. Es sind bis zu vier Vergleiche Erforderlich. Siehe: [[Diskussion:Heapsort#Bottom-Up-Heapsort - Ein Irrtum der Informatikwelt?]]}}&lt;br /&gt;
&lt;br /&gt;
# Welcher der beiden Nachfolgeknoten des abzusenkenden Elements ist größer?&lt;br /&gt;
# Ist der nun bestimmte Nachfolgeknoten größer als das abzusenkende Element?&lt;br /&gt;
&lt;br /&gt;
Nachdem ein [[Binärbaum]] zur Hälfte aus [[Blätter und innere Knoten in der Graphentheorie|Blättern]] besteht und zudem beim Sortieren ehemalige Blätter mit ohnehin schon eher niedrigen Werten abgesenkt werden, ist es wahrscheinlich, dass ein Element bis zur Blattebene oder in deren Nähe abgesenkt werden muss. Deshalb kann es lohnend sein, auf den zweiten Vergleich zu verzichten und auf Verdacht bis zur Blattebene abzusenken.&lt;br /&gt;
&lt;br /&gt;
In einem zweiten Schritt wird dann rückwärts überprüft, wie weit das Element wieder angehoben werden muss. Im günstigsten Fall (sehr große Felder mit nur wenigen [[Dublette (Datenbank)|Dubletten]]) kann dabei fast die Hälfte der insgesamt nötigen Vergleiche bei mäßigem Zusatzaufwand eingespart werden.&lt;br /&gt;
&lt;br /&gt;
Weniger geeignet ist Bottom-Up-Heapsort zur Sortierung kleinerer Felder mit einfacher numerischer Vergleichsoperation und dann, wenn im Feld sehr viele Elemente gleichwertig sind. Dann stimmt die Annahme nicht, dass meist bis in die Nähe der Blattebene abgesenkt werden muss.&lt;br /&gt;
&lt;br /&gt;
=== Algorithmus ===&lt;br /&gt;
Konkret wird der Heapsort-Algorithmus, was das Absenken betrifft, wie folgt verändert:&lt;br /&gt;
&lt;br /&gt;
Zunächst wird der [[Weg (Graphentheorie)|Pfad]], in welchem das [[Wurzel (Graphentheorie)|Wurzelelement]] versenkt werden soll, bestimmt. Dies geschieht durch die Ermittlung des jeweils größten Kindes (Pfad maximaler Kinder). Danach wird dieser bestimmte Pfad von unten nach oben vom Blatt in Richtung Wurzel durchlaufen. Hierbei wird bei jedem besuchten Knoten verglichen, ob er größer als das abzusenkende Wurzelelement ist. Ist dem so, wird das Wurzelelement an die Position des zuletzt besuchten Knotens kopiert und vorher der restliche Pfad um eine Ebene nach oben verschoben.&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man auch die Verschiebung von vornherein auf Verdacht bis zur Blattebene durchführen und später – soweit notwendig – wieder rückgängig machen. Wo Kopien relativ günstig durchgeführt werden können (weil etwa nur ein [[Zeiger (Informatik)|Zeiger]] kopiert wird), kann das insgesamt vorteilhaft sein.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Heap&amp;#039;&amp;#039;&amp;#039;: [9, 23, 24, 20, 18, 14, 17, 13, 15, 11, 10, 5, 7, 3, 2]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Baumstruktur:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
             9&lt;br /&gt;
        /         \&lt;br /&gt;
       23         24&lt;br /&gt;
     /   \       /  \&lt;br /&gt;
    20   18     14  17&lt;br /&gt;
   / \   / \   / \  / \&lt;br /&gt;
  13 15 11 10  5  7 3  2&lt;br /&gt;
Das Element &amp;#039;&amp;#039;&amp;#039;9&amp;#039;&amp;#039;&amp;#039; muss abgesenkt werden, da es kleiner als mindestens ein Nachfolgeknoten ist. Es wird als erstes der Pfad der maximalen Kinder (ausgehend von der Wurzel) bestimmt. Es ergibt sich also &amp;#039;&amp;#039;&amp;#039;9 - 24 - 17 - 3&amp;#039;&amp;#039;&amp;#039;. Der Algorithmus durchläuft diesen Pfad nun von unten nach oben, also &amp;#039;&amp;#039;&amp;#039;3 -&amp;gt; 17 -&amp;gt; 24 -&amp;gt; 9&amp;#039;&amp;#039;&amp;#039;. Nun wird der Pfad vom Blattknoten &amp;#039;&amp;#039;&amp;#039;(3)&amp;#039;&amp;#039;&amp;#039; beginnend solange durchlaufen, bis sich ein Knoten findet, der größer als &amp;#039;&amp;#039;&amp;#039;9&amp;#039;&amp;#039;&amp;#039; ist. Der Durchlauf endet folglich bei &amp;#039;&amp;#039;&amp;#039;17&amp;#039;&amp;#039;&amp;#039;. Nun werden alle Knoten ab &amp;#039;&amp;#039;&amp;#039;17&amp;#039;&amp;#039;&amp;#039; bis zum Nachfolgeknoten der Wurzel &amp;#039;&amp;#039;&amp;#039;(= 17 -&amp;gt; 24)&amp;#039;&amp;#039;&amp;#039; um eine Ebene nach oben und der Knoten &amp;#039;&amp;#039;&amp;#039;9&amp;#039;&amp;#039;&amp;#039; an die Position von &amp;#039;&amp;#039;&amp;#039;17&amp;#039;&amp;#039;&amp;#039; verschoben. Folglich ändern &amp;#039;&amp;#039;&amp;#039;17&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;24&amp;#039;&amp;#039;&amp;#039; als Nachfolgeknoten und &amp;#039;&amp;#039;&amp;#039;9&amp;#039;&amp;#039;&amp;#039; als Wurzelknoten ihren Platz.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Heap&amp;#039;&amp;#039;&amp;#039;: [24, 23, 17, 20, 18, 14, 9, 13, 15, 11, 10, 5, 7, 3, 2]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Baumstruktur:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
            24           -------|                      24&lt;br /&gt;
        /         \             |                 /         \&lt;br /&gt;
       23         17            9                23         17&lt;br /&gt;
     /   \       /  \           |               /   \      /   \&lt;br /&gt;
    20   18     14      &amp;lt;-------|              20   18    14    9&lt;br /&gt;
   / \   / \   / \  / \                       / \   / \   / \  / \&lt;br /&gt;
  13 15 11 10  5  7 3  2                     13 15 11 10 5  7  3  2&lt;br /&gt;
&lt;br /&gt;
=== Implementierung ===&lt;br /&gt;
Einfache Beispielsimplementierung in der [[C (Programmiersprache)|Programmiersprache C]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
 int heapsort_bu( int * data, int n ) // zu sortierendes Feld und seine Länge&lt;br /&gt;
 {&lt;br /&gt;
   int val, parent, child;&lt;br /&gt;
   int root= n &amp;gt;&amp;gt; 1;                  // erstes Blatt im Baum&lt;br /&gt;
   int count= 0;                      // Zähler für Anzahl der Vergleiche&lt;br /&gt;
&lt;br /&gt;
   for ( ; ; )&lt;br /&gt;
   {&lt;br /&gt;
     if ( root ) {                    // Teil 1: Konstruktion des Heaps&lt;br /&gt;
       parent= --root;&lt;br /&gt;
       val= data[root];               // zu versickernder Wert&lt;br /&gt;
     }&lt;br /&gt;
     else&lt;br /&gt;
     if ( --n ) {                     // Teil 2: eigentliche Sortierung&lt;br /&gt;
       val= data[n];                  // zu versickernder Wert vom Heap-Ende&lt;br /&gt;
       data[n]= data[0];              // Spitze des Heaps hinter den Heap in&lt;br /&gt;
       parent= 0;                     //   den sortierten Bereich verschieben&lt;br /&gt;
     }&lt;br /&gt;
     else                             // Heap ist leer; Sortierung beendet&lt;br /&gt;
       break;&lt;br /&gt;
&lt;br /&gt;
     while ( (child= (parent + 1) &amp;lt;&amp;lt; 1) &amp;lt; n )  // zweites (!) Kind;&lt;br /&gt;
     {                                         // Abbruch am Ende des Heaps&lt;br /&gt;
       if ( ++count, data[child-1] &amp;gt; data[child] )  // größeres Kind wählen&lt;br /&gt;
         --child;&lt;br /&gt;
&lt;br /&gt;
       data[parent]= data[child];     // größeres Kind nach oben rücken&lt;br /&gt;
       parent= child;                 // in der Ebene darunter weitersuchen&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     if ( child == n )                // ein einzelnes Kind am Heap-Ende&lt;br /&gt;
     {                                //   ist übersprungen worden&lt;br /&gt;
       if ( ++count, data[--child] &amp;gt;= val ) {  // größer als der zu versick-&lt;br /&gt;
         data[parent]= data[child];   //   ernde Wert, also noch nach oben&lt;br /&gt;
         data[child]= val;            // versickerten Wert eintragen&lt;br /&gt;
         continue;&lt;br /&gt;
       }&lt;br /&gt;
&lt;br /&gt;
       child= parent;                 // 1 Ebene nach oben zurück&lt;br /&gt;
     }&lt;br /&gt;
     else&lt;br /&gt;
     {&lt;br /&gt;
       if ( ++count, data[parent] &amp;gt;= val ) {  // das Blatt ist größer als der&lt;br /&gt;
         data[parent]= val;           //   zu versickernde Wert, der damit&lt;br /&gt;
         continue;                    //   direkt eingetragen werden kann&lt;br /&gt;
       }&lt;br /&gt;
&lt;br /&gt;
       child= (parent - 1) &amp;gt;&amp;gt; 1;      // 2 Ebenen nach oben zurück&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     while ( child != root )          // maximal zum Ausgangspunkt zurück&lt;br /&gt;
     {&lt;br /&gt;
       parent= (child - 1) &amp;gt;&amp;gt; 1;      // den Vergleichswert haben wir bereits&lt;br /&gt;
                                      //   nach oben verschoben&lt;br /&gt;
       if ( ++count, data[parent] &amp;gt;= val )  // größer als der zu versickernde&lt;br /&gt;
         break;                             //   Wert, also Position gefunden&lt;br /&gt;
&lt;br /&gt;
       data[child]= data[parent];     // Rückverschiebung nötig&lt;br /&gt;
       child= parent;                 // 1 Ebene nach oben zurück&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     data[child]= val;                // versickerten Wert eintragen&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return count;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zu Vergleichszwecken gibt die Funktion die Anzahl der durchgeführten Vergleiche zurück.&lt;br /&gt;
&lt;br /&gt;
== Andere Varianten ==&lt;br /&gt;
&lt;br /&gt;
=== Smoothsort ===&lt;br /&gt;
&lt;br /&gt;
Normales Heapsort sortiert bereits weitgehend vorsortierte Felder nicht schneller als andere. Die größten Elemente müssen immer erst ganz nach vorn an die Spitze des Heaps wandern, bevor sie wieder nach hinten kopiert werden. [[Smoothsort]] ändert das, indem es im Prinzip die Reihenfolge des Heaps umdreht. Dabei ist allerdings beträchtlicher Aufwand nötig, um den Heapstatus beim Sortieren aufrechtzuerhalten. Smoothsort benötigt eine lineare [[Laufzeit (Informatik)|Laufzeit]] von &amp;lt;math&amp;gt; \mathcal{O}(n) &amp;lt;/math&amp;gt;, um ein vorsortiertes Array ([[Best Case]]) zu verarbeiten, und genauso wie andere Varianten eine Laufzeit von &amp;lt;math&amp;gt; \mathcal{O}(n \cdot \log n) &amp;lt;/math&amp;gt; im Durchschnitt und im [[Worst Case]], und erzielt bei vielen nahezu sortierten Eingaben eine nahezu lineare Leistung. Es werden jedoch nicht alle nahezu sortierten Sequenzen optimal verarbeitet.&amp;lt;ref&amp;gt;{{cite journal|last=Hertel|first=Stefan|title=Smoothsort’s behavior on presorted sequences|journal=[[Information Processing Letters]]|volume=16|issue=4|date=1983-05-13|pages=165–170|url=https://publikationen.sulb.uni-saarland.de/handle/20.500.11880/26149|format=PDF|doi=10.1016/0020-0190(83)90116-3}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ternäre Heaps ===&lt;br /&gt;
&lt;br /&gt;
Eine andere Optimierung verwendet statt binären ternäre [[Heap (Datenstruktur)|Heaps]]. Diese Heaps beruhen statt auf [[Binärbaum|Binärbäumen]] auf Bäumen, bei denen jeder vollständig besetzte Knoten 3 Kinder hat. Damit kann die Zahl der Vergleichsoperationen bei einigen Tausend bis einigen Millionen Elementen um etwa 3 % reduziert werden. Außerdem sinkt der sonstige Aufwand deutlich. Insbesondere müssen durch den flacheren Heap knapp ein Drittel weniger Elemente beim Versickern (Heapify) verschoben werden.&lt;br /&gt;
&lt;br /&gt;
In einem [[Binärer Heap|binären Heap]] kann ein Element mit &amp;lt;math&amp;gt;2 \cdot n&amp;lt;/math&amp;gt; Vergleichen um &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; Ebenen abgesenkt werden und hat dabei durchschnittlich &amp;lt;math&amp;gt;\tfrac{3}{2} \cdot (2^n - 1)&amp;lt;/math&amp;gt; Indizes übersprungen. In einem ternären [[Heap (Datenstruktur)|Heap]] kann ein Element mit &amp;lt;math&amp;gt;3 \cdot m&amp;lt;/math&amp;gt; Vergleichen um &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; Ebenen abgesenkt werden und hat dabei durchschnittlich &amp;lt;math&amp;gt;3^m - 1&amp;lt;/math&amp;gt; Indizes übersprungen. Wenn bei gleicher Reichweite der relative Aufwand &amp;lt;math&amp;gt;x := \tfrac{3 \cdot m}{2 \cdot n}&amp;lt;/math&amp;gt; ist, dann gilt&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{3}{2} \cdot (2^n - 1) = 3^{\frac{2 \cdot n \cdot x}{3}}-1&amp;lt;/math&amp;gt;, also &amp;lt;math&amp;gt;x = \frac{3}{2 \cdot n} \cdot \log_3\left(\frac{3}{2} \cdot 2^n - \frac{1}{2}\right) =_{n\to\infty} \frac{3}{2} \cdot \log_3(2) \approx 0{,}946&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei &amp;lt;math&amp;gt;n=18&amp;lt;/math&amp;gt; (realistisch bei knapp 1 Million Elementen) ergibt sich 0,977. Die 1 wird oberhalb von &amp;lt;math&amp;gt;n=10&amp;lt;/math&amp;gt; unterschritten. In der Praxis ist die Ersparnis etwas größer, u.&amp;amp;nbsp;a. deswegen, weil ternäre Bäume mehr Blätter haben und deshalb beim Aufbau des [[Heap (Datenstruktur)|Heaps]] weniger Elemente versickert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Insgesamt kann die Sortierung mit ternären Heaps bei großen Feldern (mehrere Millionen Elemente) und einfacher Vergleichsoperation 20 % bis 30 % Zeit einsparen. Bei kleinen Feldern (bis etwa tausend Elemente) lohnen sich ternäre Heaps nicht oder sind sogar langsamer.&lt;br /&gt;
&lt;br /&gt;
=== &amp;#039;&amp;#039;n&amp;#039;&amp;#039;-äre Heaps ===&lt;br /&gt;
&lt;br /&gt;
Bei noch breiteren [[Baum (Graphentheorie)|Bäumen]] bzw. flacheren [[Heap (Datenstruktur)|Heaps]] steigt die Zahl der nötigen Vergleichsoperationen wieder an. Trotzdem können sie vorteilhaft sein, weil der sonstige Aufwand vor allem der für das Kopieren von Elementen weiter sinkt und geordneter auf die Elemente zugegriffen wird, was die Effizienz von [[Cache]]s erhöhen kann. Sofern bei großen Feldern nur ein einfacher numerischer Vergleich durchzuführen ist und Schreiboperationen relativ langsam sind, können 8 oder mehr Kinder pro Knoten optimal sein.&lt;br /&gt;
&lt;br /&gt;
Einfache Beispielsimplementierung mit Heaps beliebiger [[Arität]] (WIDTH, mit WIDTH&amp;gt;=2) in der [[C (Programmiersprache)|Programmiersprache C]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static size_t heapify(int *data, size_t n, size_t WIDTH, size_t root)&lt;br /&gt;
{&lt;br /&gt;
  assert(root &amp;lt; n);&lt;br /&gt;
  size_t count = 0;&lt;br /&gt;
  int val = data[root];&lt;br /&gt;
  size_t parent = root;&lt;br /&gt;
  size_t child = 0;&lt;br /&gt;
  assert(parent * WIDTH &amp;gt;= parent); // Overflow-Test&lt;br /&gt;
  while ( (child = parent * WIDTH + 1) &amp;lt; n )  // erstes Kind;&lt;br /&gt;
  {                                           // Abbruch am Ende des Heaps&lt;br /&gt;
    size_t w = n - child &amp;lt; WIDTH ?&lt;br /&gt;
      n - child : WIDTH;            // Anzahl der vorhandenen Geschwister&lt;br /&gt;
&lt;br /&gt;
    count += w;&lt;br /&gt;
&lt;br /&gt;
    size_t max = 0;&lt;br /&gt;
    for (size_t i = 1; i &amp;lt; w; ++i )  // größtes Kind suchen&lt;br /&gt;
      if (data[child+i] &amp;gt; data[child+max])&lt;br /&gt;
        max = i;&lt;br /&gt;
    child += max;&lt;br /&gt;
&lt;br /&gt;
    if (data[child] &amp;lt;= val)        // kein Kind mehr größer als der&lt;br /&gt;
      break;                        //   zu versickernde Wert&lt;br /&gt;
&lt;br /&gt;
    data[parent] = data[child];     // größtes Kind nach oben rücken&lt;br /&gt;
    parent = child;                 // in der Ebene darunter weitermachen&lt;br /&gt;
  }&lt;br /&gt;
  data[parent] = val;               // gesiebten Wert eintragen&lt;br /&gt;
  return count;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
size_t nhsort(int * data, size_t n, size_t WIDTH)&lt;br /&gt;
{&lt;br /&gt;
  assert(WIDTH &amp;gt; 1);&lt;br /&gt;
  if (n &amp;lt; 2)&lt;br /&gt;
    return 0;&lt;br /&gt;
  size_t m = (n + WIDTH - 2) / WIDTH;  // erstes Blatt im Baum&lt;br /&gt;
  int count = 0;                       // Zähler für Anzahl der Vergleiche&lt;br /&gt;
&lt;br /&gt;
  assert(m &amp;gt; 0);&lt;br /&gt;
  for (size_t r = m; r &amp;gt; 0; --r)       // Teil 1: Konstruktion des Heaps&lt;br /&gt;
    count += heapify(data, n, WIDTH, r-1);&lt;br /&gt;
  for (size_t i = n - 1; i &amp;gt; 0; --i) { // Teil 2: eigentliche Sortierung&lt;br /&gt;
    int tmp = data[0];                 // Spitze des Heaps hinter den Heap in&lt;br /&gt;
    data[0] = data[i];&lt;br /&gt;
    data[i] = tmp;                     //   den sortierten Bereich verschieben&lt;br /&gt;
    count += heapify(data, i, WIDTH, 0);&lt;br /&gt;
  }&lt;br /&gt;
  return count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zu Vergleichszwecken gibt die Funktion die Anzahl der durchgeführten Vergleiche zurück.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
* [[Hybridsort]]&lt;br /&gt;
&lt;br /&gt;
== Literatur ==&lt;br /&gt;
&lt;br /&gt;
* {{BibISBN|0-262-03293-7|Seite=135}}&lt;br /&gt;
* {{BibISBN|0-201-89685-0|Seite=145}}&lt;br /&gt;
* {{Literatur&lt;br /&gt;
   |Autor=[[Robert Floyd|Robert W. Floyd]]&lt;br /&gt;
   |Titel=Algorithm 245: Treesort 3&lt;br /&gt;
   |Sammelwerk=Communications of the ACM&lt;br /&gt;
   |Band=7&lt;br /&gt;
   |Nummer=12&lt;br /&gt;
   |Datum=1964-12&lt;br /&gt;
   |Seiten=701}}&lt;br /&gt;
* {{Literatur&lt;br /&gt;
   |Autor=J. W. J. Williams&lt;br /&gt;
   |Titel=Algorithm 232: Heapsort&lt;br /&gt;
   |Sammelwerk=Communications of the ACM&lt;br /&gt;
   |Band=7&lt;br /&gt;
   |Nummer=6&lt;br /&gt;
   |Datum=1964-06&lt;br /&gt;
   |Seiten=347–348}}&lt;br /&gt;
* {{Literatur&lt;br /&gt;
   |Autor=[[Robert Floyd|Robert W. Floyd]]&lt;br /&gt;
   |Titel=Algorithm 113: Treesort&lt;br /&gt;
   |Sammelwerk=Communications of the ACM&lt;br /&gt;
   |Band=5&lt;br /&gt;
   |Nummer=8&lt;br /&gt;
   |Datum=1962-08&lt;br /&gt;
   |Seiten=434}}&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
{{Wikibooks|Algorithmensammlung: Sortierverfahren: Heapsort|Heapsort|suffix=Implementierungen in der Algorithmensammlung}}&lt;br /&gt;
{{Commonscat|Heap sort}}&lt;br /&gt;
* [http://vimeo.com/2942939 Video zur Visualisierung von Heap Sort] auf vimeo.com&lt;br /&gt;
* {{Internetquelle&lt;br /&gt;
   |autor=Hans Werner Lang&lt;br /&gt;
   |url=https://hwlang.de/algorithmen/sortieren/heap/heap.htm&lt;br /&gt;
   |titel=Heapsort&lt;br /&gt;
   |werk=hwlang.de&lt;br /&gt;
   |datum=2023-03-23&lt;br /&gt;
   |abruf=2024-10-25&lt;br /&gt;
   |abruf-verborgen=1}}&lt;br /&gt;
* [https://www.sortieralgorithmen.de/heapsort/index.html Heaptsort auf sortieralgorithmen.de]&lt;br /&gt;
* [https://docs.python.org/3/library/heapq.html Heapsort in Python 3 – Heap queue algorithm] auf docs.python.org&lt;br /&gt;
&lt;br /&gt;
== Einzelnachweise ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Sortieralgorithmus]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Darkking3</name></author>
	</entry>
</feed>