it-swarm.com.ru

Реализация Javascript Array.sort?

Какой алгоритм использует функция JavaScript Array#sort()? Я понимаю, что для выполнения разных видов сортировки могут потребоваться всевозможные аргументы и функции, меня просто интересует, какой алгоритм использует сортировка Vanilla.

197
latortuga

Если вы посмотрите на эту ошибку 224128 , то окажется, что MergeSort используется Mozilla.

58
Britton

Я только что посмотрел на WebKit (Chrome, Safari ...) источник . В зависимости от типа массива используются разные методы сортировки:

Числовые массивы (или массивы примитивного типа) сортируются с использованием стандартной библиотечной функции C++ std::qsort , которая реализует некоторую вариацию быстрой сортировки (обычно introsort ).

смежные массивы нечислового типа подвергаются строковому форматированию и сортируются с использованием mergesort, если доступно (для получения стабильной сортировки), или qsort, если сортировка слиянием недоступна.

Для других типов (несмежные массивы и, предположительно, для ассоциативных массивов) WebKit использует либо выборочная сортировка (которую они называют "сортировка" min ), либо, в некоторых случаях, сортирует через дерево AVL. К сожалению, документация здесь довольно расплывчата, поэтому вам придется проследить пути кода, чтобы реально определить, для каких типов используется метод сортировки.

И затем есть драгоценные камни, такие как этот комментарий :

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

- Будем просто надеяться, что тот, кто на самом деле "исправит" это, лучше понимает асимптотическую среду выполнения, чем автор этого комментария, и понимает, что у radix-сортировки немного более сложное описание среды выполнения , чем просто O (N) ,.

(Спасибо phsource за указание на ошибку в исходном ответе.)

264
Konrad Rudolph

Для JS не существует чернового требования использовать определенный алгоритм сортировки. Как уже упоминалось здесь, Mozilla использует сортировку слиянием. Однако в исходном коде Chrome v8 на сегодняшний день он использует QuickSort и InsertionSort для небольших массивов.

Источник двигателя V8

Из строк 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;
      }
    }
  };

Обновление Начиная с 2018 года V8 использует TimSort, спасибо @celwell. Источник

34
Joe Thomas

Стандарт ECMAscript не определяет, какой алгоритм сортировки должен использоваться. Действительно, разные браузеры имеют разные алгоритмы сортировки. Например, метод sort () в Mozilla/Firefox не является стабильным (в смысле Word для сортировки) при сортировке карты. Сортировка IE () стабильна.

21
Steve

После еще нескольких исследований для Mozilla/Firefox оказалось, что Array.sort () использует mergesort. Смотрите код здесь .

8
latortuga

Я думаю, что это будет зависеть от того, какую реализацию браузера вы используете.

Каждый тип браузера имеет свою собственную реализацию движка javascript, так что это зависит. Вы можете проверить репозитории исходного кода для Mozilla и Webkit/Khtml для различных реализаций.

Однако IE является закрытым исходным кодом, поэтому вам, возможно, придется спросить кого-то в Microsoft.

6
Huibert Gill

Начиная с V8 v7.0/Chrome 70, V8 использует TimSort , алгоритм сортировки Python. Chrome 70 был выпущен 13 сентября 2018 года.

Смотрите пост в блоге разработчика V8 для подробностей об этом изменении. Вы также можете прочитать исходный код или патч 1186801 .

3
Boris