[排序算法]快速排序基本思路及代码实现

110 阅读2分钟

昨天学习了快速排序,平均时间复杂度 O(n log2n), 本文排序默认按升序处理。


快速排序

思路

目前快排大致分两种思路,一种是挖坑填补法,另一种是交换元素法。 我学习的是第二种 交换元素法,第一种等日后再复习快排时学习补充在这里吧(挖坑....) 交换元素法的基本思路是:

  1. 选定枢纽:某个数组中 某个元素,开头或结尾或中间元素均可。
  2. 找位置:我们要找到枢纽元素在即将有序的数组中的位置。方法如下: 假设我们选定最后一个元素len - 1len为数组长度)作为枢纽元素, 那么我们把除了枢纽元素剩下的元素分组,比枢纽元素小的一组,比枢纽元素大 的一组, 具体方法:(比较绕可以直接读代码)使用双指针将指向的元素与枢纽元素,依次比较并交换,左侧第一个比枢纽元素大的和右侧第一个比枢纽元素小的元素。
  3. 对枢纽两侧数组重复1 、2步骤。

快排的算法的核心是找位置这个步骤,找到枢纽元素本所在的位置,同时将两侧以枢纽元素为基准按大小分组 快速排序 参考代码

arr = [5, 3, 6, 1, 8, 4, 7, 2, 0, 9];
// 快速排序(交换版本)
function quickSort(array, begin, end) {
    if (array.length === 1) {//大小为1就返回
        return;
    }
    // 排序部分
    if (begin < end) {
        let mid = separate(array, begin, end);
        // 以下几行为展示快排数组区间代码
        console.log(`区间${begin}-${end} 枢纽所在的位置${mid}`);
        let showArr = array.map((index, value) => {
            if (value >= begin && value <= end) {
                return `${index}`;
            } else {
                return index;
            }
        });
        console.log(showArr);
        //————————————————————————————
        quickSort(array, begin, mid - 1);
        quickSort(array, mid + 1, end);
    }
}
function separate(array, left, right) {
    let pivot = array[right];//取最后的作枢纽
    let i = left;
    let j = right - 1;
    while (true) {
        while (i < right && array[i] < pivot) {
            i++;
        }
        while (j > 0 && array[j] > pivot) {
            j--;
        }
        if (i < j) {//上面的i j 分别从左右两个方向,向中间遍历到了i(比枢纽大的数) j(比枢纽小的数)
            [array[i], array[j]] = [array[j], array[i]];
        } else {//如果两个指针已经相遇了,就交换i和枢纽的位置。
            [array[right], array[i]] = [array[i], array[right]];
            break;
        }
    }
    return i;
}
quickSort(arr, 0, arr.length - 1);

注意事项

  1. 分两个函数,一个是递归的快排自身,另一个是分区返回枢纽下标给mid的分离函数。
  2. 快排递归时,分左[begin, mid - 1] 右[mid + 1, end] 两个区间分别递归。
  3. 分区时,要在枢纽元素之外的数进行查找比较,查找时和交换时,都要确认两个指针的位置。

平均时间复杂度:O(nlog2n) 一般是左右两个区间二分。