归并排序(merge_sort)

  最近在学习算法,学到归并排序这里确实有些让人迷惑,主要是一直没能理解递归的具体运行方式。

  归并排序是分治法的典型应用,将一整个大问题“分”,然后“治”。对于数组排序来说,“分”的过程就是将整个数组分成单个数字,“治”的过程就是将这些单个数字排序合并。

  首先我们应该思考如何合并的过程,在归并排序中,所有的子序列都是有序的,这么来说就好办了:

复制代码
 1 void merge(int[] A, int left, int mid, int right){
 2         //两个数组的长度
 3         int n1 = mid - left + 1;
 4         int n2 = right - mid;
 5 
 6         //复制两个子数组
 7         int L[] = new int[n1 + 1];
 8         int R[] = new int[n2 + 1];
 9         for (int i = 0;i < n1;i++)
10             L[i] = A[left + i];
11         for (int i = 0;i < n1;i++)
12             R[i] = A[mid + i + 1];
13 
14         //设置哨兵
15         L[n1] = Integer.MAX_VALUE;
16         R[n2] = Integer.MAX_VALUE;
17 
18         //排序过程
19         int i = 0;
20         int j = 0;
21         for (int k = left; k <= right; k++){
22             if(L[i]<=R[j]){
23                 A[k] = L[i];
24                 i++;
25             }else {
26                 A[k] = R[j];
27                 j++;
28             }
29         }
30     }
复制代码

  上面的代码里,是将数组A的两个区间合并排序。既然两个数组都有序,那么从头开始,依次比较大小,就能将两个数组合并成一个大的有序的数组。需要注意的是这里在数组最后我们添加了一个哨兵元素,这个元素可以帮我们简化代码,同时在执行时不需要判断数组是否越界。

  合并过程既然已经解决,剩下的就是“分”的问题。这里的分有些像二分查找。

复制代码
    /*
    *归并排序,分治的思想,先分,再治
     */
    void merge_sort(int[] A,int p,int r){
        if(p < r){
            int q = (p + r)/2;
            merge_sort(A,p,q);
            merge_sort(A,q + 1,r);
            merge(A,p,q,r);
        }
    }
复制代码

  我觉得理解递归需要逐步运行,一步一步地看递归运行的每一步过程,这样才能真正理解吸收

posted @   小事不要慌  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示