当前位置:   article > 正文

快速排序及优化

快速排序及优化

普通快速排序(以升序为例):

  1. 每一轮排序选择一个基准点进行分区:让小于基准点的元素的进入一个分区,大于基准点的元素的进入另外一个分区,当分区完成时,基准点元素的位置就是其最终位置;
  2. 在子分区内重复以上过程,直到子分区元素个数少于等于1。

实现方式

1. 单边循环快排
a. 选择最右元素作为基准点元素
b. j指针负责找到比基准点小的元素,一旦找到则与i进行交换;
c. i指针维护小于基准点元素的边界,也是每次交换的目标索引
d. 最后基准点与i交换,i即为分区位置

import java.util.Arrays;

/**
 * 单边循环快排
 */
public class Task04_QuickSort1 {

    public static void main(String[] args) {
        int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
        quick(a, 0, a.length-1);
    }

    public static void quick(int[] a,int l,int h){
        if (l >= h){
            return ;
        }
        int p = partition(a, l, h); // p 索引值
        quick(a, l,p - 1); // 左边分区的范围确定
        quick(a,p + 1, h); // 右边分区的范围确定
    }

    public static int partition(int[] a,int l, int h){
        int pv = a[h]; // 基准点元素
        int i = l; // 每次交换的目标索引
        for (int j = l;j < h;j++){
            if (a[j] < pv){
                // 优化
                if (i != j) {
                    swap(a, i, j);
                }
                i++;
            }
        }
        // 优化
        if (i != h){
            swap(a, i, h);
        }
        System.out.println(Arrays.toString(a) + " i=" + i);

        // 返回值代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
        return i;
    }

    public static void swap(int[] a,int i,int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

在这里插入图片描述

2. 双边循环快排
a. 选择最左元素作为基准点元素;
b. j指针负责从右往左找到比基准点小的元素,i指针负责从左往右找到比基准点大的元素,一旦找到二者交换,直至i,j相交;
c. 最后基准点与i(此时i与j相等)交换,i即为分区位置

public static int partition(int[] a,int l, int h){
        int pv = a[l];
        int i = l;
        int j = h;
        while (i < j){
            // j 从右往左找小的
            while (i < j && a[j] > pv){
                j--;
            }
            // i 从左往右找大的
            // i < j:5 1 2 3 6 7 8 9,pv=5,j=3,i=5
            // i一直到6,才找到比基准大的,如果没有i<j,基准点5要被6交换走了
            // <= :防止一开始时,基准点元素被交换
            while (i < j && a[i] <= pv){
                i++;
            }
            swap(a, i, j);
        }
        // 基准点元素与i交换
        swap(a, l, i);
        System.out.println(Arrays.toString(a)+" i="+i);
        return i;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

要点:

  1. 基准点在左边,并且要先j后i;
  2. while(i < j && a[j] > pv ) j–;
  3. while(i < j && a[i] <= pv ) i++;

特点:

  1. 平均时间复杂度是O(nlog2n),最坏时间复杂度O(n^2);
  2. 数据量较大时,优势比较明显;
  3. 属于不稳定排序。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/640400
推荐阅读
相关标签
  

闽ICP备14008679号