C++数据结构与算法分析——快速排序

快速排序

介绍

快速排序也叫快排,讲究的是一个字。它是分治思想的一个应用,即:将一个多数据的数组排序问题转换为一个一个数据的排序,每个数据排序后得到的数组即是排序后的数组。

原理

假设有一个数组 a [ n ] a[n] a[n],数组中元素为 a [ 0 ] a [ 1 ] . . . . . . a [ n − 1 ] a[0]a[1]......a[n-1] a[0]a[1]......a[n1]
快速排序就是在这个数组中随机找到一个“哨兵”值 a [ k ] a[k] a[k]
然后将 a [ 0 ] ∼ a [ k − 1 ] a[0] \sim a[k-1] a[0]a[k1]存入比 a [ k ] a[k] a[k]的数,而 a [ k + 1 ] ∼ a [ n − 1 ] a[k+1]\sim a[n-1] a[k+1]a[n1]则存入比 a [ k ] a[k] a[k]的数。
具体实现方法为:
使用两个指针ij,将i指向 a [ 0 ] a[0] a[0]j指向 a [ n − 1 ] a[n-1] a[n1],将i从前往后遍历,j从后往前遍历,在i<j前提下,若a[i] >= a[k],指针i停住,等待。若a[j] <= a[k],指针j停住,等待,若两指针都进入了等待状态,则将a[i]a[j]数值对换,指针继续往前走。
这番操作做完后 a [ 0 ] ∼ a [ k − 1 ] a[0]\sim a[k-1] a[0]a[k1]的数都比 a [ k ] a[k] a[k],而 a [ k + 1 ] ∼ a [ n − 1 ] a[k+1]\sim a[n-1] a[k+1]a[n1]中的数都比 a [ k ] a[k] a[k],此时 a [ 0 ] ∼ a [ k − 1 ] a[0]\sim a[k-1] a[0]a[k1] a [ k ] a[k] a[k] a [ k + 1 ] ∼ a [ n − 1 ] a[k+1]\sim a[n-1] a[k+1]a[n1]已经是从小到大排序了。
因此只需要再将 a [ 0 ] ∼ a [ k − 1 ] a[0]\sim a[k-1] a[0]a[k1] a [ k + 1 ] ∼ a [ n − 1 ] a[k+1]\sim a[n-1] a[k+1]a[n1]分别作为单独数组进行同样的操作即可。
以此类推,当最后分割成单个数据排序后整个数组也就从小到大排序完成了。

时间复杂度( O ( n l o g n ) O(nlogn) O(nlogn))

假设一个数组长度为n,平均每次分割都是分割成长度相等的2个数组,一直分割下去,假设分割 k k k次后每个数组长度为1(代表排序完成),则此时 2 k = n 2^k = n 2k=n,解得 k = l o g 2 n k = log_2n k=log2n,在每次的循环中数组都要遍历一遍,因此时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度( O ( 1 ) O(1) O(1))

因为只用了i,j,l,r,t等有限个额外空间,因此空间复杂度为 O ( 1 ) O(1) O(1)

快排模拟

我们以一个长度 n = 5 n=5 n=5数组为例:

3 1 2 4 5

我们取它的中间数mid = 2t = a[2] = 2此时i = 0j = 4

  1. 判断a[0]是否小于t:∵3 > 2,指针i停住。
  2. 判断a[4]是否大于t:∵5 > 2,j--
  3. 判断a[3]是否大于t:∵4 > 2,j--
  4. 判断a[2]是否大于t:∵2 = 2,指针j停住
  5. 此时ij都在等待状态,将a[i]a[j]的数值进行交换,i++j--
  6. 此时i = 1,j = 1,i == j,跳出循环
  7. 此时的数组为

    2 1 3 4 5

  8. mid处分割成两个数组,第一个为 a [ 0 ] ∼ a [ m i d ] a[0]\sim a[mid] a[0]a[mid],第二个为 a [ m i d + 1 ] ∼ a [ n − 1 ] a[mid+1]\sim a[n-1] a[mid+1]a[n1],再分别进行相同操作。后面可以自行模拟。

代码

void quick_sort(int q[],int l,int r){
   if(l >= r) return;//l == r 也可以,因为l == r时一定会结束

   int t = q[(r+l)/2], i = l - 1, j = r + 1;
   //因为do-while循环会先执行一次i++和j--,所以i先减1,j先加1

   while(i < j){
       do i++;while(q[i] < t);
       do j--;while(q[j] > t);
       if(i < j) swap(q[i],q[j]);
   }
   quick_sort(q,l,j);
   quick_sort(q,j + 1,r);
}

边界问题

快排边界问题和整数二分边界问题本质是一样的,都是容易引起死循环,这里就不说了,但是这个模板是没有问题的,将分割处记住即可。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

L_Hygen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值