• 归并排序


    归并排序分治法的一个典型且基本的应用。它的基本思想是:将对N个对象的问题转换成两次对N/2个对象的问题。归并排序减少了数据的比较次数,转而增加了数据的移动次数,使得排序速度相对较快。该算法的递推公式T(N) = 2T(N/2) + O(N)表明其算法复杂度上限为O(NlogN)。下面是其C++代码:

     1 #include<cstring>
     2 #include<cstdio>
     3 #include<iostream>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 int innersort(int* A,int left,int right,int* CPY)
     8 {//[left,mid]and[mid+1,right];
     9     if(right==left)return 0;
    10     int mid=(left+right)/2;
    11     int i=left,k=mid+1;
    12     int cur=left;
    13     while(i!=mid+1&&k!=right+1)
    14     {
    15         if(A[i]>A[k])CPY[cur++]=A[k++];
    16         else CPY[cur++]=A[i++];
    17     }//一定有一侧的数据会最先完成排序
    18     while(i!=mid+1)CPY[cur++]=A[i++];
    19     while(k!=right+1)CPY[cur++]=A[k++];//对剩余的一侧数据一次添加进入CPY数组即可
    20     memcpy(A+left,CPY+left,sizeof(int)*(right-left+1));//复制回到原数组
    21     return 0;
    22 }
    23 
    24 int merger(int* A,int left,int right,int* CPY)
    25 {//[left,mid]and[mid+1,right];
    26     if(left<right)
    27     {
    28         int center=(left+right)/2;
    29         //中点的归属需要特别考虑
    30         merger(A,left,center,CPY);
    31         merger(A,center+1,right,CPY);
    32         innersort(A,left,right,CPY);
    33     }
    34     return 0;
    35 }
    36 
    37 int mergesort(int* A,int* Aend)
    38 {//[left,right);
    39     int right=Aend-A;
    40     int* temp=new int[right+1];//临时数组开得大了一点
    41     merger(A,0,right-1,temp);
    42     //数组的边界问题与分割方案问题一直是关注点
    43     delete[] temp;
    44     return 0;
    45 }
    46 
    47 int main()
    48 {
    49     int aim[]={3,5,2,6,7,3,2,6,2,6,3,7,3,2};
    50     mergesort(aim,aim+14);
    51     for(int i=0;i<14;i++)
    52     {
    53         printf("%d ",aim[i]);
    54     }
    55     printf("
    ");
    56     return 0;
    57 }

    归并排序中的比较次数是所有排序中最少的。原因是,它一开始是不断地划分,比较只发生在合并各个有序的子数组时。

    因此,JAVA的泛型排序类库中实现的就是归并排序。因为:对于JAVA而言,比较两个对象的操作代价是很大的(根据Comparable接口的compareTo方法进行比较),而移动两个对象,其实质移动的是引用,代价比较小。(排序本质上是两种操作:比较操作和移动操作)

    归并排序算法分析

     归并排序算法有两个基本的操作,一个是,也就是把原数组划分成两个子数组的过程。另一个是,它将两个有序数组合并成一个更大的有序数组。

    它将数组平均分成两部分: center = (left + right)/2,当数组分得足够小时---数组中只有一个元素时,只有一个元素的数组自然而然地就可以视为是有序的,此时就可以进行合并操作了。因此,上面讲的合并两个有序的子数组,是从 只有一个元素 的两个子数组开始合并的。

    合并后的元素个数:从 1-->2-->4-->8......

    比如初始数组:[24,13,26,1,2,27,38,15]

    ①分成了两个大小相等的子数组:[24,13,26,1]    [2,27,38,15]

    ②再划分成了四个大小相等的子数组:[24,13]   [26,1]    [2,27]    [38,15]

    ③此时,left < right 还是成立,再分:[24]   [13]   [26]    [1]    [2]     [27]    [38]   [15]

    此时,有8个小数组,每个数组都可以视为有序的数组了!!!,每个数组中的left == right,从递归中返回,故开始执行合并:

    merge([24],[13]) 得到 [13,24]

    merge([26],[1]) 得到[1,26]

    .....

    .....

    最终得到 有序数组。

    下面提供两个归并排序的模板:

     1 int mergesort(int *aim,int x,int y,int *temp)
     2 {//aim是原数组,temp是临时数组
     3     int lenth=y-x;
     4     if(lenth==1)return 0;
     5     //
     6     int mid=x+lenth/2;
     7     mergesort(aim,x,mid,temp);
     8     mergesort(aim,mid,y,temp);
     9     //
    10     int p=x,q=mid,i=x;
    11     while(p<mid||q<y)
    12     {
    13         if(p>=mid||(q<y&&aim[q]<aim[p]))temp[i++]=aim[q++];
    14         else temp[i++]=aim[p++];
    15     }
    16     memcpy(&aim[x],&temp[x],sizeof(int)*lenth);
    17     return 0;
    18 }

    第二个:

     1 int mergesort(int *aim,int x,int y)
     2 {
     3     if(y-x==1)return 0;
     4     //
     5     int lenth=y-x;
     6     int mid=x+lenth/2;
     7     mergesort(aim,x,mid);
     8     mergesort(aim,mid,y);
     9     //
    10     int temp[lenth];//开辟了临时数组,这样会变慢
    11     int cur=0;
    12     int *q=&aim[x];
    13     int *h=&aim[mid];
    14     while(q!=&aim[mid]&&h!=&aim[y])
    15     {
    16         if(*q>*h){temp[cur++]=*h;h++;}
    17         else {temp[cur++]=*q;q++;}
    18     }
    19     while(q!=&aim[mid]){temp[cur++]=*q;q++;}
    20     while(h!=&aim[y]){temp[cur++]=*h;h++;}
    21     memcpy(&aim[x],temp,sizeof(int)*lenth);
    22     return 0;
    23 }

    OK

  • 相关阅读:
    [转]oracle in 多个字段
    [转][MVC4]ASP.NET MVC4+EF5(Lambda/Linq)读取数据
    SQL Server “复制”表结构,创建_Log表及触发器
    [转]WordPress主题开发:主题初始化
    struts2请求过程源码分析
    java调优
    websocket之四:WebSocket 的鉴权授权方案
    高可用性及容灾的几个衡量指标
    Struts2返回JSON对象的方法总结
    java websocket @ServerEndpoint注解说明
  • 原文地址:https://www.cnblogs.com/savennist/p/12310920.html
Copyright © 2020-2023  润新知