常用排序算法的JavaScript实现与性能比较

一、冒泡排序

 原理:依次比较两个相邻的项,如果前者大于后者,则交换两者位置,就如同气泡往上冒一样。

代码实现:

Array.prototype.bubbleSort = function(){
	var length = this.length;
	for(var i=0;i<length;i++){
		for(var j=0;j<length-1-i;j++){
			this[j]>this[j+1] && swap(this,j,j+1)  //swap方法交换两个元素
		}
	}
}

注意,内层循环的次数需要减掉外层已循环过的次数,因为外层循环每走一遍就有一个元素被排好序,无需再进行排序。

这种排序方式的时间复杂度为O(n^2),(时间复杂度的计算方法参见http://baike.baidu.com/link?url=DnQgmILQ4dt2kCRwafBtNJHo21upzQVZAX2Y6TyJLoh2rxy_YQtxfhjwhmHmneETaSlw9KuKCjzSJqwGtzL4CUSm4aC3mYTfDlsjfZWCRFiQ8TiPnKHvn3mZ6-YpTkAYX1MEn5BRoFmjOHFRjzNCSK)

,我们可以在http://math.hws.edu/eck/js/sorting/xSortLab.html中模拟这个过程,结果如下:

执行10个长度为10000的乱序数组的排序,总耗时为28.7秒

二、选择排序

原理:从数组中找到最小值,与数组首位交换位置(即放在第一位),接着再寻找第二小的值,放在第二位,以此类推

代码实现:

Array.prototype.selectSort = function(){
	var length = this.length, minIndex;
	for(var i =0;i<length-1;i++){
		minIndex = i;
		for(var j=i;j<length;j++){
			if(this[minIndex]>this[j])minIndex = j;
		}
		i !== minIndex) && swap(this,i,minIndex);  //swap方法交换两个元素
	}
}

这种排序方式的时间复杂度为O(n^2),模拟排序结果如下:

执行10个长度为10000的乱序数组的排序,总耗时为17.7秒

三、插入排序

插入排序分为直接插入排序,二分插入排序和希尔排序,这里介绍的是直接插入排序

原理:将数列的第一个元素视为有序数列,后面都视为无序数列:

{{a1},{a2,a3,a4,…,an}}

然后将无序数列中的元素插入到有序数列的对应位置,插入前通过比大小的方式找到其在有序数列中的对应位置。

Array.prototype.insertSort = function(){
	var length = this.length, j, temp;
	for(var i=1;i<length;i++){
		j = 1;
		temp = array[i];  //temp为待排序项
		while(j>0 && array[j-1] > temp){  
			array[j] = array[j-1];		  
			j--;
		}
		//若temp项之前存在比temp大的项,则把这个项移到当前位置上,
		//直到找不到比temp更大的项时,
		array[j] = temp		
		//执行插入操作			
	}
}

这种排序方式的时间复杂度为O(n^2),模拟排序结果如下:

执行10个长度为10000的乱序数组的排序,总耗时为8秒

四、归并排序

从这里开始才是真正能投入实际使用的排序方法,包括最后的快速排序,浏览器一般使用这两种方法之一作为sort函数的实现(但是V8对较短的数组使用插入排序方法)

原理:归并排序采用分治–递归的思想,先对一个数组进行不断的对半拆解,直至子项个数为1。如图:

(原图:http://www.108js.com/article/article5/img/1.png)

之后执行合并,从最下层开始,依次比较左边的项是否比右边的小,是的话移除左数组的第一位并放进新数组中,否则移除右数组的第一位并放进新数组中,这样就可以重新合并出一个排完序的大数组。

代码实现:

function merge(left, right) {
		var result = [];
		while(left.length > 0 && right.length > 0) {
			if(left[0] < right[0]) {
				result.push(left.shift());
			} else {
				result.push(right.shift());
			}
		}
		// 当左右数组长度不等.将比较完后剩下的数组项链接起来即可
		console.log(result)
		return result.concat(left).concat(right);
	}
	
	function mergeSort(array) {
		if(array.length == 1) return array;
		// 对半划分
		var mid = Math.floor(array.length / 2);
		var left = array.slice(0, mid);
		var right = array.slice(mid);
		// 递归合并
		return merge(mergeSort(left), mergeSort(right));
	}

这种排序方式的时间复杂度为O(n*log n),模拟排序结果如下:

能发现归并排序对大数组的排序效率已经有了质的提升

五、快速排序

原理:首先选取一个基准项(pivot),我们一般选取中间项作为pivot;接着所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。然后对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止

代码实现:

var quickSort = function(arr) {
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat([pivot], quickSort(right));
};

这里参考了阮一峰老师的文章,详情可移步

http://www.ruanyifeng.com/blog/2011/04/quicksort_in_javascript.html

这种排序方式的时间复杂度为O(n*log n),模拟排序结果如下:

与归并排序很接近,对于快速排序与归并排序的性能比较,可参考以下文章:

http://stackoverflow.com/questions/680541/quick-sort-vs-merge-sort

作者:lee1994522

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值