时隔一年(当时是2020.05.02),再看当初写的快排,只能说能排序,但是性能比较差:
1,选取比较元素的时候,没必要浪费两次数学计算去取中间值!也就是这个是没必要的:
const middleIndex = Math.floor(arr.length/2);
因为本身就是待排数组,取任何一个元素做中间值都一样,因为每一个元素都可能出现在数组的任意位置,完全没不要去取中间元素。
2,用到了数组的高级用法splice去取中间元素,还去操作删除数组,这个删除元素本身就会涉及到底层数据搬移。会降低性能,完全可以优化掉。
const middleValue = arr.splice(middleIndex,1)[0]; // 把计划做中间数据的元素拿出来
3,空间复杂度高,不是原地排序。
每次拆分都的数组都涉及临时数组leftArr和rightArr。
今天(2021.08.22)将上述3个点优化掉前两个,第三个优化实现有点复杂,往后再尝试。
function quickSort(arr){
if(arr.length <=1){
return arr;
}
const middleIndex = 0;// Math.floor(arr.length/2);
const leftArr = [], rightArr = [], middle = [arr[middleIndex]];
for(let i=0; i< arr.length; i++){
if(i !== middleIndex ) {
if(arr[i] < middle[0]){
leftArr.push(arr[i])
}else{
rightArr.push(arr[i])
}
}
}
return quickSort(leftArr).concat(middle,quickSort(rightArr) )
}
以下是202.05.02的原文,对理解快速排序也还是有帮助。
今天有个朋友问快速排序的原理,用processon给他画了一个图,也顺手贴上来,给需要的朋友使用。
快排的核心原理是:
1,选数组中的中间数据为比较的基数 (其实选哪个都可以,选第一个或者最后一个都行)
2,从头开始遍历数组,跟选出来的中间数进行比较,比中间数小的放左边数组,大的放右边数组
3,此时得到leftArr数组、中间元素、右边数组
4,分别对左边数组执行步骤1~3,直到拆不出数组位置。
5,最后会把拆出来的元素都连起来。
直接上一个流程图,希望一图能胜千言哈:
直接撸代码(Javascript):
var originalArr = [12,23,16,14,12,21,7];
function quickSort(arr) {
// 只有一个元素的时候就不用排了,直接返回,需要一直拆解到只有一个元素
if(arr.length<=1){
return arr;
}
// 拿到中间元素
const middleIndex = Math.floor(arr.length/2);
const middleValue = arr.splice(middleIndex,1)[0]; // 把计划做中间数据的元素拿出来
let left = [];
let right = [];
// 跟别跟中间元素进行大小比较
for(let i=0;i<arr.length;i++){
if(arr[i]<=middleValue){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
// 这一步是关键,需要递归的处理
return quickSort(left).concat(middleValue,quickSort(right));
}
let newArr = quickSort( [...originalArr] );
console.log(`quickSort end, newArr = ${JSON.stringify(newArr)}`);
// 结果: quickSort end, newArr = [7,12,12,14,16,21,23]