两个O(nlogn)的排序算法——归并排序和快速排序

归并排序

假设初始数组a = [9,8,7,6,5,4,3,2,1],数组长度为9。要求从小排到大
排序思路:
将数组一直对半分解为两部分,直到分解为每个部分都只有一个元素,然后排序好合并,整个过程就变成了合并有序数组
过程如下
1.将数组一直对半分解为两部分:
[9,8,7,6,5,4,3,2,1]
[9,8,7,6,5]&&[4,3,2,1]
[9,8,7]&&[6,5],[4,3]&&[2,1]
[9,8]&&[7],[6]&&[5],[4]&&[3],[2]&&[1]
[9]&&[8]
然后开始合并,并排序好
[8,9]&[7],[6]&&[5],[4]&&[3],[2]&&[1]
[7,8,9]&&[5,6],[3,4]&&[1,2]
[7,8,9]&&[5,6],[3,4]&&[1,2]
[5,6,7,8,9]&&[1,2,3,4]
[1,2,3,4,5,6,7,8,9]
js实现代码如下

const a = [9,8,7,6,5,4,3,2,1]
function mergeSort(arr,p,q){
	//只有一个元素就不再分解了
	if(p < q){
		//只有一个元素就不再分解了
		const m = parseInt((p+q)/2)
		mergeSort(arr,p,m)
		mergeSort(arr,m+1,q)
		merge(arr,p,m,q)
	}
}
function merge(arr,p,r,q){
	let i = p,j = r+1
	let temp = []
	while(i <= r && j <= q){
		if(arr[i] <= arr[j]){
			temp.push(arr[i])
			i++
		}else{
			temp.push(arr[j])
			j++
		}
	}
	if(i <= r){
		for(;i <= r;i++){
			temp.push(arr[i])
		}
	}
	if(j <= p){
		for(;j <= q;j++){
			temp.push(arr[i])
		}
	}
	//将排序完的数组拷贝回原数组
	for(let k = 0 ; k < temp.length ; k++){
		arr[p+k] = temp[k]
	}
}
mergeSort(a,0,a.length-1)
console.log(a)
//生成随机数组测试
const b = []
const n = 10//数组长度
for(let i = 0 ; i < n ; i++){
    b.push(parseInt(n*Math.random()))
}
console.log(b)
const s = new Date().getTime()
mergeSort(b,0,b.length-1)
const e = new Date().getTime()
console.log(e-s)
console.log(b)

从merge函数中可以看到申明了一个temp数组暂存排序好的元素,所以归并排序原地排序算法

快速排序

假设初始数组a = [8,9,2,3,6,5,7,4,1],数组长度为9。要求从小排到大
快速排序简称快排
排序思路
如果要 排序 数组中下标p到q,那么就从其中任选一个元素,利用这个元素作为分区点,将比它小的元素放到左边,比它大的数放到右边,它放中间(不一定是正中央),然后对左边右边区间重复此操作,直到区间缩小到1,那么排序就完成了
过程如下
1.从要排序数组中选择任意一个数,比如选择了a[7] = 4作为分区点,然后将比4小的和比4大的筛选出来[2,3,1]&&[8,9,6,5,7],将分区点放到这两个区间中间,此时a=[2,3,1,4,8,9,6,5,7]
2.此时左右区间都不止一个元素,继续对左右区间[2,3,1]&&[8,9,6,5,7]重复步骤1,比如分区点都选择倒数第一个数,分别是1和7,可以得到[]&&[2,3]和[6,5]&&[8,9],将分区点分别放到中间得到[1,2,3]&&[6,5,7,8,9],此时a=[1,2,3,4,6,5,7,8,9]
3.此时还有区间都不止一个元素,[2,3],[6,5],[8,9]对这些区间重复步骤1,分区点还是都选择倒数第一个数,分别是3,5,9,可以得到[2]&&[],[]&&[6],[8]&&[],将分区点分别放到中间得到[2,3],[5,6],[8,9],此时a=[1,2,3,4,5,6,7,8,9],完成排序
js代码实现如下
1.非原地排序写法

const a = [8,9,2,3,6,5,7,4,1]
function quickSort(arr,p,q){
	if(p >= q) return
	//选择最后一个数字作为分区点
	let pivot = arr[q]
	let left = []
	let right = []
	for(let i = p ; i < q; i++){
		if(arr[i] < pivot){
			left.push(arr[i])
		}else{
			right.push(arr[i])
		}
	}
	let j = p
	//拷贝
	for(let i = 0 ; i < left.length ; i++){
		arr[j++] = left[i]
	}
	let m = j
	arr[j++] = pivot
	for(let i = 0 ; i < right.length ; i++){
		arr[j++] = right[i]
	}
	quickSort(arr,p,m-1)
	quickSort(arr,m+1,q)
}
quickSort(a,0,a.length-1)
console.log(a)
//生成随机数组测试
const b = []
const n = 10//数组长度
for(let i = 0 ; i < n ; i++){
    b.push(parseInt(n*Math.random()))
}
console.log(b)
const s = new Date().getTime()
quickSort(b,0,b.length-1)
const e = new Date().getTime()
console.log(e-s)
console.log(b)

2.原地排序写法

const a = [8,9,2,3,6,5,7,4,1]
function quickSort(arr,p,q){
	if(p >= q) return
	let i = p,j = p
	for(;j < q;j++){
		if(arr[j] < arr[q]){
			[arr[i],arr[j]] = [arr[j],arr[i]]
			i++
		}
	}
	[arr[i],arr[j]] = [arr[j],arr[i]]
	quickSort(arr,p,i-1)
	quickSort(arr,i+1,q)
}
quickSort(a,0,a.length-1)
console.log(a)
//生成随机数组测试
const b = []
const n = 10//数组长度
for(let i = 0 ; i < n ; i++){
    b.push(parseInt(n*Math.random()))
}
console.log(b)
const s = new Date().getTime()
quickSort(b,0,b.length-1)
const e = new Date().getTime()
console.log(e-s)
console.log(b)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值