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


    前置知识:讲解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 // 把 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
    2. #include
    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 // 把 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

  • 相关阅读:
    (附源码)springboot通用办事流程管理软件 毕业设计 211819
    kafka基本原理以及快速实战
    psensor 的手势功能
    OpenFeign动态代理、源码分析
    【MySQL】如何使用SQL语句获取表结构和获取全部表名
    红队隧道应用篇之NetCat使用(十一)
    一文解读 NFT 零版税
    systrace/perfetto抓取方式分享
    专业课-代码题记录
    指针笔试题~走近大厂
  • 原文地址:https://blog.csdn.net/weixin_41987016/article/details/134338789