快速排序的更易理解版

242 阅读1分钟

今天旧活新整,发现了一个快速排序的更易理解版,还是在原有空间进行排序,不过能更好体现快速排序的策略特点。

好活共赏。

//快速排序不是稳定排序。最坏时间复杂度为O(n2) 最好情况 O(nlogn) 平均情况 O(nlogn)


function quicksort(start, end, nums) {
    if (start > end) {
        return;
    }
    let pivot = nums[end],
        i = start - 1; //i最开始没有确定比枢纽值小的子序列
    for (let j = start; j < end; j++) {
        if (nums[j] <= pivot) {
            i++;
            [nums[i], nums[j]] = [nums[j], nums[i]];
        }
    }
    //i是比枢纽值小的子序列的最后一个
    //i+1确定了枢纽值的位置

    [nums[i + 1], nums[end]] = [pivot, nums[i + 1]];
    quicksort(start, i, nums);
    quicksort(i + 2, end, nums)
}

function randomNums(len) {
    let arr = [];
    for (let i = 0; i < len; i++) {
        arr[i] = Number.parseInt(Math.random() * 1000);
    }
    return arr;
}

function main() {
    let nums = randomNums(10);
    let numStandard = [...nums];
    quicksort(0, nums.length - 1, nums);
    numStandard.sort((a, b) => a - b);
    console.log(nums);
    console.log(numStandard);
    console.log(numStandard.toString() == nums.toString());
}
main();

快速排序基于分治法,通过选取枢轴值,将原数组分解为两半,一半均比枢轴值小,一半均比枢轴值大,不断拆分子问题。 今天这个版本,更易体现这种枢轴划分的特点。

 let pivot = nums[end],
        i = start - 1; //i最开始没有确定比枢纽值小的子序列
for (let j = start; j < end; j++) {
        if (nums[j] <= pivot) {
            i++;
            [nums[i], nums[j]] = [nums[j], nums[i]];
        }
 }

注意看, 结果上[start,i]这个双闭区间中的元素全比枢轴值小,妙啊,比双指针的while循环更易理解,属实拿捏了。

下面是最常见快排的实现

//快速排序不是稳定排序。最坏时间复杂度为O(n2) 最好情况 O(nlogn) 平均情况 O(nlogn)


function quicksort(start, end, nums) {
    if (start > end) {
        return;
    }
    let pivot = nums[start],
        l = start,
        r = end;
    while (l != r) {
        while (nums[r] >= pivot && l < r) {
            r--;
        }
        while (nums[l] <= pivot && l < r) {
            l++;
        }
        if (l < r) {
            [nums[l], nums[r]] = [nums[r], nums[l]];
        }

    }
    [nums[start], nums[l]] = [nums[l], pivot];

    quicksort(start, l - 1, nums);
    quicksort(l + 1, end, nums)
}

function randomNums(len) {
    let arr = [];
    for (let i = 0; i < len; i++) {
        arr[i] = Number.parseInt(Math.random() * 1000);
    }
    return arr;
}

function main() {
    let nums = randomNums(10);
    let numStandard = [...nums];
    quicksort(0, nums.length - 1, nums);
    numStandard.sort((a, b) => a - b);
    console.log(nums);
    console.log(numStandard);
    console.log(numStandard.toString() == nums.toString());
}
main();

再整个快排随机版,也就那么回事。

//快速排序不是稳定排序。最坏时间复杂度为O(n2) 最好情况 O(nlogn) 平均情况 O(nlogn)


function quicksort(start, end, nums) {
    if (start > end) {
        return;
    }
    let pivotIndex = Number.parseInt(Math.random() * (end - start) + start);
    let pivot = nums[pivotIndex],
        l = start,
        r = end;
    //随机化就体现在随机选取枢轴,然后与第一个交换
    [nums[start], nums[pivotIndex]] = [nums[pivotIndex], nums[start]];
    while (l != r) {
        while (nums[r] >= pivot && l < r) {
            r--;
        }
        while (nums[l] <= pivot && l < r) {
            l++;
        }
        if (l < r) {
            [nums[l], nums[r]] = [nums[r], nums[l]];
        }

    }

    //l==r
    [nums[start], nums[l]] = [nums[l], pivot];

    quicksort(start, l - 1, nums);
    quicksort(l + 1, end, nums)
}

function randomNums(len) {
    let arr = [];
    for (let i = 0; i < len; i++) {
        arr[i] = Number.parseInt(Math.random() * 1000);
    }
    return arr;
}

function main() {
    let nums = randomNums(10);
    let numStandard = [...nums];
    quicksort(0, nums.length - 1, nums);
    numStandard.sort((a, b) => a - b);
    console.log(nums);
    console.log(numStandard);
    console.log(numStandard.toString() == nums.toString());
}
main();

快排刻烟吸肺。