十大排序之快速排序

快速排序

本文将介绍三种快速排序的方法

  • 经典快速排序
  • 随机快速排序
  • 二分快速排序
经典快速排序算法思想

快速排序基于分治的思想,采用递归的方式处理子问题

选取一个哨兵k,这里假设哨兵选取数组第一个元素

即令k = arr[0] = 4

请添加图片描述

然后设立两个指针 ij 分别初始化指向 第一个元素 和 最后一个元素

请添加图片描述

第一遍排序

从右往左,依次和哨兵比较,如果大于等于哨兵的值,则 j-- ,否则退出循环,然后交换 arr[i]arr[j]

接着从左往右,依次和哨兵比较,如果小于等于哨兵的值,则 i++ , 否者退出循环,然后交换 arr[i]arr[j]

请添加图片描述

请添加图片描述

请添加图片描述

直到 i == j 第一次排序结束,哨兵左侧的值都是小于等于 k 的,右侧都是大于等于 k 的,已经部分有序,接下来进行递归,将左侧继续快速排序,右侧也进行排序

请添加图片描述

请添加图片描述

请添加图片描述

递归结束后,整体就已经有序了

快速排序相比于归并排序来说,不需要另设额外数组,因此空间复杂度会降低,时间复杂度平均情况下也是 O ( N l o g ( N ) ) O(Nlog(N)) O(Nlog(N)),最坏情况下是 O ( N 2 ) O(N^2) O(N2)

以上的解题思路属于书本上的经典快排思想

代码
void quickSort(vector<int>& arr, int left, int right) {
    if (left >= right) return;
    int i = left;
    int j = right;
    int k = arr[i];
    while (i < j) {
        while (i < j && arr[j] >= k) j--;
        swap(arr[j], arr[i]);
        while (i < j && arr[i] <= k) i++;
        swap(arr[i], arr[j]);
    }
    quickSort(arr, left, i - 1);
    quickSort(arr, i + 1, right);
}
随机快速排序算法思想

经典快速排序中,选择的哨兵是固定的,即选择最左侧的元素

但是,容易存在极端现象,如果哨兵选的不好也容易增大时间复杂度,因此,使用随机快排可以避免这类问题

随机快排就是让哨兵的选取变成随机的,即在 [left, right] 中随机选取其中一个元素作为哨兵,然后和 arr[left] 进行交换,再使用经典排序排序的方法即可

代码
void quickSortByRandom(vector<int>& arr, int left, int right) {
    if (left >= right) return;
    // 在区间内随机选取一个元素作为哨兵
    int k = rand() * (right - left + 1) + left;
    // 和left交换
    swap(arr[left], arr[k]);
    int i = left;
    int j = right;
    // 快速排序
    while(i < j) {
        while (i < j && arr[j] >= arr[left]) j--;
        while (i < j && arr[i] <= arr[left]) i++;
        if (i < j) {
            swap(arr[i], arr[j]);
        }
    }
    swap(arr[i], arr[left]);
    quickSortByRandom(arr, left, i - 1);
    quickSortByRandom(arr, i + 1, right);
}
二分快速排序

利用二分法 + 分治 进行排序

void quickSortByBinary(vector<int>& arr, int left, int right) {
    if (left >= right) return;
    int i = left;
    int j = right;
    // 选取中间元素
    int mid = arr[i + ((j - i) >> 1)];
    do {
        while (arr[i] < mid) i++; // 从左到右,找第一个大于等于mid的数
        while (arr[j] > mid) j--; // 从右到左,找第一个小于等于mid的数
        if (i <= j) { // 范围之内进行交换
            swap(arr[i], arr[j]);
            i++;
            j--;
        }
    } while(i < j); // 越界条件
    quickSortByBinary(arr, left, j); // [left, j] 属于<= mid 的区域
    quickSortByBinary(arr, i, right); // [i, right] 属于>= mid 的区域
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值