快速排序算法

核心思路(分治思想)

快速排序采用**分治(Divide and Conquer)**的思想,基本步骤如下:

  1. 选取基准(Pivot):从数组中选择一个“基准值”。
  2. 分区(Partition)
    • 将数组分成两部分:小于基准值的放左边,大于基准值的放右边(可原地交换实现)。
  3. 递归排序(Recursion)
    • 对左右两个子数组递归调用快速排序,直到区间长度为 1 或 0(递归终止条件)。

分区方法

分区方法 核心思路 适用场景
单指针法(Lomuto) 选择 pivot,遍历时将小于等于 pivot 的交换到前面 适用于普通数据,代码简单
双指针法(Hoare) 选择 pivot,左右指针向中间移动,交换不符合条件的元素 适用于大规模数据,交换次数更少
三指针法 维护 < pivot= pivot> pivot 三个区间 适用于数据中大量相同元素,避免不均匀分区

 

代码实现

双指针法:

  • 选择 pivot(基准值):通常选择 数组的第一个元素 arr[low] 作为基准值。
  • 双指针遍历,确定分区位置的索引号
    • 左指针 i:向右移动,寻找到一个大于等于 pivot 的元素
    • 右指针 j:向左移动,寻找到一个小于等于 pivot 的元素
    • 交换 arr[i]arr[j],让小的去左,大的去右。
  • 终止条件:如果 ij 相遇(即 i >= j),那么说明 pivot 已经被正确分区
        function quickSort(arr, start = 0, end = arr.length - 1) {
            if (start < end) {
                //分区索引位置
                let partitionIndex = partition(arr, start, end);
                //分区-左侧排序
                quickSort(arr, start, partitionIndex);
                //分区-右侧排序
                quickSort(arr, partitionIndex + 1, end);
            }
            return arr;
        }
        //排序并返回分区索引点
        function partition(arr, start, end) {
            //基准值
            let pivot = arr[start];
            //由于do while语句的原因,开始节点要-1,结束节点要+1,不然会漏洞头尾元素
            let i = start - 1, j = end + 1;
            while (true) {
                //小于pivot时就一直移动
                do { i++; } while (arr[i] < pivot);
                //大于pivot时就一直移动
                do { j--; } while (arr[j] > pivot);
                // 完成一次分区
                if (i >= j) return j;
                //es6的解构语法实现交换,避免了临时变量
                [arr[i], arr[j]] = [arr[j], arr[i]];
            }
        }

 

do{ 代码块 } while(条件)

do... while 语句其实是 while 语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环。

posted @ 2018-05-26 22:35  我是格鲁特  阅读(219)  评论(0)    收藏  举报