快速排序

283 阅读2分钟

小知识,大挑战!本文正在参与“  程序员必备小知识  ”创作活动

1.快速排序描述
  1.每一轮排序选择一个基准点(pivot)进行分区

    1.让小于基准点的元素进入一个分区,大于基准点的元素进入另一个分区

    2.当分区完成时,基准点元素的位置就是其最终位置

  2.在子分区重复以上过程,直至子分区元素个数少于等于1,这体现的是分而治之的思想(divide-and-conquer)
2.单边循环快排 (lomuto 洛穆托分区方案)

  1.选择最右元素作为基准点元素

  2. i 指针维护小于基准点元素的边界,也是每次交换的目标索引

  3. j 指针负责找到比基准点小的元素,一旦找到则与 i 进行交换

  4.最后基准点与i交换,i即为分区位置

3.特点

  1.平均时间复杂度是 O(n㏒ⁿ) ,最坏时间复杂度是 O(n²)

  2.数据量较大时,优势非常明显

  3.属于不稳定排序

public static void main(String[] args) {
    // 原始数据
    int[] arr = {5,3,7,2,9,8,1,4};
    quickSort(arr,0,arr.length - 1);
}

//快速排序方法 递归方法
public static void quickSort(int[] arr,int l,int h) {
    if (l >= h) {
        // 代表没有可以执行的分区退出递归
        return;
    }
    //调用分区方法 获取每轮分组的边界
    int p = partition(arr, l, h);
    //左边分区的范围确定
    quickSort(arr,l,p - 1);
    //右边分区的范围确定
    quickSort(arr,p + 1,h);
}

//分区方法
public static int partition(int[] arr ,int l,int h) {
    // pv是基准点元素,h 是分区上限也是本轮分区基准点
    int pv = arr[h];
    // i 是交换目标索引,l 是左边界
    int i = l;
    // j 开始循环获取比基准点小的值
    for (int j = l; j < h; j++) {
        if (arr[j] < pv) {
            if (i != j) {
                // 如果比较的元素小于基准点,
                // 并且他不是目标索引的位置,
                // 就把j元素交换到目标索引位置
                swap(arr,i,j);
            }
            // 目标索引加1
            i++;
        }
    }
    if (i != h) {
        swap(arr,h,i);
    }
    System.out.println(Arrays.toString(arr)+"本轮基准点正确位置i:="+i);
    // 返回值代表基准点元素所在正确索引位置,用它确定下一轮分区的边界
    return i;
}

// 交换方法
public static void swap(int[] arr,int i,int j) {
    int t = arr[i];
    arr[i] = arr[j];
    arr[j] = t;
}

执行效果

quickSort.jpg