经典算法:快速排序

快速排序

快速排序是对[[冒泡排序]]的优化,使用了分治的思想。

步骤

  1. 选择基准元素(Pivot):从数组中选择一个元素作为基准。常见的选择方法有:

    • 选择第一个元素
    • 选择最后一个元素
    • 选择中间的元素
    • 随机选择一个元素
    • 三数取中法(选择第一个、最后一个和中间值的中间值)
  2. 划分操作(Partition):将数组重新排列,使得所有小于基准的元素都位于基准的左侧,而所有大于基准的元素都位于基准的右侧。基准元素位于最终位置。理想情况下左右划分应相对均匀。

  3. 递归排序

    • 对基准左侧的子数组进行快速排序
    • 对基准右侧的子数组进行快速排序
  4. 合并:由于快速排序是在原地排序(in-place),不需要额外的合并步骤。

复杂度分析

理想情况(平均情况)

  • 假设划分均匀,那么共需要 O ( l o g n ) O(logn) O(logn)时间。
  • 每次划分对每个数排序,即n次。时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

最坏情况

  • 原数组有序,且基准元素选择不优秀;
    假设有数组[1,2,3,4,5,6,7,8,9],基准元素为最后一个,递增排序;
第一次划分
  • 基准:9
  • 左侧子数组:[1, 2, 3, 4, 5, 6, 7, 8]
  • 右侧子数组:[]
第二次划分
  • 基准:8
  • 左侧子数组:[1, 2, 3, 4, 5, 6, 7]
  • 右侧子数组:[]
第三次划分
  • 基准:7
  • 左侧子数组:[1, 2, 3, 4, 5, 6]
  • 右侧子数组:[]

可以看出,这其实就是冒泡,复杂度为 O ( n 2 ) O(n^2) O(n2),也可以看出,这个算法不稳定

总结

  • 快速排序是一种高效的排序算法,平均时间复杂度为 O ( n l o g ⁡ n ) O(nlog⁡n) O(nlogn)
  • 在最坏情况下,时间复杂度可能退化为 O ( n 2 ) O(n^2) O(n2),但通过优化基准元素的选择,可以减少这种情况的发生。
  • 快速排序是不稳定的排序算法,可能会改变相同元素的相对顺序。

模板

#define MAX_N 1000000

int N;
int nums[MAX_N];

int partition(int low, int high)
{
    int pivot = nums[low];
    while (low < high)
    {
        while (low < high && nums[high] >= pivot) high--;
        nums[low] = nums[high];
        while (low < high && nums[low] <= pivot) low++;
        nums[high] = nums[low];
    }
    nums[low] = pivot;
    return low;
}

void qsort(int low, int high)
{
    if (low < high)
    {
        int mid = partition(low, high);
        qsort(low, mid - 1);
        qsort(mid + 1, high);
    }
}
  • 21
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云璃丶夢紡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值