当前位置:   article > 正文

手撕七大排序(三)

手撕七大排序(三)

快速排序(一次排序)

一. 基本思想

当然这里也是目前为止我们能够接触到的最快的算法

图形表示如下

 

我们将最左边的值称为 “key 值”

这里我们从右边开始 依次往左遍历 如果找到小于key下标数 就交换它们的值

并且将key的下标赋值给right

之后我们从左边开始 依次往右遍历 如果找到大于key下标的数 就交换它们的值

并且将key的下标赋值给left

我们想想看 什么时候结束呢?

当然是left < right 的时候

二. 代码表示

我们这里有代码表示如下

  1. int PartSort1(int* a, int left, int right)
  2. {
  3. //三数取中
  4. int midi = GetmidNumi(a, left, right);
  5. if (midi != left)
  6. Swap(&a[left], &a[midi]);
  7. //单趟
  8. int keyi = left;
  9. while (left < right)
  10. {
  11. //右边先走 找比key
  12. while (left < right && a[right] >= a[keyi])
  13. {
  14. right--;
  15. }
  16. //右边找到小的 左边走 找key
  17. while (left < right && a[left] <= a[keyi])
  18. {
  19. left++;
  20. }
  21. Swap(&a[left], &a[right]);
  22. }
  23. //leftright相遇后 交换keyi的值和相遇点的值
  24. Swap(&a[keyi], &a[left]);
  25. //更新坐标
  26. keyi = left;
  27. return keyi;
  28. }

我们来看看结果是什么样子的

快速排序(整体排序)

一. 基本思路

既然我们每次可以将整个数组可以分成两个部分

我们可以将数组的左边和右边继续进行快速排序

这里我们进行递归

二. 递归思路

既然我们已经决定了要进行递归了

那么我们想想看极限条件是什么?

是不是要左值大于等于右值的时候 只剩下一个值了 是不是肯定有序了

所以说有极限条件如下

  1. if (left >= right)
  2. {
  3. return;
  4. }

 那么我们接下来就可以考虑左右两边怎么排了

我们来看看我们的数组

是不是从左到右分成三个部分

分别是

left~keyi-1;
keyi;
keyi+1~right;

所以说我们就可以有以下代码

  1. //区间 [begin,keyi-1] keyi [keyi+1,end]
  2. QuickSort1(a,begin, keyi - 1);
  3. QuickSort1(a, keyi + 1, end);

之后我们来试试 整体排序的效果咋样

可以完成

优化

我们假设 排序的数组就是一个有序的

那这样是不是我们的算法就变得很复杂了啊

到这里的时间复杂度就变成了O(N^2)

那么针对有序数组的这个问题 我们能不能做出一个优化呢?

答案是有的

那就是三数取中

 

我们找到最左边 左右边 还有中间三个数中的中间值

然后让这个值和left交换

之后再进行排序 是不是就能变成很优了啊

那么我们这里再来写个函数 三数取中

  1. int GetmidNumi(int* a, int left, int right)
  2. {
  3. int mid = (left + right) / 2;
  4. if (a[left] < a[mid])
  5. {
  6. if (a[mid] < a[right])
  7. {
  8. return mid;
  9. }
  10. else if(a[left]>a[right])
  11. {
  12. return left;
  13. }
  14. else
  15. {
  16. return right;
  17. }
  18. }
  19. else//a[left]>a[mid]
  20. {
  21. if (a[left] < a[right])
  22. {
  23. return left;
  24. }
  25. else if (a[right] < a[mid])
  26. {
  27. return mid;
  28. }
  29. else
  30. {
  31. return right;
  32. }
  33. }
  34. }

之后再来写进函数里面

  1. void QuickSort1(int* a, int left,int right)
  2. {
  3. //返回条件
  4. if (left >= right)
  5. {
  6. return;
  7. }
  8. //有序的时候 时间复杂度O(N^2)优化
  9. //随机选key
  10. /*int randi = left + (rand() % (right - left));
  11. Swap(&a[left], &a[randi]);*/
  12. //三数取中
  13. int midi = GetmidNumi(a, left, right);
  14. if (midi != left)
  15. Swap(&a[left], &a[midi]);
  16. int begin = left; int end = right;
  17. //单趟
  18. int keyi = left;
  19. while (left < right)
  20. {
  21. //右边先走 找比key
  22. while (left < right && a[right] >= a[keyi])
  23. {
  24. right--;
  25. }
  26. //右边找到小的 左边走 找key
  27. while (left < right && a[left] <= a[keyi])
  28. {
  29. left++;
  30. }
  31. Swap(&a[left], &a[right]);
  32. }
  33. //leftright相遇后 交换keyi的值和相遇点的值
  34. Swap(&a[keyi], &a[left]);
  35. //更新坐标
  36. keyi = left;
  37. //递归
  38. //区间 [begin,keyi-1] keyi [keyi+1,end]
  39. QuickSort1(a,begin, keyi - 1);
  40. QuickSort1(a, keyi + 1, end);
  41. }

我们来看看运行结果

可以完美运行

双指针法实现一趟快排 

我们这里首先设置两个指针

一个prev 指向第一个元素 也就是key值

一个cur指向最后的元素

类似这样子

比如说 cur走到了2 然后2小于key值

这个时候pre就得++ 然后交换cur和pre指向的值

当cur走到7 9 下面的时候就直接++ 不做任何操作

如果说cur的坐标大于 数组的元素-1的时候结束循环

这个时候我们再将prev和key值交换一下就可以了

最后结果表示如下

  1. //前后指针法
  2. int PartSort3(int* a, int left, int right)
  3. {
  4. //三数取中
  5. int midi = GetmidNumi(a, left, right);
  6. if (midi != left)
  7. Swap(&a[left], &a[midi]);
  8. int keyi = left;
  9. int prev = left;
  10. int cur = left + 1;
  11. while (cur <= right)
  12. {
  13. if (a[cur] < a[keyi] && ++prev != cur)
  14. {
  15. Swap(&a[cur], &a[prev]);
  16. }
  17. ++cur;
  18. }
  19. Swap(&a[keyi], &a[prev]);
  20. keyi = prev;
  21. return keyi;
  22. }
  23. void QuickSort(int* a, int left, int right)
  24. {
  25. if (left >= right)
  26. {
  27. return;
  28. }
  29. //递归
  30. int keyi = PartSort1(a, left, right);
  31. QuickSort(a, left, keyi - 1);
  32. QuickSort(a, keyi + 1, right - 1);
  33. }

  以上便是本文所有内容,如有错误请各位大佬不吝赐教,感谢留言

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/828531?site
推荐阅读
相关标签
  

闽ICP备14008679号