Einführung
Die Komplexität von Mergesort für Inputs, die in umgekehrter Sortierung sortiert wurden, ist o (n^2), und Timsort wird durch Optimierung von Mergesort für diese Situation erzeugt. Die durchschnittliche Komplexität ist n*o (log n), der beste Fall ist o (n) und der schlimmste Fall ist N*o (log n). Und Timsort ist eine Stabilitätsart. Die Idee ist, zuerst die sortierte Spalte zu partitionieren und dann die Partitionen zusammenzuführen, die dem Mergesort-Schritt genauso aussehen. Es gibt jedoch einige Optimierungen für umgekehrte und große Daten.
Optimierungsidee der Zusammenführung der Sortierung
Es gibt mehrere Optimierungsmethoden für die Zusammenführungssortierung:
Wie beim schnellen Sortieren können Sie Sortieren verwenden oder Sortieren für kleine Arrays auswählen, um rekursive Anrufe zu vermeiden.
Bevor Merge () aufgerufen wird, können Sie feststellen, ob ein [Mid] kleiner oder gleich einem [Mid+1] ist. Wenn ja, dann ist es nicht nötig zu verschmelzen, das Array ist bereits bestellt. Der Grund ist sehr einfach. Da die beiden Subtarrays bereits geordnet sind, ist ein [Mid] der Maximalwert des ersten Subtarrays, und ein [Mid+1] ist der Mindestwert des zweiten Subarrays. Wenn ein [Mid] <= a [Mid+1], wird das Array als Ganzes bestellt.
Um Zeiten zum Kopieren von Elementen in das Hilfsarray zu sparen, können die Rollen des ursprünglichen Arrays und des Auxiliary -Arrays auf jeder Ebene des rekursiven Anrufs ausgetauscht werden.
Der Merge -Prozess in der merge () -Methode muss bestimmen, ob ich und j die Grenze überschritten haben, dh eine Hälfte der Kante wurde aufgebraucht. Eine andere Möglichkeit, den Code zu entfernen, der erkennt, ob eine Hälfte der Seite erschöpft war. Der spezifische Schritt besteht darin, die zweite Hälfte des Arrays A [] in absteigender Reihenfolge nach Aux [] zu kopieren und dann von beiden Enden zusammenzuführen. Für Arrays {1,2,3} und {2,3,5} wird das erste Subtarray wie gewohnt kopiert, und das zweite wird von hinten nach vorne kopiert und das endgültige Element in aux [] ist {1,2,3,5,3,2}. Der Nachteil dieser Methode besteht darin, dass die Zusammenführung der Zusammenführung zu einer instabilen Sortierung wird. Die Code -Implementierung ist wie folgt:
void merge (int [] a, int lo, int mid, int hi, int [] aux) {für (int k = lo; k <= mid; k ++) {aux [k] = a [k];} für (int k = mid+1; k <= hi; k ++) {ux [k] = a [hi - k+mid];} int i // von den beiden Enden zur Mitte für (int k = lo; k <= hi; k ++) if (aux [i] <= aux [j]) a [k] = aux [i ++]; sonst a [k] = aux [j--];}Timsorts Schritte
Trennwand
Die Idee der Partitionierung besteht darin, das Array einmal zu scannen und die kontinuierliche positive Sequenz (falls es sortiert ist, aufsteigender Reihenfolge, dann ist die positive Sequenz eine aufsteigende Sequenz) oder [streng] (um die Stabilität des Sortieralgorithmus sicherzustellen) als Partition (Lauf). Wenn es sich um eine umgekehrte Sequenz handelt, wechseln Sie die Elemente in der Partition um. Zum Beispiel
1, 2, 3, 6, 4, 5, 8, 6, 4 Die Partitionierungsergebnisse sind
[1,2,3,6], [4,5,8] [6,4]
Dann umkehren Sie die umgekehrte Sequenz um
[1,2,3,6], [4,5,8] [4,6]
verschmelzen
Betrachten Sie beispielsweise ein extremes Beispiel: Die Längen der Partitionen betragen 10000, 10, 1000, 10, 10 und 10. Natürlich hoffen wir, 10 10 in 20, 20 und 1000 zuerst in 1020 zu verschmelzen. Wenn wir uns von links nach rechts verschmelzen, werden wir jedes Mal das Array 10000 und die Kombination kleiner Zahlen verwenden, was zu teuer ist. So können wir eine Strategie verwenden, um die Reihenfolge der Zusammenführungen zu optimieren.
Beispiel
Mit einem Run -Stapel wird ein Laufstapel verwendet, um festzustellen, ob er zusammengeführt werden sollte.
if (nremaining <min_merge) {int initrunlen = lockunandMakeAscending (a, lo, hi); BinarySort (a, lo, hi, lo + initrunlen); zurückkehren; }Sortieren Sie weniger als min_merge (32) und sortieren Sie nach der Partitionierung direkt mit binärer Einfügung
int minrun = minrunLength (Nremination); Finden Sie die Ausgangsposition der nächsten Partition heraus und drehen Sie auch die umgekehrte Sequenz int runlen = lockUnandMakeAscending (a, lo, hi); // Stellen Sie sicher, dass die Läufe im Laufstapel größer sind als Minrun. Wenn die aktuelle Partition zu klein ist, nehmen Sie die Elemente von hinten heraus, um zu erstellen, wenn (Runlen <minrun) {int force = nremaining <= minrun? NREMINING: Minrun; BinarySort (a, lo, lo + Kraft, lo + runlen); Runlen = Kraft; } // Rennen in den Lauf Stack ts.pushrun (lo, runlen); // Beurteile, ob es zusammengeführt werden soll. Ich startet von der Spitze des Stapels und weiß, dass es nicht zusammengeführt werden kann // 1. Runlen [i - 3]> Runlen [i - 2] + Runlen [i - 1] // 2. Runlen [i - 2]> Runlen [i - 1] ts.mergecollapse (); lo += runlen; Nremination -= Runlen; } while (nremaining! = 0); // alle verbleibenden Läufe zusammenführen, um Sortiersorte zu vervollständigen. // Die verbleibenden Lauf ts.mergeforceCollapse () zusammenführen; Assert ts.Stacksize == 1;Betrachten Sie eine wichtigere Funktion
/ *** Wenn die Längen der letzten 2 Läufe länger als der vorherige hinzugefügt werden, verwenden Sie den Lauf in der mittleren Position und der Lauf mit einer kürzeren Vorder- und Rücklängen, um zu verschmelzen. Wenn die Längen der letzten 2 Läufe kürzer als die vorherigen sind, verschmelzen Sie die beiden Läufe*/ private void mergeCollapse () {while, {whilepssize (staplsize> 1) {int n = staplsize {2; if (n> 0 && runlen [n-1] <= runlen [n] + runlen [n + 1]) {if (Runlen [n-1] <Runlen [n + 1]) n-; Mergeat (n); } else if (runlen [n] <= runlen [n + 1]) {mergeat (n); } else {break; // Invariante ist festgelegt}}