• 数据结构------排序3(快速排序)


    引言:

     

    上面两篇文章讲了几种排序方法,它们的一些性能和时间复杂度我进行了总结,如果一些代码不懂可以参考《排序1》,《排序2》

    1.什么是快速排序?      

    1.1快拍定义及图解

    1.首先设定一个分界值,通过该分界值将数组分成左右两部分。  2.将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。   3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。  4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

     2.hoare法实现

    hoare法是快拍中比较常用的一种方法。

    2.1hoare单趟实现

    1. //快速排序单趟实现
    2. int PartSort1(int* a, int begin, int end)
    3. {
    4. int left = begin;
    5. int right = end;
    6. int key = begin;
    7. int keyi = begin;
    8. if (begin >= end)//如果最多有一个就不用递归了
    9. {
    10. return;
    11. }
    12. while (left < right)
    13. {
    14. while (left < right && a[right] >= a[key])
    15. {
    16. right--;
    17. }
    18. while (left < right && a[left] <= a[key])
    19. {
    20. left++;
    21. }
    22. Swap(&a[left], &a[right]);
    23. }
    24. Swap(&a[left], &a[keyi]);
    25. return left;

     2.2多趟实现

    2.21大致思想:

    前面我们以基准值为参考进行了简单排序,现在比基准值小的在其左边,大的在其右边。

    那我们就可以分两组实现左边一组,右边一组就行了,在这里我们用递归来实现。

     2.22第一种方法实现

    1. //hoare法整体实现
    2. void PartSort1D(int* a, int begin, int end)
    3. {
    4. int left = begin;
    5. int right = end;
    6. int key = begin;
    7. int keyi = begin;
    8. if (begin >= end)//如果最多有一个就不用递归了
    9. {
    10. return;
    11. }
    12. while (left < right)
    13. {
    14. while (left < right && a[right] >= a[key])
    15. {
    16. right--;
    17. }
    18. while (left < right && a[left] <= a[key])
    19. {
    20. left++;
    21. }
    22. Swap(&a[left], &a[right]);
    23. }
    24. Swap(&a[left], &a[keyi]);
    25. keyi = left; //把keyi交换到中间
    26. PartSort1D(a, begin, keyi - 1);
    27. PartSort1D(a, keyi + 1, end);
    28. }

    2.23第二种方法实现

    这种只不过是单趟排序再加一个主函数,但是更便捷了。

    1. int PartSort1(int* a, int begin, int end)
    2. {
    3. int left = begin;
    4. int right = end;
    5. int key = begin;
    6. int keyi = begin;
    7. if (begin >= end)//如果最多有一个就不用递归了
    8. {
    9. return;
    10. }
    11. while (left < right)
    12. {
    13. while (left < right && a[right] >= a[key])
    14. {
    15. right--;
    16. }
    17. while (left < right && a[left] <= a[key])
    18. {
    19. left++;
    20. }
    21. Swap(&a[left], &a[right]);
    22. }
    23. Swap(&a[left], &a[keyi]);
    24. return left;
    25. }
    26. //整体法
    27. void QuickSort(int* pa, int begin, int end)
    28. {
    29. assert(pa);
    30. if (begin >= end)
    31. {
    32. return;
    33. }
    34. //这里为单趟实现的方式
    35. int keyi = PartSort1(pa, begin, end);
    36. QuickSort(pa, begin, keyi - 1);
    37. QuickSort(pa, keyi + 1, end);
    38. }

    3.挖坑法实现

    3.1大致思路:

    以最左侧的数为基准数key,此时将key的值保存并将这个位置变成一个坑, 让right左移找小于key的数,找到后将这个数要到刚才的这个坑中,right1位置又形成一个坑,再将left的值移到这个坑中,最后将key移到left,right重叠位置,重复多次。

     3.2挖坑法单趟实现

    1. //挖坑法
    2. int PartSort2(int* a, int begin, int end)
    3. {
    4. int key = a[begin];
    5. int tmp = begin;//坑位
    6. int right = end;
    7. int left = begin;
    8. while (left < right)
    9. {
    10. //当左边小于右边时循环结束
    11. while (left < right && a[right] >= key)
    12. {
    13. right--;
    14. }
    15. Swap(&a[tmp], &a[right]);
    16. tmp = right; //把right位置变成坑位
    17. while (left < right && a[left] <= key)
    18. {
    19. left++;
    20. }
    21. Swap(&a[tmp], &a[left]);
    22. tmp = left;
    23. }
    24. Swap(&key, &a[tmp]);
    25. return tmp;
    26. }

    大致思想和上面的基本一致。

    3.3多趟实现第一种

    思路和hoare法一模一样,以坑位tmp为界限,左边调用一次递归,右边调用一次递归就行。

    1. //挖坑法
    2. void PartSort2D(int* a, int begin, int end)
    3. {
    4. int key = a[begin];
    5. int tmp = begin;//坑位
    6. int right = end;
    7. int left = begin;
    8. while (left < right)
    9. {
    10. //右边找小,填左坑
    11. while (left < right && a[right] >= key)
    12. {
    13. right--;
    14. }
    15. Swap(&a[tmp], &a[right]);
    16. tmp = right;
    17. //左边找大,填右坑
    18. while (left < right && a[left] <= key)
    19. {
    20. left++;
    21. }
    22. Swap(&a[tmp], &a[left]);
    23. tmp = left;
    24. }
    25. Swap(&key, &a[tmp]);
    26. PartSort2D(a, begin,tmp - 1);
    27. PartSort2D(a, tmp + 1, end);
    28. }

    3.4第二种方法实现

    1. //挖坑法
    2. int PartSort2(int* a, int begin, int end)
    3. {
    4. int key = a[begin];
    5. int tmp = begin;//坑位
    6. int right = end;
    7. int left = begin;
    8. while (left < right)
    9. {
    10. //当左边小于右边时循环结束
    11. while (left < right && a[right] >= key)
    12. {
    13. right--;
    14. }
    15. Swap(&a[tmp], &a[right]);
    16. tmp = right; //把right位置变成坑位
    17. while (left < right && a[left] <= key)
    18. {
    19. left++;
    20. }
    21. Swap(&a[tmp], &a[left]);
    22. tmp = left;
    23. }
    24. Swap(&key, &a[tmp]);
    25. return tmp;
    26. }
    27. //整体法
    28. void QuickSort(int* a, int begin, int end)
    29. {
    30. assert(a);
    31. if (begin >= end)
    32. {
    33. return;
    34. }
    35. //这里为单趟实现的方式
    36. int keyi = PartSort2(a, begin, end);
    37. QuickSort(a, begin, keyi - 1);
    38. QuickSort(a, keyi + 1, end);
    39. }

    这里就不过多解释了。

    4.前后指针法

    4.1前后指针思路分析

    一个先行指针cur,一个后行prev,cur先走,当遇见小于key的值时,两者同步,当遇见大于key的值时,cur继续往前走,prev不动,所以prev前面一定是大于key的数,直到cur找到小于key的值时停下,然后交换cur和prev前面那个数.

    4.11那能不能进行单趟实现呢?

      可以,当cur遇见的都是小于key的值时,prev,cur同步,当cur出界限时,prev和key完成交换,单趟结束。

    4.2源码单趟实现

    1. //前后指针法
    2. int PartSort3(int* a, int begin, int end)
    3. {
    4. int key = begin;
    5. int cur = begin + 1;
    6. int prev = begin;
    7. while (cur <= end)
    8. {
    9. if ((a[cur] < a[key]) && (++prev != cur))
    10. {
    11. Swap(&a[cur], &a[prev]);
    12. }
    13. cur++;
    14. }
    15. Swap(&a[prev], &a[key]);
    16. return prev;
    17. }

    4.3多趟实现

    1. //前后指针法
    2. void PartSort3D(int* a, int begin, int end)
    3. {
    4. int key = begin;
    5. int cur = begin + 1;
    6. int prev = begin;
    7. while (cur <= end)
    8. {
    9. if ((a[cur] < a[key]) && (++prev != cur))
    10. //交换prev的前一个值
    11. {
    12. Swap(&a[cur], &a[prev]);
    13. }
    14. cur++;
    15. }
    16. Swap(&a[prev], &a[key]);
    17. QuickSort(a, begin, prev - 1);
    18. QuickSort(a, key + 1, end);
    19. }

    非递归实现下次在更新吧。

  • 相关阅读:
    API与C++中的API
    教你如何通过内网穿透轻松实现PL/SQL远程连接Oracle数据库【内网穿透】
    全国省市县 经纬度的 json数据(提供原文件),写Java代码,入库(提供代码)
    剑指Offer 33.二叉搜索树的后序遍历序列
    SSM框架基于h5的校园兼职招聘系统的设计与实现源码+论文三稿+ppt+查重报告(包远程安装,已降重)
    uniapp实现点击选项跳转到应用商店进行下载
    RabbitMQ原理(二):SpringAMQP编程
    python flask_restful “message“: “Failed to decode JSON object: None“
    浅谈AI人体姿态识别技术的先进性及安防视频监控应用场景
    小程序之自定义组件 结合案例
  • 原文地址:https://blog.csdn.net/bit_jie/article/details/126110492