• 算法复习周------递归之“合并排序”


    算法的考试周来到了,从今天开始我就开始了算法的复习准备。。。我准备从递归开始依次是动态规划、贪心、回溯。这几章的内容其实挺乱的,但是总结下来会有所收获。也希望能给看blog的人一些收获。付出总有收获的嘛。。。好了闲话少说,这里就开始第一个算法

    算法:递归——合并排序


    算法描述:
    作为一个排序算法,它是将待排列的元素分成大小大致相同的两个子集合,并分别对两个子集合排序,然后将排好的子集合合并。相当于把大问题分成若干个小问题,分别处理后然后整合起来。

    这里放一个图便于理解:。在这个图中,我们可以看到我们的例子是:8 4 5 7 1 3 6 2 如果我们要对这个数进行排列的话,我们就要分两个步骤去解决这个问题。①将大问题分成很多小问题   ②将小问题处理后合并成大问题

    在上述例子中,我们将问题分为了84  57  13  62 这四组,然后对这四组里面的数字排序  Ⅰ:48  57  13   26  ——>  Ⅱ:将最小的问题合并成4578    1326 两个问题,然后合并之后在内部排序(因为45  78这两组数字是有一定规律的,所以排序过程就不用遍历所有数字排序,这也是为什么用合并排序快速的地方----**后面细讲**),然后将这两组数字内部排序为 4578  1236 ——>  Ⅲ:之后将这个两个不完善的两个子序列在合并、合并时仍排序。最终我们得到最后的答案。

    在这里我要圈出来合并排序的关键点:①算法处理问题时如何将问题由大分小进行递归  ②小问题处理完成后如何在合并成大问题时将两个子序列排序

    这里我贴出来第一个关键点的代码(如何“分”):

     private static void sort(int[] arr,int left,int right,int []temp){
            
                int mid = (left+right)/2;
                sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
                sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
                merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
            
        }

    在代码里,我们传入arr[]待排序数组,传入left(初始的时候是0),right(初始的时候是数组长度-1),而temp[]是我们用到的中间数组(先不用管它)。

    这里取arr数组的中间的数作为支点,然后将大问题从中间分开,依次交给两个部分处理。而小问题中又将问题分成小小问题。。。。(类似于分权制度,都不愿意干活,就都分给下属。。)

    之后我们来看如何“合”的问题。

    这里我放上去一个图片便于清晰理解:

    在这里我就要接受上面提到的合并中巧妙的思想了:大家根据图片会发现:我在合并小问题的时候建立了两个指针,开始的时候分别指向两个子问题的开始端,例如:1与4比较,1小。所以将1放到temp中的第一个。之后红色块的指针后移动一位,比较2与4,2更小然后把2放到temp中。。。经过了好几次后直到右边的6放到temp中(此时右侧没有数了,所以支教把绿色块全部放进去就好),这就是合并的过程。这样就是为什么代码排序效率更高的原因。

    这里贴上代码:

    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
            int i = left;//左序列指针
            int j = mid+1;//右序列指针
            int t = 0;//临时数组指针
            while (i<=mid && j<=right){
                if(arr[i]<=arr[j]){
                    temp[t++] = arr[i++];
                }else {
                    temp[t++] = arr[j++];
                }
            }
            while(i<=mid){//将左边剩余元素填充进temp中
                temp[t++] = arr[i++];
            }
            while(j<=right){//将右序列剩余元素填充进temp中
                temp[t++] = arr[j++];
            }
            t = 0;
            //将temp中的元素全部拷贝到原数组中
            while(left <= right){
                arr[left++] = temp[t++];
            }
        }
    }

    PS:最后将temp临时数组中的数放到arr中。

    时间复杂度:  在这个问题中,时间复杂度可以递推出来:

    由此我们知道,合并排序的时间复杂度是 O(nlogn。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

    (这里面很多图片来自老师的讲义和链接 https://www.cnblogs.com/chengxiao/p/6194356.html),大家也可以去看连接中所讲的,这里我没有写代码,所以需要代码的同学可以so一下。

    ——————————————————————————————Made By  Pinging

  • 相关阅读:
    Grails入门教程(二)
    为脚本语言平反JavaScript篇(2)
    【CEO来信】李开复:创新工场我的新公司
    api测试常用测试点
    04 jmeter线程介绍及脚本编写
    02 改变jmeter工具GUI永久使用中文方法
    Mac配置hosts文件
    03 GUI界面的错误日志查看及清除
    页面存在多个url,使用jmeter进行遍历操作
    2.0数据之独立存储(Isolated Storage)
  • 原文地址:https://www.cnblogs.com/Pinging/p/7873547.html
Copyright © 2020-2023  润新知