微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

本机JavaScript排序执行速度低于实现的mergeesort和quicksort

我已经实现了一个mergeesort和一个quicksort来比较它们与native JavaScript的排序.对于快速排序,我试图使用这种算法: view algorithm on youtube.两种算法都使用尽可能少的内存,对于合并排序,每个递归调用传递一个辅助数组(以避免开销),而对于quicksort,开始和结束职位.我正在使用排序在NodeJs应用程序中管理大量数据.

下面您可以使用mergesort,quicksort和native JavaScript排序,您可以测试性能

问题是:为什么本机JavaScript执行速度较慢?

在我的情况下

Chrome – merge sort:measure:1997.920ms; quicksort:measure:1755.740ms; native:measure:4988.105ms
节点:merge sort:measure:2233.413ms; quicksort:measure:1876.055ms; native:measure:6317.118ms

合并排序

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) {
    for (var k = lo; k <= hi; k++) {
      aux[k] = arr[k];
    }

    var i = lo;
    var j = mid + 1;
    for (var k = lo; k <= hi; k++) {
      if (i > mid) {
        arr[k] = aux[j++];
      } else if (j > hi) {
        arr[k] = aux[i++];
      } else if (aux[i] < aux[j]) {
        arr[k] = aux[i++];
      } else {
        arr[k] = aux[j++];
      }
    }
  }

  function sort(array,hi) {
    if (hi <= lo) return;
    var mid = Math.floor(lo + (hi - lo) / 2);
    sort(array,mid);
    sort(array,mid + 1,hi);

    merge(array,hi);
  }

  function merge_sort(array) {
    var aux = array.slice(0);
    sort(array,array.length - 1);
    return array;
  }

  return merge_sort(array);
}


console.time('measure');
mergeSort(arr);
console.timeEnd('measure');
console.log(arr[0],arr[1]);

快速排序

var length = 10000000; //  ten millions;
var arr = [];
for (let i = length; i > 0; i--) {
  // random array
  arr.push(parseInt(Math.random() * 1000000000));
}

function quickSort(arr,leftPos,rightPos,arrLength) {
  let initialLeftPos = leftPos;
  let initialRightPos = rightPos;
  let direction = true;
  let pivot = rightPos;
  while ((leftPos - rightPos) < 0) {
    if (direction) {
      if (arr[pivot] < arr[leftPos]) {
        quickSort.swap(arr,pivot,leftPos);
        pivot = leftPos;
        rightPos--;
        direction = !direction;
      } else
        leftPos++;
    } else {
      if (arr[pivot] <= arr[rightPos]) {
        rightPos--;
      } else {
        quickSort.swap(arr,rightPos);
        leftPos++;
        pivot = rightPos;
        direction = !direction;
      }
    }
  }
  if (pivot - 1 > initialLeftPos) {
    quickSort(arr,initialLeftPos,pivot - 1,arrLength);
  }
  if (pivot + 1 < initialRightPos) {
    quickSort(arr,pivot + 1,initialRightPos,arrLength);
  }
}
quickSort.swap = (arr,el1,el2) => {
  let swapedElem = arr[el1];
  arr[el1] = arr[el2];
  arr[el2] = swapedElem;
}
arrLength = arr.length;
console.time('measure');
quickSort(arr,arrLength - 1,arrLength);
console.log(arr[0],arr[1]);
console.timeEnd('measure');

本机Javascript排序

var length = 10000000; //  ten millions;
var arr = [];
for (let i = length; i > 0; i--) {
  // random array
  arr.push(parseInt(Math.random() * 100000000));
}

console.time('measure');
arr.sort(function compareNumbers(a,b) {
  return a - b;
});
console.timeEnd('measure');

console.log(arr[0],arr[1]);

解决方法

那么为什么本机排序较慢?看看代码

https://github.com/v8/v8/blob/0c76b0ae850027006d5ec0d92449e449d996d3bb/src/js/array.js#L744

这个问题似乎是GetThirdindex().当分区大小为>时调用1000,我假定它用于防止快速排除最坏情况的性能,但是开销是重要的,因为它创建了内部的对数组并对其进行排序,并且这些对的排序可能导致对GetThirdindex()的进一步的递归调用.这与与分割原始阵列相关的递归调用和对内部数组对进行分区相结合.

由于这些示例的测试数据是随机数据,所以Relu的quicksort不需要像GetThirdindex()这样的东西.还有对阵列中的“孔”的检查,但是我认为这并不重要.

GetThirdindex()的替代方案将是中位数的中位数:

http://en.wikipedia.org/wiki/Median_of_medians

