web-dev-qa-db-fra.com

Implémentation Javascript Array.sort?

Quel algorithme la fonction JavaScript Array#sort() utilise-t-elle? Je comprends que cela peut prendre toutes sortes d'arguments et de fonctions pour effectuer différents types de tri. Je m'intéresse simplement à l'algorithme utilisé par le type Vanilla.

205
latortuga

Si vous regardez ce bogue 224128 , il semble que MergeSort est utilisé par Mozilla.

62
Britton

Je viens juste de jeter un coup d'œil au WebKit (Chrome, Safari…) source . Selon le type de tableau, différentes méthodes de tri sont utilisées:

Tableaux numériques (ou des tableaux de type primitif) sont triés à l'aide de la fonction de bibliothèque standard C++ std::qsort qui implémente certaines variations de quicksort (généralement introsort ).

Les tableaux contigus de type non numérique sont stringifiés et triés en utilisant mergesort, si disponible (pour obtenir un tri stable) ou qsort si aucun tri par fusion n'est disponible.

Pour les autres types (tableaux non contigus et vraisemblablement pour les tableaux associatifs), WebKit utilise soit tri de sélection (qu'ils appellent tri "min" ) ou, dans certains cas, il trie via un arbre AVL. Malheureusement, la documentation ici est plutôt vague, vous devez donc tracer les chemins de code pour voir réellement quels types de méthodes de tri sont utilisés.

Et puis il y a des gemmes comme ce commentaire :

// 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).

- Espérons simplement que quiconque "corrige" cela a une meilleure compréhension de l'exécution asymptotique que l'auteur de ce commentaire et se rend compte que le type de radix a une description d'exécution légèrement plus complexe que simplement O (N) .

(Merci à phsource pour avoir signalé l'erreur dans la réponse d'origine.)

270
Konrad Rudolph

Il n’existe pas de projet d’exigence pour JS d’utiliser un algorithme de tri spécifique. Comme beaucoup l'ont mentionné ici, Mozilla utilise le tri par fusion. Cependant, dans le code source de la version 8 de Chrome, il utilise QuickSort et InsertionSort, pour les tableaux plus petits.

source de moteur V8

Lignes 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;
      }
    }
  };

Mise à jour À partir de 2018, le V8 utilise TimSort, merci @celwell. Source

34
Joe Thomas

La norme ECMAscript ne spécifie pas quel algorithme de tri doit être utilisé. En effet, différents navigateurs proposent différents algorithmes de tri. Par exemple, la méthode sort () de Mozilla/Firefox n’est pas stable (au sens de tri du mot) lors du tri d’une carte. La sorte () d'IE est stable.

23
Steve

Après quelques recherches supplémentaires, il apparaît, pour Mozilla/Firefox, que Array.sort () utilise mergesort. Voir le code ici .

9
latortuga

Je pense que cela dépend de l’implémentation du navigateur auquel vous faites référence.

Chaque type de navigateur a sa propre implémentation de moteur javascript, donc ça dépend. Vous pouvez vérifier les dépôts de code source pour Mozilla et Webkit/Khtml pour différentes implémentations.

Internet Explorer étant une source fermée, vous devrez peut-être contacter quelqu'un de Microsoft.

8
Huibert Gill

V7.0/Chrome 70, la V8 utilise TimSort , l'algorithme de tri de Python. Chrome 70 a été publié le 13 septembre , 2018.

Voir le le post sur le blog de développement V8 pour plus de détails sur ce changement. Vous pouvez également lire le code source ou patch 1186801 .

3
Boris

La fonction Array.sort () de JavaScript dispose de mécanismes internes pour sélectionner le meilleur algorithme de tri (QuickSort, MergeSort, etc.) en fonction du type de données des éléments du tableau.

0
Abhijit Srivastava