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


236

Який алгоритм Array#sort()використовує функцію JavaScript ? Я розумію, що для виконання різного роду видів може знадобитися будь-яка аргументація та функції, мене просто цікавить, який алгоритм використовує сорт ванілі.


Вам слід розглянути альтернативне рішення з наведених.
Ентоні

Відповіді:


77

Якщо ви подивитеся на цю помилку 224128 , виявиться, що MergeSort використовується Mozilla.


3
Добре це також неправильно в тому, що він лише заявляє алгоритм конкретної реалізації. У специфікації немає таких тверджень, а в інших реалізаціях використовуються інші алгоритми, тому це досить оману.
Патрік Робертс

292

Я щойно подивився на джерело WebKit (Chrome, Safari…) . Залежно від типу масиву використовуються різні методи сортування:

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

Суміжні масиви нечислового типу класифікуються і сортуються за допомогою 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).

- Будемо сподіватися, що той, хто насправді «виправляє» це, краще розуміє асимптотичну тривалість виконання, ніж автор цього коментаря, і розуміє, що радіо-сортування має дещо складніший опис виконання, ніж просто O (N).

(Завдяки phsource за вказівку на помилку в оригінальній відповіді.)


46

Не існує проектної вимоги для 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. Джерело


9
Я вважаю, що V8 зараз використовує TimSort: github.com/v8/v8/blob/78f2610345fdd14ca401d920c140f8f461b631d1/…
celwell

24

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


15
Оновлення: останні Firefoxes мають стабільний Array.sort; див. це питання .
skagedal

Справа в тому, що алгоритм сортування залежить від реалізації.
sean

Для цікавих, стандарт ECMAscript можна знайти тут: tc39.github.io/ecma262/#sec-array.prototype.sort
Бенджамін

10

Після ще кількох досліджень для Mozilla / Firefox виявляється, що Array.sort () використовує mergesort. Дивіться код тут .


8

Я думаю, що це залежатиме від того, яку реалізацію браузера ви пропонуєте.

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

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


Різні перекладачі можуть робити щось по-різному в тому сенсі, що вони або баггі (тобто це не за призначенням), або вони додають або знімають функції. Метод sort () є стандартною частиною Core JavaScript і визначатиметься стандартом, який браузери хочуть дотримуватися.
Джейсон Бантінг

2
@JasonBunting якщо функція реалізована і робить те, що вона повинна робити, як визначено в специфікації, розробники браузерів можуть реалізовувати функцію так, як вони хочуть: будь то бульбашка або швидке сортування. Характеристики ECMA не визначають алгоритм сортування, який слід використовувати.
Дамір Зекич


0

Функція Array.sort () JavaScript має внутрішні механізми для вибору найкращого алгоритму сортування (QuickSort, MergeSort тощо) на основі типу даних елементів масиву.


0

спробуйте це швидко:

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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.