Javascript Array.sort Implementierung?


236

Welchen Algorithmus verwendet die JavaScript- Array#sort()Funktion? Ich verstehe, dass es allerlei Argumente und Funktionen erfordern kann, um verschiedene Arten von Sortierungen durchzuführen. Ich bin einfach daran interessiert, welchen Algorithmus die Vanille-Sortierung verwendet.


Sie sollten eine alternative Lösung von den angegebenen in Betracht ziehen.
Anthony

Antworten:


77

Wenn Sie sich diesen Fehler 224128 ansehen , scheint MergeSort von Mozilla verwendet zu werden.


3
Nun, es ist auch insofern falsch, als es nur einen Algorithmus für eine bestimmte Implementierung angibt. Die Spezifikation erhebt keine derartigen Ansprüche, und andere Implementierungen verwenden andere Algorithmen, so dass dies ziemlich irreführend ist.
Patrick Roberts

292

Ich habe mir gerade die WebKit- Quelle (Chrome, Safari…) angesehen . Abhängig von der Art des Arrays werden verschiedene Sortiermethoden verwendet:

Numerische Arrays (oder Arrays vom primitiven Typ) werden mithilfe der C ++ - Standardbibliotheksfunktion sortiert, die std::qsorteinige Variationen von Quicksort (normalerweise Introsort ) implementiert .

Zusammenhängende Arrays vom nicht numerischen Typ werden mithilfe von Mergesort stringiert und sortiert, sofern verfügbar (um eine stabile Sortierung zu erhalten) oder qsortwenn keine Zusammenführungssortierung verfügbar ist.

Für andere Typen (nicht zusammenhängende Arrays und vermutlich für assoziative Arrays) verwendet WebKit entweder eine Auswahlsortierung (die sie als "min" -Sortierung bezeichnen ) oder in einigen Fällen eine Sortierung über einen AVL-Baum. Leider ist die Dokumentation hier ziemlich vage, sodass Sie die Codepfade nachverfolgen müssen, um tatsächlich zu sehen, für welche Typen welche Sortiermethode verwendet wird.

Und dann gibt es Edelsteine ​​wie diesen Kommentar :

// FIXME: Since we sort by string value, a fast algorithm might be to use a
// radix sort. That would be O(N) rather than O(N log N).

- Hoffen wir nur, dass jeder, der dies tatsächlich „behebt“, die asymptotische Laufzeit besser versteht als der Verfasser dieses Kommentars und erkennt, dass die Radix-Sortierung eine etwas komplexere Laufzeitbeschreibung hat als einfach O (N).

(Vielen Dank an phsource für den Hinweis auf den Fehler in der ursprünglichen Antwort.)


46

Es gibt keine Entwurfsanforderung für JS, ein bestimmtes Sortieralgorthim zu verwenden. Wie viele hier erwähnt haben, verwendet Mozilla die Zusammenführungssortierung. Im Chrome v8-Quellcode werden jedoch ab heute QuickSort und InsertionSort für kleinere Arrays verwendet.

V8 Motorquelle

Von den Linien 807 - 891

  var QuickSort = function QuickSort(a, from, to) {
    var third_index = 0;
    while (true) {
      // Insertion sort is faster for short arrays.
      if (to - from <= 10) {
        InsertionSort(a, from, to);
        return;
      }
      if (to - from > 1000) {
        third_index = GetThirdIndex(a, from, to);
      } else {
        third_index = from + ((to - from) >> 1);
      }
      // Find a pivot as the median of first, last and middle element.
      var v0 = a[from];
      var v1 = a[to - 1];
      var v2 = a[third_index];
      var c01 = comparefn(v0, v1);
      if (c01 > 0) {
        // v1 < v0, so swap them.
        var tmp = v0;
        v0 = v1;
        v1 = tmp;
      } // v0 <= v1.
      var c02 = comparefn(v0, v2);
      if (c02 >= 0) {
        // v2 <= v0 <= v1.
        var tmp = v0;
        v0 = v2;
        v2 = v1;
        v1 = tmp;
      } else {
        // v0 <= v1 && v0 < v2
        var c12 = comparefn(v1, v2);
        if (c12 > 0) {
          // v0 <= v2 < v1
          var tmp = v1;
          v1 = v2;
          v2 = tmp;
        }
      }
      // v0 <= v1 <= v2
      a[from] = v0;
      a[to - 1] = v2;
      var pivot = v1;
      var low_end = from + 1;   // Upper bound of elements lower than pivot.
      var high_start = to - 1;  // Lower bound of elements greater than pivot.
      a[third_index] = a[low_end];
      a[low_end] = pivot;

      // From low_end to i are elements equal to pivot.
      // From i to high_start are elements that haven't been compared yet.
      partition: for (var i = low_end + 1; i < high_start; i++) {
        var element = a[i];
        var order = comparefn(element, pivot);
        if (order < 0) {
          a[i] = a[low_end];
          a[low_end] = element;
          low_end++;
        } else if (order > 0) {
          do {
            high_start--;
            if (high_start == i) break partition;
            var top_elem = a[high_start];
            order = comparefn(top_elem, pivot);
          } while (order > 0);
          a[i] = a[high_start];
          a[high_start] = element;
          if (order < 0) {
            element = a[i];
            a[i] = a[low_end];
            a[low_end] = element;
            low_end++;
          }
        }
      }
      if (to - high_start < low_end - from) {
        QuickSort(a, high_start, to);
        to = low_end;
      } else {
        QuickSort(a, from, low_end);
        from = high_start;
      }
    }
  };