合并排序比quicksort快,这些方法用于防止最坏的情况,但它需要与原始数组相同大小或一半大小的辅助数组.

Introsort是快速排序和堆叠的混合,如果递归级别太深,可以转换为堆积,这将是另一种选择:

http://en.wikipedia.org/wiki/Introsort

下面的第二个合并排序示例使用比较函数进行比较.它比本机版本快得多.在Chrome的情况下,比较功能并没有影响整体的时间.在Firefox的情况下,比较功能更有效果.在Firefox的情况下,本机版本的内存不足,所以我无法比较.

这些是自上而下合并排序的一些更快的版本,原始海报“好奇”,使用相互递归函数来避免复制和稍微优化的merge()(每个比较两个条件).

Firefox的结果(时间有所不同)

native sort - Failed for out of memory.
Relu's merge sort - 1.8 seconds
Relu's 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's merge sort - 2.1 seconds
Relu's 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,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,hi) {
    if (hi < lo) return;
    if (hi == lo){
        aux[lo] = arr[lo];
        return;
    }
    var mid = Math.floor(lo + (hi - lo) / 2);
    sortarrtoarr(arr,mid);
    sortarrtoarr(arr,hi);
    merge(arr,hi);
  }

  function sortarrtoarr(arr,hi) {
    if (hi <= lo) return;
    var mid = Math.floor(lo + (hi - lo) / 2);
    sortarrtoaux(arr,mid);
    sortarrtoaux(arr,hi);
    merge(aux,arr,hi);
  }

  function merge_sort(arr) {
    var aux = arr.slice(0);
    sortarrtoarr(arr,arr.length - 1);
    return arr;
  }

  return merge_sort(array);
}

console.time('measure');
mergeSort(arr);
console.timeEnd('measure');
console.log(arr[0],arr[1]);

合并排序与比较功能

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,comparefn) {
  function merge(arr,hi,comparefn) {
    var i = lo;
    var j = mid + 1;
    var k = lo;
    while(true){
      var cmp = comparefn(arr[i],arr[j]);
      if(cmp <= 0){
        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,comparefn) {
    if (hi < lo) return;
    if (hi == lo){
        aux[lo] = arr[lo];
        return;
    }
    var mid = Math.floor(lo + (hi - lo) / 2);
    sortarrtoarr(arr,comparefn);
    sortarrtoarr(arr,comparefn);
    merge(arr,comparefn);
  }

  function sortarrtoarr(arr,comparefn) {
    if (hi <= lo) return;
    var mid = Math.floor(lo + (hi - lo) / 2);
    sortarrtoaux(arr,comparefn);
    sortarrtoaux(arr,comparefn);
    merge(aux,comparefn);
  }

  function merge_sort(arr,comparefn) {
    var aux = arr.slice(0);
    sortarrtoarr(arr,arr.length - 1,comparefn);
    return arr;
  }

  return merge_sort(array,comparefn);
}

console.time('measure');
mergeSort(arr,function compareNumbers(a,b) {
  return a - b;
});
console.timeEnd('measure');
// check result
for (let i = 1; i < length; i++) {
    if(arr[i] < arr[i-1]){
        console.log('error');
        break;
    }
}
console.log(arr[0],arr[1]);

旁注:本机排序不稳定:

本机JavaScript排序 – 测试稳定性

var length = 100000;
var arr = [];
var j;
for (let i = 0; i < length; i++) {
  j = parseInt(Math.random() * 100);
  arr[i] = [j,i];
}

console.time('measure');
arr.sort(function compareNumbers(a,b) {
  return a[0] - b[0];
});
console.timeEnd('measure');

for (let i = 1; i < length; i++) {
    if( (arr[i][0] == arr[i-1][0]) &&
        (arr[i][1] <  arr[i-1][1]) ){
        console.log('not stable');
        console.log(arr[i-1][0],arr[i-1][1]);
        console.log(arr[i  ][0],arr[i  ][1]);
        break;
    }
}

本机Javascript排序 – 更改比较使其稳定

var length = 100000;
var arr = [];
var j;
for (let i = 0; i < length; i++) {
  j = parseInt(Math.random() * 100);
  arr[i] = [j,b) {
  if(a[0] == b[0])
    return a[1] - b[1];
  return a[0] - b[0];
});
console.timeEnd('measure');

for (let i = 1; i < length; i++) {
    if( (arr[i][0] == arr[i-1][0]) &&
        (arr[i][1] <  arr[i-1][1]) ){
        console.log('not stable');
        console.log(arr[i-1][0],arr[i  ][1]);
        break;
    }
}

原文地址:https://www.jb51.cc/js/154434.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