Welcher Sortieralgorithmus funktioniert am besten bei meist sortierten Daten?
Welcher Sortieralgorithmus funktioniert am besten bei meist sortierten Daten?
Antworten:
Basierend auf der hochwissenschaftlichen Methode, animierte Gifs anzusehen, würde ich sagen, dass Insertion- und Bubble-Sorten gute Kandidaten sind.
Nur wenige Artikel => INSERTION SORT
Artikel sind meistens schon sortiert => INSERTION SORT
Besorgt über Worst-Case-Szenarien => HEAP SORT
Interessiert an einem guten Durchschnittsergebnis => QUICKSORT
Gegenstände werden aus einem dichten Universum gezogen => EIMERSORT
Wunsch, so wenig Code wie möglich zu schreiben => INSERTION SORT
Timsort ist "ein adaptiver, stabiler, natürlicher Mergesort" mit " übernatürlicher Leistung auf vielen Arten von teilweise geordneten Arrays" (weniger als lg (N!) Vergleiche erforderlich und nur N-1)". Python ist eingebautsort()
hat diesen Algorithmus seit einiger Zeit verwendet, anscheinend mit guten Ergebnissen. Es wurde speziell entwickelt, um teilweise sortierte Teilsequenzen in der Eingabe zu erkennen und zu nutzen, die häufig in realen Datensätzen auftreten. In der realen Welt ist es häufig so, dass Vergleiche viel teurer sind als das Austauschen von Elementen in einer Liste, da man normalerweise nur Zeiger austauscht, was Timsort sehr oft zu einer hervorragenden Wahl macht. Wenn Sie jedoch wissen, dass Ihre Vergleiche immer sehr billig sind (z. B. Schreiben eines Spielzeugprogramms zum Sortieren von 32-Bit-Ganzzahlen), gibt es andere Algorithmen, die wahrscheinlich eine bessere Leistung erzielen. Der einfachste Weg, Timsort zu nutzen, ist natürlich die Verwendung von Python. Da Python jedoch Open Source ist, können Sie den Code möglicherweise auch ausleihen. Alternativ enthält die obige Beschreibung mehr als genug Details, um Ihre eigene Implementierung zu schreiben.
lg(n!)
Vergleiche auf einem fast sortierten Array, bis hinunter zu O(n)
! | @behrooz: Kein Vergleich Art kann einen durchschnittlichen Fall besser hat als O(n log n)
und lg(n!)
ist O(n log n)
. Der schlimmste Fall von Timsort ist also asymptotisch nicht schlimmer als der einer anderen Vergleichsart. Darüber hinaus ist der beste Fall besser oder gleich jeder anderen Vergleichssorte.
Einfügesortierung mit folgendem Verhalten:
k
in Slots 1..n
zunächst, ob el[k] >= el[k-1]
. Wenn ja, fahren Sie mit dem nächsten Element fort. (Überspringen Sie offensichtlich das erste Element.)1..k-1
, um die Einfügeposition zu bestimmen, und fahren Sie dann mit den Elementen darüber. (Sie können dies nur tun , wenn , k>T
wo T
einiger Schwellenwert ist, mit kleinen k
dies übertrieben ist.)Diese Methode führt die geringste Anzahl von Vergleichen durch.
Versuchen Sie es mit einer introspektiven Sortierung. http://en.wikipedia.org/wiki/Introsort
Es basiert auf Quicksort, vermeidet jedoch das Worst-Case-Verhalten von Quicksort für nahezu sortierte Listen.
Der Trick besteht darin, dass dieser Sortieralgorithmus die Fälle erkennt, in denen Quicksort in den Worst-Case-Modus wechselt und auf Heap- oder Merge-Sortierung umschaltet. Nahezu sortierte Partitionen werden von einer nicht-naiiven Partitionsmethode erkannt, und kleine Partitionen werden mithilfe der Einfügesortierung behandelt.
Sie erhalten den besten aller wichtigen Sortieralgorithmen für die Kosten für mehr Code und Komplexität. Und Sie können sicher sein, dass Sie niemals auf Worst-Case-Verhalten stoßen, egal wie Ihre Daten aussehen.
Wenn Sie ein C ++ - Programmierer sind, überprüfen Sie Ihren std :: sort-Algorithmus. Möglicherweise wird die introspektive Sortierung bereits intern verwendet.
Splaysort ist ein unbekanntes Sortierverfahren basierend auf Splay-Baum , eine Art von adaptivem Binärbaum. Splaysort eignet sich nicht nur für teilweise sortierte Daten, sondern auch für teilweise umgekehrt sortierte Daten oder für Daten, für die bereits eine Reihenfolge besteht. Es ist O (nlogn) im allgemeinen Fall und O (n) im Fall, wenn die Daten auf irgendeine Weise sortiert sind (vorwärts, rückwärts, Orgelpfeife usw.).
Der große Vorteil gegenüber der Einfügesortierung besteht darin, dass das O (n ^ 2) -Verhalten nicht wiederhergestellt wird, wenn die Daten überhaupt nicht sortiert sind. Sie müssen also nicht unbedingt sicher sein, dass die Daten teilweise sortiert sind, bevor Sie sie verwenden .
Sein Nachteil ist der zusätzliche Platzbedarf für die benötigte Spreizbaumstruktur sowie die Zeit, die zum Erstellen und Zerstören des Spreizbaums erforderlich ist. Abhängig von der Größe der Daten und der erwarteten Vorsortierung kann sich der Overhead für die Geschwindigkeitssteigerung jedoch lohnen.
Ein Artikel über Splaysort wurde in Software - Practice & Experience veröffentlicht.
Insertion oder Shell Sort!
Dijkstras Smoothsort eignet sich hervorragend für bereits sortierte Daten. Es ist eine Heapsort-Variante, die im O (n lg n) Worst-Case und O (n) Best-Case ausgeführt wird. Ich habe eine Analyse des Algorithmus geschrieben, falls Sie neugierig sind, wie er funktioniert.
Natural Mergesort ist eine weitere wirklich gute Variante - es handelt sich um eine Bottom-Up-Mergesort-Variante, bei der die Eingabe als Verkettung mehrerer verschiedener sortierter Bereiche behandelt und dann mithilfe des Zusammenführungsalgorithmus zusammengefügt wird. Sie wiederholen diesen Vorgang, bis der gesamte Eingabebereich sortiert ist. Dies läuft in O (n) Zeit, wenn die Daten bereits sortiert sind und O (n lg n) im schlimmsten Fall. Es ist sehr elegant, obwohl es in der Praxis nicht so gut ist wie einige andere adaptive Sorten wie Timsort oder Smoothsort.
Die Einfügungssortierung benötigt die Zeit O (n + die Anzahl der Inversionen).
Eine Inversion ist ein Paar, (i, j)
so dass i < j && a[i] > a[j]
. Das heißt, ein Paar, das nicht in Ordnung ist.
Ein Maß für "fast sortiert" ist die Anzahl der Inversionen - man könnte "fast sortierte Daten" als Daten mit wenigen Inversionen bezeichnen. Wenn man weiß, wie viele Inversionen linear sind (zum Beispiel haben Sie gerade O (1) -Elemente an eine sortierte Liste angehängt), dauert die Einfügesortierung O (n).
Wie alle anderen sagten, achten Sie auf naives Quicksort - das kann eine O (N ^ 2) -Leistung für sortierte oder nahezu sortierte Daten haben. Mit einem geeigneten Algorithmus für die Auswahl des Pivots (entweder zufällig oder im Median von drei - siehe Auswählen eines Pivots für Quicksort ) funktioniert Quicksort dennoch einwandfrei.
Im Allgemeinen besteht die Schwierigkeit bei der Auswahl von Algorithmen wie der Einfügesortierung darin, zu entscheiden, wann die Daten nicht in der richtigen Reihenfolge sind, sodass Quicksort wirklich schneller wäre.
Ich werde nicht so tun, als ob ich hier alle Antworten hätte, da ich denke, dass es erforderlich sein kann, die Algorithmen zu codieren und sie anhand repräsentativer Datenproben zu profilieren, um zu den tatsächlichen Antworten zu gelangen. Aber ich habe den ganzen Abend über diese Frage nachgedacht, und hier ist, was mir bisher eingefallen ist, und einige Vermutungen darüber, was wo am besten funktioniert.
Sei N die Anzahl der Artikel insgesamt, M die Anzahl der nicht in Ordnung befindlichen Artikel.
Die Blasensortierung muss so etwas wie 2 * M + 1 durch alle N Gegenstände führen. Wenn M sehr klein ist (0, 1, 2?), Wird dies meiner Meinung nach sehr schwer zu schlagen sein.
Wenn M klein ist (sagen wir weniger als log N), hat die Einfügesortierung eine große durchschnittliche Leistung. Wenn ich jedoch keinen Trick sehe, den ich nicht sehe, wird die Leistung im schlimmsten Fall sehr schlecht sein. (Richtig? Wenn der letzte Artikel in der Reihenfolge an erster Stelle steht, müssen Sie, soweit ich sehen kann, jeden einzelnen Artikel einfügen, was die Leistung beeinträchtigt.) Ich vermute, dass es dafür einen zuverlässigeren Sortieralgorithmus gibt Fall, aber ich weiß nicht, was es ist.
Wenn M größer ist (sagen wir gleich oder groß als log N), ist die introspektive Sortierung mit ziemlicher Sicherheit am besten.
Ausnahme: Wenn Sie im Voraus wissen, welche Elemente unsortiert sind, sollten Sie diese Elemente am besten herausziehen, nach introspektiver Sortierung sortieren und die beiden sortierten Listen zu einer sortierten Liste zusammenführen. Wenn Sie schnell herausfinden könnten, welche Artikel nicht in Ordnung sind, wäre dies auch eine gute allgemeine Lösung - aber ich konnte keinen einfachen Weg finden, dies zu tun.
Weitere Gedanken (über Nacht): Wenn M + 1 <N / M ist, können Sie die Liste nach einem Lauf von N / M in einer Reihe durchsuchen, die sortiert sind, und diesen Lauf dann in beide Richtungen erweitern, um das Out-of zu finden -Auftragspositionen. Das dauert höchstens 2N Vergleiche. Sie können dann die unsortierten Elemente sortieren und die beiden Listen sortiert zusammenführen. Die Gesamtvergleiche sollten weniger als 4N + M log2 (M) betragen, was meiner Meinung nach jede nicht spezialisierte Sortierroutine übertreffen wird. (Noch weiter gedacht: Das ist schwieriger als ich dachte, aber ich denke immer noch, dass es vernünftigerweise möglich ist.)
Eine andere Interpretation der Frage ist, dass es möglicherweise viele nicht in Ordnung befindliche Elemente gibt, diese sich jedoch sehr nahe an der Stelle befinden, an der sie in der Liste enthalten sein sollten. (Stellen Sie sich vor, Sie beginnen mit einer sortierten Liste und tauschen jedes andere Element gegen das nachfolgende aus.) In diesem Fall funktioniert die Blasensortierung meiner Meinung nach sehr gut. Ich denke, die Anzahl der Durchgänge ist proportional zu der am weitesten entfernten Position eines Elements ist. Die Sortierung nach Einfügungen funktioniert schlecht, da jeder Artikel außerhalb der Reihenfolge eine Einfügung auslöst. Ich vermute, dass eine introspektive Art oder ähnliches auch gut funktionieren wird.
Wenn Sie eine spezielle Implementierung zum Sortieren von Algorithmen, Datenstrukturen oder anderen Elementen benötigen, die mit den oben genannten verknüpft sind, kann ich Ihnen das hervorragende Projekt "Datenstrukturen und Algorithmen" auf CodePlex empfehlen ?
Es wird alles haben, was Sie brauchen, ohne das Rad neu zu erfinden.
Nur mein kleines Salzkorn.
Dieser schönen Sammlung von Sortieralgorithmen für diesen Zweck in den Antworten scheint Gnome Sort zu fehlen , was ebenfalls geeignet wäre und wahrscheinlich den geringsten Implementierungsaufwand erfordert.
Nachdenken Heap. Ich glaube, es ist die beständigste der O (n lg n) -Sorten.
Die Blasensortierung (oder, noch sicherer, die bidirektionale Blasensortierung) ist wahrscheinlich ideal für meist sortierte Listen, obwohl ich wette, dass eine optimierte Kammsortierung (mit einer viel geringeren anfänglichen Lückengröße) etwas schneller wäre, wenn die Liste nicht vorhanden wäre. t ganz so perfekt sortiert. Die Kammsortierung wird zur Blasensortierung.
Nun, es hängt vom Anwendungsfall ab. Wenn Sie wissen, welche Elemente geändert werden, ist das Entfernen und Einfügen für mich der beste Fall.
Die Blasensortierung ist definitiv der Gewinner. Die nächste auf dem Radar wäre die Einfügungssortierung.
Halten Sie sich von QuickSort fern - es ist sehr ineffizient für vorsortierte Daten. Die Einfügesortierung verarbeitet nahezu sortierte Daten gut, indem so wenige Werte wie möglich verschoben werden.