归并排序
假设初始数组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)