前言
js写快排并不难 但是网上很多js版本的快排并不规范
错误示例1
function test(nums){
if(nums.length <= 1) return nums;
let left = [],right = [];
let target = nums[0];
for(let i=1;i<nums.length;i++){
if(nums[i]>target) right.push(nums[i])
if(nums[i]<=target) left.push(nums[i])
}
// left.push(target);
return test(left).concat(target).concat(test(right));
}
let nums = [3,2,2,1,4];
let res = test(nums);
如上所示 上述快排看上去貌似没问题 但是实质上违背了快排的原则 快排的本质是交换 但是上述代码并没有体现出交换,因此并不规范
错误示例2
/**
* @author vigdxx@gmail.com
* @param {Array} arr 待排序数组
*/
function quickSort(arr) {
/**
* @description 对数组的一部分进行排序,快排的基准为取待排序部分首项
* @param {Number} i 待排序部分开始位置
* @param {Number} j 待排序部分结束位置
*/
function sort(i,j) {
// if(i >= j) {return} // 递归出口
// let start = i;
// let end = j;
if(i>=j) return;
let start = i;
let end = j;
while(i < j) {
for(;j>i;j--) {
if(arr[i] > arr[j]) {
[arr[j],arr[i]] = [arr[i],arr[j]];
break;
}
}
// 这个地方用 ++i,可以少一次比较
for(;i<j;i++) {
if(arr[i] > arr[j]) {
[arr[j],arr[i]] = [arr[i],arr[j]];
break;
}
}
}
// 此时 i == j , arr[i] 左边的小于等于 arr[i],右边的大于arr[i]
sort(start,i-1);
sort(i+1,end)
}
sort(0,arr.length - 1);
return arr;
}
let arr = [ 30, 6, 78, 20, 1, 90 ];
console.log(quickSort(arr));
上述代码貌似也没有问题 但是确没有体现出枢纽,快排算法的第一步就是确定枢纽;
规范的快排
/**
* @author vigdxx@gmail.com
* @param {Array} arr 待排序数组
*/
function quickSort(arr) {
/**
* @description 对数组的一部分进行排序,快排的基准为取待排序部分首项
* @param {Number} i 待排序部分开始位置
* @param {Number} j 待排序部分结束位置
*/
function sort(i,j) {
if(i >= j) {return} // 递归出口
let start = i;
let end = j;
let privot = arr[start];
while(i < j) {
while(i<j&&arr[j]>=privot) j--;
arr[i] = arr[j];
while(i<j&&arr[i]<=privot) i++;
arr[j] = arr[i];
}
arr[i] = privot;
sort(start,i-1);
sort(i+1,end)
}
sort(0,arr.length - 1);
return arr;
}
let arr = [ 30, 6, 78, 20, 1, 90 ];
console.log(quickSort(arr));
上述是笔者用js实现的快排 既体现了枢纽 又体现出了交换的思想;