当前位置:   article > 正文

归并排序 图解 递归 + 非递归 + 笔记

归并排序 图解 递归 + 非递归 + 笔记

前置知识:讲解019-算法笔试中处理输入和输出,讲解020-递归和master公式

  • (1)左部分排好序,右部分排好序,利用merge过程让左右整体有序
  • (2)merge过程:谁小拷贝谁,直到左右两部分所有的数字耗尽
  • (3)递归实现和非递归实现
  • (4)时间复杂度O(n*logn)
  • (5)需要辅助数组,所以额外空间复杂度O(n)
  • (6)归并排序为什么比O(n^2)的排序快?因为比较行为没有浪费!
  • (7)利用归并排序的便利性可以解决很多问题,例如归并分治

注意:有些资料说可以用原地归并排序,把额外空间复杂度变成O(1),不要浪费时间去学。因为原地归并排序确实可以省空间,但是会把复杂度变成O(n^2)

  • 对这个数组arr=[6,4,2,3,9,4] ,进行归并排序 

  1. 归并排序
  2. 递:左,有序
  3. 递:右,有序
  4. 整合(非):左,右

呵呵哒的瞎想(可以不看):f(0,0)是6,f(1,1)是4,只有获得了这两个数值,才能合并成f(0,1),也就是[4,6]。而这个过程正好是后序遍历。左右中

  1. // 递归方法
  2. void mergeSort(vector<int>& arr, int left, int right) {
  3. if (left == right) return;
  4. int mid = (left + right) / 2;
  5. mergeSort(arr, left, mid); // 左
  6. mergeSort(arr, mid + 1, right); // 右
  7. merge(arr, left, mid, right); // 中
  8. }
  • 挑其中一步来演示: 把[2,4,6]和[3,4,9]合并(merge)

最后再刷回原数组 

  1. void merge(vector<int>& arr,int left, int mid, int right) {
  2. int n = right - left + 1;
  3. vector<int> help(n,0);
  4. int i = 0;
  5. int a = left;
  6. int b = mid + 1;
  7. while (a <= mid && b <= right) {
  8. help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
  9. }
  10. // 左侧指针,右侧指针,必有一个越界,另一个不越界
  11. while (a <= mid) {
  12. help[i++] = arr[a++];
  13. }
  14. while (b <= right) {
  15. help[i++] = arr[b++];
  16. }
  17. for (i = 0; i <n; i++) { // 把 help 里面的数据重新刷回到原数组arr
  18. arr[i+left] = help[i];
  19. }
  20. }

(1)归并排序递归版

  1. // 递归方法
  2. void mergeSort(vector<int>& arr, int left, int right) {
  3. if (left == right) return;
  4. int mid = (left + right) / 2;
  5. mergeSort(arr, left, mid);
  6. mergeSort(arr, mid + 1, right);
  7. merge(arr, left, mid, right);
  8. }

(2)归并排序非递归版

  1. // 归并排序非递归版
  2. // 时间复杂度:O(n * logn)
  3. // 空间复杂度:O(n)
  4. void mergeSort2(vector<int>& arr) {
  5. int n = arr.size();
  6. // 一共发生O(logn)次
  7. for (int left, mid, right, step = 1; step < n; step <<= 1) {
  8. // 内部分组merge,时间复杂度:O(n)
  9. left = 0;
  10. while (left < n) {
  11. mid = left + step - 1;
  12. if (mid + 1 >= n) {
  13. // 已经没有右侧了
  14. break;
  15. }
  16. // 有右侧,求右侧的右边界
  17. right = min(left + (step << 1) - 1, n - 1);
  18. // left ... mid mid+1 ... right
  19. // left ... mid mid+1 ... right
  20. // left ... mid mid+1 ... right
  21. merge(arr,left, mid, right);
  22. left = right + 1;
  23. }
  24. }
  25. }

完整代码:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. void merge(vector<int>& arr,int left, int mid, int right) {
  5. int n = right - left + 1;
  6. vector<int> help(n,0);
  7. int i = 0;
  8. int a = left;
  9. int b = mid + 1;
  10. while (a <= mid && b <= right) {
  11. help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
  12. }
  13. // 左侧指针,右侧指针,必有一个越界,另一个不越界
  14. while (a <= mid) {
  15. help[i++] = arr[a++];
  16. }
  17. while (b <= right) {
  18. help[i++] = arr[b++];
  19. }
  20. for (i = 0; i <n; i++) { // 把 help 里面的数据重新刷回到原数组arr
  21. arr[i+left] = help[i];
  22. }
  23. }
  24. /*
  25. 归并排序递归版
  26. 假设left...right一共 n 个数
  27. T(n) = 2 * T(n/2) + O(n)
  28. a = 2,b = 2,c = 1
  29. 根据master公式,时间复杂度:O(n * logn)
  30. 空间复杂度:O(n)
  31. */
  32. // 递归方法
  33. void mergeSort(vector<int>& arr, int left, int right) {
  34. if (left == right) return;
  35. int mid = (left + right) / 2;
  36. mergeSort(arr, left, mid);
  37. mergeSort(arr, mid + 1, right);
  38. merge(arr, left, mid, right);
  39. }
  40. // 归并排序非递归版
  41. // 时间复杂度:O(n * logn)
  42. // 空间复杂度:O(n)
  43. void mergeSort2(vector<int>& arr) {
  44. int n = arr.size();
  45. // 一共发生O(logn)次
  46. for (int left, mid, right, step = 1; step < n; step <<= 1) {
  47. // 内部分组merge,时间复杂度:O(n)
  48. left = 0;
  49. while (left < n) {
  50. mid = left + step - 1;
  51. if (mid + 1 >= n) {
  52. // 已经没有右侧了
  53. break;
  54. }
  55. // 有右侧,求右侧的右边界
  56. right = min(left + (step << 1) - 1, n - 1);
  57. // left ... mid mid+1 ... right
  58. // left ... mid mid+1 ... right
  59. // left ... mid mid+1 ... right
  60. merge(arr,left, mid, right);
  61. left = right + 1;
  62. }
  63. }
  64. }
  65. int main() {
  66. vector<int> arr = { 6,4,2,3,9,4};
  67. int n = arr.size();
  68. mergeSort(arr, 0, n - 1);
  69. //mergeSort2(arr);
  70. for (int i = 0; i < n; i++) {
  71. cout << " " << arr[i] << " " << endl;
  72. }
  73. system("pause");
  74. return 0;
  75. }

完整图:

参考和推荐视频:

算法讲解021【必备】归并排序_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1wu411p7r7/?spm_id_from=333.999.list.card_archive.click&vd_source=a934d7fc6f47698a29dac90a922ba5a3

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

闽ICP备14008679号