现在的位置: 首页 > 综合 > 正文

排序算法系列-归并排序

2019年06月09日 ⁄ 综合 ⁄ 共 3017字 ⁄ 字号 评论关闭
文章目录

归并排序

Written By lpstudy, A man ofstriving for life.Please mark the deviation if you copy it.

1       排序描述

归并排序是一种重要的递归排序排序思想。它将一个大的问题划分成两个子问题,然后分别对两个小点的子问题进行求解,对求解后的结果合并后即为原大问题的解。由于这个是递归的,于是原来一个很大的问题,就被一点一点的拆分,最后拆分成最简单的情况,可以直接求解,然后将一点点的简单的情况逐个合并,最后即为所得。说着有些复杂,不过代码实现由于使用了递归,看起来就非常整洁明了了。

void MergeSort(整个A)
{
         if(满足条件)//这实际是递归的进行条件,也可以反过来看是递归的结束条件
         {
                  MergeSort(A的前一半);   //子问题,A的前一半
                  MergeSort(A的后一半);   //子问题,A的后一半
                  Merge(A的前一半,A的后一半);//两个子问题的解的合并
         }
}

2       存储结构

此排序算法可以直接数组存储。下面举例说明排序过程,一共有8个元素。

l  首先将8个元素的问题分解两个4个元素的问题。即9 2 83 和 7 1 0 6

l  然后对于前面4个的问题,即9 2 8 3,同样继续分解为两个2个元素的问题,即分解为92 和 8 3。

l  再次对于前面的小小子问题92,继续分解为两个子问题9和2

l  再再次对于前面的小小小子问题9,它只有一个元素,故而肯定是有序就不用排序了。

l  开始合并过程,将9和2两个子问题合并,排序成2,9;8和3两个子问题合并为3,8

l  继续合并2,9和3,8,合并成2,3,9,8.另外的一半同样合并为0,1,6,7

l  继续合并两个子问题得到最终的结果0,1,2,3,6,7,8,9

l  结果如下图所示

 

索引

0

1

2

3

4

5

6

7

元素值

9

2

8

3

7

1

0

6

第1趟

2

9

3

8

1

7

0

6

第2趟

2

3

8

9

0

1

6

7

第3趟

0

1

2

3

6

7

8

9

3       算法代码

主要分为两个部分,一个是总体递归框架部分,一个是对两个子问题的merge问题。

3.1    总体框架部分

//注意递归的结束条件,即只有一个元素的时候,递归截止

typedef int ElemType;

void MergeSort(ElemTypeA[],int low, int high)
{
    if(low <high)//high与low的差为元素个数,当low<high,是表明有多余个元素,表明可以继续递归。
    {
       int mid = (low+high)/2;
 
       MergeSort(A,low, mid);
       MergeSort(A,mid+1, high);
       Merge(A,low, mid, high);
    }
}

3.2    合并函数

//两个子问题的合并问题。

void Merge(ElemType A[], int low,int mid, int high)
{
    //将两个有序表A[low-> mid]和A[mid+1 -> high] 合并。
    //需要借助第三个表帮助合并,为了简单起见,我直接定义一个局部静态数组充当暂存数据
    const int MAX_SIZE = 9999;
    static ElemType H[MAX_SIZE];//辅助合并表

    int m = mid++;
    int k = 0;//合并后的H表的索引

    while(low <=m && mid<= high)
    {
       if(A[low] <A[mid])
           H[k++] =A[low++];
       else
           H[k++] =A[mid++];
    }
    while(low <=m)//左半还有未合并完成的
       H[k++] =A[low++];
    while(mid <=high)//右半还有未合并完成的
       H[k++] =A[mid++];
 
    for(inti = k-1; i >=0; --i,--high)
       A[high] =H[i];//将合并的集合复制回去
}

3.3    时间复杂度

由算法过程可以看出,每一个子问题合并为O(n)的级别,每一个子问题为T(n/2),故而中时间为T(n) = 2*T(n/2) + O(n)。这个时间复杂度为O(nlgn),而且它是一个稳定排序。

对于T(n) = a*T(n/b) + f(n)的形式,算法导论中有证明

         如果f(n) <, 则T(n) = O()

         如果f(n)=, 则T(n) = O(*lgn)

         如果f(n)>, 则T(n) = O()  其中当n趋近于无穷时,a*f(n/b)/ f(n)  < 1

举例来说:

         T(n)= 2T(n/2) + O(1) 其中b=a=2,故而属于第1种情况,T(n) = O(n)

         T(n)= 2T(n/2) + O(n) 其中b=a=2,故而属于第2种情况,T(n) = O(n*lgn)

         T(n)= 2T(n/2) + O(n*n) 其中b=a=2,故而属于第3种情况,T(n) = O(n*n)

4       执行代码和截图

4.1     完整执行代码

#include <iostream>
using namespacestd;
 
typedef int ElemType;
 
//两个子问题的合并问题。
void Merge(ElemType A[], int low,int mid, int high)
{
    //将两个有序表A[low-> mid]和A[mid+1 -> high] 合并。
    //需要借助第三个表帮助合并,为了简单起见,我直接定义一个局部静态数组充当暂存数据

    const int MAX_SIZE = 9999;
    static ElemType H[MAX_SIZE];//辅助合并表
 
    int m = mid++;
    int k = 0;//合并后的H表的索引

    while(low <=m && mid<= high)
    {
       if(A[low] <A[mid])
           H[k++] =A[low++];
       else
           H[k++] =A[mid++];
    }
    while(low <=m)//左半还有未合并完成的
       H[k++] =A[low++];
    while(mid <=high)//右半还有未合并完成的
       H[k++] =A[mid++];
 
    for(inti = k-1; i >=0; --i,--high)
       A[high] =H[i];//将合并的集合复制回去
}
void MergeSort(ElemTypeA[],int low, int high)
{
    if(low <high)//high与low的差为元素个数,当low<high,是表明有多余个元素,表明可以继续递归。
    {
       int mid = (low+high)/2;
 
       MergeSort(A,low, mid);
       MergeSort(A,mid+1, high);
       Merge(A,low, mid, high);
    }
}
void LP_MergeSort(ElemTypeA[],int len)
{

    MergeSort(A, 0,len-1);
}
void PrintArray(ElemTypeA[],int len)
{
    for(inti = 0; i < len; ++i)
    {
       printf("%3d",A[i]);
    }
    printf("\n");
}
int main()
{
    ElemType A[] ={9,2,8,3,7,1,0,6};
    int len = 8;
 
    printf("beforeMergeSort, array is ");
    PrintArray(A,len);

    LP_MergeSort(A,len);
    printf(" afterMergeSort, array is ");
    PrintArray(A,len);
    return 0;
};

4.2     运行截图

【上篇】
【下篇】

抱歉!评论已关闭.