• 一起学数据结构(12)——归并排序的实现


    1. 归并排序原理:

    归并排序的大概原理如下图所示:

            从图中可以看出,归并排序的整体思路就是把已给数组不断分成左右两个区间,当这个区间中的数据数量到达一定数值时,便返回去进行排序,整体的结构类似二叉树的结构,因此,对于归并排序同样可以利用递归进行实现。

           对于递归实现归并排序,首先需要实现的第一步便是如何区分左右区间,在快速排序中,虽然在递归时依然同样需要根据一个值来区分左右区间,但是用于区分左右区间的值是在左右两边遍历数组时自动选出来的,对于归并排序,通过观察可以发现,归并排序的左右区间是通过数组下标的中间值进行区分的,为了方便表示,将这个中间值命名为mid,例如,数组在进行第一次区分左右区间时,左区间的范围是[0,3],右区间的范围是[4,7]通过计算不难得到mid = 3,所以,对于数组左右区间的划分,可以通过midbegin(数组下标起始),end(数组下标末位来划分)即

                                                              左区间范围:[0,mid]

                                                              右区间范围:[mid+1,end]

           同时,在图中当区间中的数值数量为2后,下一步直接进行排序,此处图中省略了区间分为两个区间数值数量为1的两个区间的过程,这是因为,在区间中的数值数量< 2时,便停止划分区间

    所以,对于区间划分这部分的递归,可以用代码表示为:

    1. //归并排序
    2. void _MergeSort(int* a, int begin, int end)
    3. {
    4. if (begin >= end)
    5. {
    6. return;
    7. }
    8. int mid = (begin + end) / 2;
    9. MergeSort(a, begin, mid);
    10. MergeSort(a,mid + 1, end);
    11. }

    在区间划分结束后,就需要对数组进行排序。这里需要注意,在进行排序时,不能直接在原本已有的数组进行排序,为了解决这个问题,本文选择独立开辟一块空间用于排序,当一部分区间在这部分空间排序完成后,便将这部分内容返回到原数组,开辟空间的过程如下:

    1. void MergeSort(int* a, int begin, int end)
    2. {
    3. int* tmp = (int*)malloc(sizeof(int) * (end - begin + 1));
    4. if (tmp == NULL)
    5. {
    6. perror("malloc fail");
    7. }
    8. _MergeSort(a, tmp, begin, end);
    9. }

    因为开辟的空间需要在上面的函数中使用,所以对于函数的定义需要更改为上图中的格式。

    对于如何排序,文章给出下面的方法:

    对于一个区间,定义四个变量,分别为:begin1,end1,begin2,end2,具体使用方法如下:

    begin1 = begin,end1 = mid,begin2 = mid+1,end2 = end,具体使用方法如下方的代码所示:

    1. //归并排序
    2. void _MergeSort(int* a,int* tmp, int begin, int end)
    3. {
    4. if (begin >= end)
    5. {
    6. return;
    7. }
    8. int mid = (begin + end) / 2;
    9. _MergeSort(a,tmp, begin, mid);
    10. _MergeSort(a,tmp,mid + 1, end);
    11. int begin1 = begin, end1 = mid;
    12. int begin2 = mid + 1, end2 = end;
    13. int index = begin;
    14. while (begin1 <= end1 && begin2 <= end2)
    15. {
    16. if (a[begin1] < a[begin2])
    17. {
    18. tmp[index++] = a[begin1++];
    19. }
    20. else
    21. {
    22. tmp[index++] = a[begin2++];
    23. }
    24. }
    25. while (begin1 <= end1)
    26. {
    27. tmp[index++] = a[begin1++];
    28. }
    29. while (begin2 <= end2)
    30. {
    31. tmp[index++] = a[begin2++];
    32. }
    33. memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
    34. }

    为了方便解释代码内容,给出下面的图像:

     首先对左右区间进行区分,期间各个区间的begin1,end1,begin2,end2,如图所示,当区间数据数量< 2时,停止区分区间进行排序,例如对[10,6]这个区间,如果a[begin1] < a[begin2],则让小的哪个值插入到tmp,此时tmp中的内容如下图所示:

    向原数组拷贝数值后,原数组左区间数值如下:

    [10,6]区间遍历完成后,再遍历[7,1]区间,由于begin 的不同,再数据调整完拷贝到tmp后,tmp数组内容为:

     

    随后再向原数组中拷贝,原数组内容为

     

    对于其他的序列,依旧按照此规律,此部分不再叙述。

    测试函数如下:
     

    1. void TestMergeSort()
    2. {
    3. int i[] = { 10,6,7,1,3,9,4,2 };
    4. int size = sizeof(i) / sizeof(int);
    5. MergeSort(i, 0, size - 1);
    6. printf("归并排序:");
    7. ArrayPrint(i, size);
    8. }

    运行结果如下:

     

  • 相关阅读:
    Spring framework day 03:Spring 整合 事务管理
    基因数据平台
    FF14 XIVLauncher 启动器与 Dalamud 卫月框架使用教程
    华为OD 机智的外卖员(100分)【java】A卷+B卷
    合合信息大模型加速器亮相WAIC大会:文档解析与文本识别新突破
    武汉ITSS运维服务认证价值
    Java统计指定目录下文件夹数量和内部文件的数量并导出
    从风险评估到应急救援,实景三维为抗震减灾提供精细化决策依据
    nginx基础篇
    仿真1. 什么是仿真系统
  • 原文地址:https://blog.csdn.net/2301_76836325/article/details/134021177