• 快速选择排序


    "你经过我每个灿烂时刻,我才真正学会如你般自由" 


             前些天有些无聊,想试试自己写的快排能否过leetcode上的排序算法题。结果是,不用截图可想而知,肯定是没过的,否则也不会有这篇文章的产出。

            这份快排算法代码在面对大量重复数的时候,时间复杂度会下降到O(n^2),这也是为什么leetcode显示最后会超时。所以如何解决呢?也许在此之前,可以先回顾回顾快排三步核心算法步骤。

    ——前言


    快排的三个核心算法

    ● HOARE版

            这是最早的版本,也叫做左右指针法。不过这个算法需要值得注意的是一个地方。排升序时,一定是需要右指针先动,相反如果是排降序,则是左指针先动。        

    1. int PartSort1(vector<int>& nums, int l, int r)
    2. {
    3. // 左右指针法
    4. int key = nums[l];
    5. int left = l;
    6. int right = r;
    7. while (left < right)
    8. {
    9. // 这里需要注意取等
    10. // 如果不取等可能陷入死循环
    11. while (left < right && nums[right] >= key)
    12. {
    13. right--;
    14. }
    15. while (left < right && nums[left] <= key)
    16. {
    17. left++;
    18. }
    19. if (left < right) {
    20. swap(nums[left], nums[right]);
    21. }
    22. }
    23. // 处理keyi
    24. swap(nums[left], nums[l]);
    25. return left;
    26. }

            我们对上述例子进行排序后的代码为:

    ● 挖坑法

            

    1. int PartSort2(vector<int>& nums, int l, int r)
    2. {
    3. int key = nums[l];
    4. int hole = l;
    5. int left = l, right = r;
    6. while (left < right){
    7. // 右边找小 填左坑
    8. while (left < right && nums[right] >= key){
    9. right--;
    10. }
    11. // 填坑
    12. swap(nums[right], nums[hole]);
    13. hole = right; // 新坑
    14. while (left < right && nums[left] <= key){
    15. left++;
    16. }
    17. swap(nums[left], nums[hole]);
    18. hole = left; // 新坑
    19. }
    20. // hole即为最终落脚点
    21. return hole;
    22. }

            

    ● 前后指针法

            最后的前后指针法,也在前言中用到,这里不做多的解释。

    1. int PartSort3(vector<int>& nums, int l, int r)
    2. {
    3. int key = nums[l];
    4. int prev = l, cur = l + 1;
    5. while (cur <= r)
    6. {
    7. // 找小
    8. if (nums[cur] < key && ++prev != cur)
    9. {
    10. // prev指向的一定是比key大的数
    11. swap(nums[prev], nums[cur]);
    12. }
    13. cur++;
    14. }
    15. swap(nums[prev], nums[l]);
    16. return prev;
    17. }

            


    快速选择排序

            可是,你使用上述的不管哪种算法,都无法跑过leetcode上面的题,都会在重复数的情况下超时!这里我们可以用到归并分治的思想,如果将一个无序数组排序成有序数组,选定其中一个数作为key,可以将这个数组分为三部分:

    1. int getRandom(vector<int>& nums, int l, int r)
    2. {
    3. int keyi = rand();
    4. return nums[keyi % (r-l+1) + l];
    5. }
    6. void qsort(vector<int>& nums, int l, int r)
    7. {
    8. if(l < r)
    9. {
    10. int key = getRandom(nums,l,r);
    11. // 数组分三块
    12. // 先让left、right指向非法区域
    13. int i = l,left = l-1,right = r+1;
    14. // [i,right]是未处理区域
    15. while(i < right)
    16. {
    17. if(nums[i] < key) swap(nums[++left],nums[i++]);
    18. else if(nums[i] == key) i++;
    19. else swap(nums[--right],nums[i]);
    20. }
    21. // 递归处理其他区间
    22. qsort(nums,l,left);
    23. qsort(nums,right,r);
    24. }
    25. }

            我们终于是可以通过啦~


    本篇到此结束,感谢你的阅读。

    祝你好运,向阳而生~

  • 相关阅读:
    七大基本比较排序算法(上)
    软件设计师 程序设计语言
    Angular 服务器端渲染应用的一个错误消息 type ReferenceError - localStorage is not defined
    Error:QSqlDatabase: QMYSQL driver not loaded (Qt+C++ 找不到mysql的驱动)
    vue常见问题汇总
    Tars-Java网络编程源码分析
    将数据、代码、栈放入不同的段
    抖音矩阵系统,这个排名很难啊。按?
    esp32 nvs set_blob
    在UniApp中引入大于40kb字体包的记录
  • 原文地址:https://blog.csdn.net/RNGWGzZs/article/details/133523008