Ответ 1
Так почему же родной сорт медленнее? Глядя на код в
https://github.com/v8/v8/blob/0c76b0ae850027006d5ec0d92449e449d996d3bb/src/js/array.js#L744
Проблема, кажется, GetThirdIndex(). Он вызывается, когда размер раздела составляет > 1000, и я предполагаю, что он используется для предотвращения производительности худшего случая quicksort, но накладные расходы значительны, поскольку он создает внутренние массивы пар и сортирует их, а сортировка этих пар может привести к дальнейшему рекурсивному вызывает GetThirdIndex(). Это сочетается с рекурсивными вызовами, связанными с разбиением исходного массива и разбиением внутренних массивов пар.
Так как тестовые данные для этих примеров являются случайными данными, для быстрой сортировки Relu не требуется что-то вроде GetThirdIndex(). Там также проверяется "дыры" в массиве, но я предполагаю, что это не имеет значения.
Альтернативой GetThirdIndex() будет медиана медианы:
http://en.wikipedia.org/wiki/Median_of_medians
Сортировка слияний быстрее, чем quicksort с этими методами, используемыми для предотвращения сценариев наихудшего случая, но для этого необходим вспомогательный массив того же размера или половины размера исходного массива.
Introsort, который является гибридом быстросортирующего и heapsort, переключается на heapsort, если уровень рекурсии становится слишком глубоким, будет альтернативой:
http://en.wikipedia.org/wiki/Introsort
Второй пример сортировки слияния использует функцию сравнения, чтобы провести справедливое сравнение. Это значительно быстрее, чем родная версия. В случае Chrome функция сравнения не сильно повлияла на общее время. В случае с Firefox функция сравнения имела больший эффект. В случае с Firefox родная версия не удалась из-за нехватки памяти, поэтому я не смог ее сравнить.
Это несколько более быстрые версии сортировки слияния сверху вниз, которые исходный плакат был "любопытен", используя взаимно рекурсивные функции, чтобы избежать копирования и несколько оптимизированного слияния() (два условных выражения для сравнения).
Результаты с Firefox (времена несколько меняются)
native sort - failed for out of memory.
Relu merge sort - 1.8 seconds
Relu quick sort - 1.3 seconds
optimized merge sort - 1.4 seconds
optimized merge sort with compare - 1.8 seconds
Результаты с Chrome (времена несколько меняются)
native sort - 5.3 seconds
Relu merge sort - 2.1 seconds
Relu quick sort - 1.8 seconds
optimized merge sort - 1.6 seconds
optimized merge sort with compare - 1.7 seconds
Объединить сортировку
var length = 10000000; // ten millions;
var arr = [];
for (let i = length; i > 0; i--) {
// random array
arr.push(parseInt(Math.random() * 1000000000));
}
var mergeSort = function(array) {
function merge(arr, aux, lo, mid, hi) {
var i = lo;
var j = mid + 1;
var k = lo;
while(true){
if(arr[i] <= arr[j]){
aux[k++] = arr[i++];
if(i > mid){
do
aux[k++] = arr[j++];
while(j <= hi);
break;
}
} else {
aux[k++] = arr[j++];
if(j > hi){
do
aux[k++] = arr[i++];
while(i <= mid);
break;
}
}
}
}
function sortarrtoaux(arr, aux, lo, hi) {
if (hi < lo) return;
if (hi == lo){
aux[lo] = arr[lo];
return;
}
var mid = Math.floor(lo + (hi - lo) / 2);
sortarrtoarr(arr, aux, lo, mid);
sortarrtoarr(arr, aux, mid + 1, hi);
merge(arr, aux, lo, mid, hi);
}
function sortarrtoarr(arr, aux, lo, hi) {
if (hi <= lo) return;
var mid = Math.floor(lo + (hi - lo) / 2);
sortarrtoaux(arr, aux, lo, mid);
sortarrtoaux(arr, aux, mid + 1, hi);
merge(aux, arr, lo, mid, hi);
}
function merge_sort(arr) {
var aux = arr.slice(0);
sortarrtoarr(arr, aux, 0, arr.length - 1);
return arr;
}
return merge_sort(array);
}
console.time('measure');
mergeSort(arr);
console.timeEnd('measure');
console.log(arr[0], arr[1]);