Update Ab 2018 verwendet V8 TimSort, danke @celwell. Quelle



24

Der ECMAscript-Standard legt nicht fest, welcher Sortieralgorithmus verwendet werden soll. In der Tat bieten verschiedene Browser unterschiedliche Sortieralgorithmen. Zum Beispiel ist Mozilla / Firefoxs sort ( ) beim Sortieren einer Karte nicht stabil (im Sinne des Wortes). IE sort () ist stabil.


15
Update: Aktuelle Firefoxes haben einen Stall Array.sort; siehe diese Frage .
Skagedal

Der Punkt ist, dass der Sortieralgorithmus implementierungsabhängig ist.
Sean

Für Neugierige ist der ECMAscript-Standard hier zu finden: tc39.github.io/ecma262/#sec-array.prototype.sort
Benjamin

10

Nach einigen weiteren Untersuchungen scheint es, dass Array.sort () für Mozilla / Firefox Mergesort verwendet. Siehe den Code hier .


8

Ich denke, das hängt davon ab, auf welche Browser-Implementierung Sie sich beziehen.

Jeder Browsertyp hat eine eigene Implementierung der Javascript-Engine, es kommt also darauf an. Sie können die Quellcode-Repos für Mozilla und Webkit / Khtml auf verschiedene Implementierungen überprüfen.

IE ist jedoch eine geschlossene Quelle, sodass Sie möglicherweise jemanden bei Microsoft fragen müssen.


Verschiedene Dolmetscher können die Dinge in dem Sinne unterschiedlich machen, dass sie entweder fehlerhaft sind (dh nicht absichtlich sind) oder Funktionen hinzufügen oder entfernen. Die sort () -Methode ist ein Standardbestandteil von Core JavaScript und wird durch den Standard definiert, dem die Browser folgen möchten.
Jason Bunting

2
@JasonBunting Wenn die Funktion implementiert ist und das tut, was sie gemäß der Spezifikation tun soll, können Browserentwickler die Funktion nach Belieben implementieren : sei es Blase oder schnelle Sortierung. ECMA-Spezifikationen definieren keinen zu verwendenden Sortieralgorithmus.
Damir Zekić


0

Die Array.sort () -Funktion von JavaScript verfügt über interne Mechanismen zur Auswahl des besten Sortieralgorithmus (QuickSort, MergeSort usw.) auf der Grundlage des Datentyps der Array-Elemente.


0

versuchen Sie dies mit schneller Sortierung:

function sort(arr, compareFn = (a, b) => a <= b) {

    if (!arr instanceof Array || arr.length === 0) {
        return arr;
    }

    if (typeof compareFn !== 'function') {
        throw new Error('compareFn is not a function!');
    }

    const partition = (arr, low, high) => {
        const pivot = arr[low];
        while (low < high) {
            while (low < high && compareFn(pivot, arr[high])) {
                --high;
            }
            arr[low] = arr[high];
            while (low < high && compareFn(arr[low], pivot)) {
                ++low;
            }
            arr[high] = arr[low];
        }
        arr[low] = pivot;
        return low;
    };

    const quickSort = (arr, low, high) => {
        if (low < high) {
            let pivot = partition(arr, low, high);
            quickSort(arr, low, pivot - 1);
            quickSort(arr, pivot + 1, high);
        }
        return arr;
    };

    return quickSort(arr, 0, arr.length - 1);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.