合并排序算法

来源:互联网 发布:廖雪峰python 编辑:程序博客网 时间:2024/06/04 18:16

算法思想

合并排序算法是用分治策略实现对n个元素进行排序的算法。其基本思想是:将待排序元素分成大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。合并算法可递归描述如下:

void MergeSort(int a[], int left, int right){    if (left < right)    { //至少还有两个元素        int mid = (left + right) / 2;   //取中点        MergeSort(a, left, mid);        MergeSort(a, mid+1, right);        Merge(a, b, left, mid, right);  //合并到数组b        Copy(a, b, left, right);        //复制回数组a    }}

其中,算法Merge合并两个排好序的数组段到一个新的数组b中,然后由Copy将合并后的数组段再复制回数组a中。Merge和Copy都可在O(n)时间内完成,因此合并排序算法对n个元素进行排序,在最坏情况下所需的计算时间T(n)满足:

T(n)={O(1)2T(n/2)+O(n)n <= 1n > 1

解此递归方程可得T(n) = O(nlgn).由于排序问题的计算时间下界为 Ω(nlgn),所以合并排序算法是一个渐进最优算法。

实现代码

#include <stdio.h>#include <stdlib.h>void MergeSort(int a[], int left, int right);void Merge(int a[], int b[], int l, int m, int r);void Copy(int a[], int b[], int s, int e);int main(){    int i, n;    printf("please enter array size:");    scanf("%d", &n);    int a[n];    printf("please enter number:");    for (i = 0; i < n; i++)        scanf("%d", &a[i]);    printf("array:\n");    for (i = 0; i < n; ++i)        printf("%4d", a[i]);    printf("\n");    MergeSort(a, 0, n-1);    printf("sort array:\n");    for (i = 0; i < n; ++i)        printf("%4d", a[i]);    printf("\n");    return 0;}void MergeSort(int a[], int left, int right){ //合并排序    if (left < right)    { //至少还有两个元素        int n = right - left + 1;       //b数组大小        int b[n];   //下标从0开始        int mid = (left + right) / 2;   //取中点        MergeSort(a, left, mid);        //排序左边部分        MergeSort(a, mid + 1, right);   //排序右边部分        Merge(a, b, left, mid, right);  //合并到数组b        Copy(a, b, left, right);        //复制回数组a    }}void Merge(int a[], int b[], int l, int m, int r){ //把a数组排好序的左右两部分合并到b数组中    int i, j, k;    i = l;      //i指向a左边起始下标    j = m + 1;  //j指向a右边起始下标    k = 0;      //k指向b数组起始下标    while (i <= m && j <= r)    {        if (a[i] < a[j])            b[k++] = a[i++];        else            b[k++] = a[j++];    }    /*把数组剩余的部分复制到b中*/    while (i <= m)        b[k++] = a[i++];    while (j <= r)        b[k++] = a[j++];}void Copy(int a[], int b[], int s, int e){ //b数组复制到a数组    int i, j;    for (i = s, j= 0; i <= e; ++i, ++j)        a[i] = b[j];}

算法改进

对于算法MergeSort,还可以从分支策略的机制入手,容易消除算法中的递归。事实上,算法MergeSort的递归过程只是将待排序集合一分为二,直至待排序集合只剩下一个元素为止,然后不断合并两个排好序的数组段。按此机制,可以首先将数组a中相邻元素两两配对。用合并算法将他们排序,构成n/2组长度为2的排好序的子数组段,然后将他们排序成长度为4的排好序的子数组段,如此继续下去,直至整个数组排好序。
按此思想,消去递归后的合并排序算法可描述如下:

void MergeSort(int a[], int n){    int b[n];    int s = 1;    while (s < n)    {        MergeSort(a, b, s, n);  //合并到数组b        s += s;        MergeSort(b, a, s, n);  //合并到数组a        s += s;    }}

其中MergePass用于合并排好序的相邻数组段。具体的合并算法由Merge来实现。对于MergePass函数,合并排好序的相邻数组段。到最后,可能剩下元素不足2s个,对于大于s个元素和小于等于s个元素分别采用不同的处理方式。具体见函数定义。
对于函数Merge,与之前大致相同,只是数组b下标从l开始,而之前的Merge函数,下标从0开始。

改进后的代码

/***合并排序——非递归版本*/#include <stdio.h>#include <stdlib.h>void MergeSort(int a[], int n);void MergePass(int a[], int b[], int s, int n);void Merge(int a[], int b[], int l, int m, int r);int main(){    int i, n;    printf("please enter array size:");    scanf("%d", &n);    int a[n];    printf("please enter number:");    for (i = 0; i < n; i++)        scanf("%d", &a[i]);    printf("array:\n");    for (i = 0; i < n; ++i)        printf("%4d", a[i]);    printf("\n");    MergeSort(a, n);    printf("sort array:\n");    for (i = 0; i < n; ++i)        printf("%4d", a[i]);    printf("\n");    return 0;}void MergeSort(int a[], int n){ //合并排序    int b[n];    int s = 1;    while (s < n)    {        MergePass(a, b, s, n);  //合并到数组b        s += s;        MergePass(b, a, s, n);  //合并到数组a        s += s;    }}void MergePass(int a[], int b[], int s, int n){    int i = 0, j;    while (i <= n - 2 * s)    { //max(i) 到 n-1的闭区间大小为2s        Merge(a, b, i, i+s-1, i+2*s-1); //合并大小为s的相邻2段子数组        i = i + 2*s;    }    //剩下的运算个数少于2s个    if (i + s < n)    { //至少还有s+1个元素        Merge(a, b, i, i+s-1, n-1);    }    else    { //最多剩下s个元素        for (j = i; j < n; j++)            b[j] = a[j];    }}void Merge(int a[], int b[], int l, int m, int r){ //合并a[l:m]和a[m+1:r]到b[l:r]    int i = l, j = m+1, k = l;    while (i <= m && j <= r)    {        if (a[i] <= a[j])            b[k++] = a[i++];        else            b[k++] = a[j++];    }    /*把数组剩余的部分复制到b中*/    while (i <= m)        b[k++] = a[i++];    while (j <= r)        b[k++] = a[j++];}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果6s手机打不开怎么办 苹果ipad密码输入打不开怎么办 苹果平板黑屏了打不开怎么办 苹果6sp电影商城打不开怎么办 苹果6应用商城打不开怎么办 游戏下载好了安装不上怎么办 苹果5s应用商店不见了怎么办 id被停用手机白板打不开怎么办 苹果6s下载不了软件怎么办 苹果下载的软件打不开怎么办 苹果6s下不了app怎么办 苹果手机因为闪退打不开了怎么办 天猫方糖坏了怎么办 天猫魔盒的遥控器坏了怎么办 天猫盒子没声音怎么办 天猫魔盒播放声音很低怎么办 天猫魔盒3a卡顿怎么办 天猫网络机顶盒打不开了怎么办 天猫机顶盒遥控器丢了怎么办 天猫机顶盒没有遥控器怎么办 天猫机顶盒很卡怎么办 天猫机顶盒没遥控器怎么办 天猫机顶盒看不了怎么办 天猫机顶盒变黑白怎么办 天猫精灵丢了怎么办 咪咕盒子没信号怎么办 猫los灯亮了怎么办 网络猫los闪红灯怎么办 台式电脑二级网页打不开.怎么办 光纤猫los红闪怎么办 系统管理员账户密码被更改怎么办 花呗不能使用了怎么办 开通余额宝提示身份验证失败怎么办 蚂蚁花呗刷脸认证老失败怎么办 火狐浏览器登录系统后打不开怎么办 花呗自动扣费怎么办 彪马运动裤买大了怎么办 淘宝卖家认证无法通过怎么办 淘宝开店申请未认证该怎么办 传照片到淘宝看不到照片怎么办 淘宝店铺秒出复核怎么办