数据结构——归并排序

 这篇博客主要摘自https://www.cnblogs.com/chengxiao/p/6194356.html我又用C++重写了一下代码

基本思想

  归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

分而治之

   可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

合并相邻有序子序列

  再来看看阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 500010
#define ll long long int
using namespace std;
ll a[maxn];
ll temp[maxn];
ll sum;
void Merge(int l,int r,int m)
{
    int i=l;
    int j = m + 1;
    int k = l;
    while(i<=m&&j<=r)
    {
        if(a[i]>a[j])
        {
            //sum+=m-i+1;
            temp[k++]=a[j++];
        }
        else
        {
            temp[k++]=a[i++];
        }
    }
    while(i<=m)///将剩余的元素存到数组中
    {
        temp[k++]=a[i++];
    }
    while(j<=r)
    {
        temp[k++]=a[j++];
    }
    for(i=l; i<=r; i++)
    {
        a[i]=temp[i];
    }
}
void mergesort(int l,int r)
{
    if(l<r)
    {
        int m = (l + r) / 2;
        mergesort(l,m);///左二分排序
        mergesort(m+1,r);///右二分排序
        Merge(l,r,m);///合并两个升序数组
    }
}
int main()
{
    int n,i;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
        {
            break;
        }
        for(i=0; i<n; i++)
        {
            scanf("%lld",&a[i]);
        }
        sum=0;
        mergesort(0,n-1);
        for(i=0; i<n; i++)
        {
            printf("%lld ",a[i]);
        }
    }
    return 0;
}

执行结果

[1, 2, 3, 4, 5, 6, 7, 8, 9]

最后

  归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

原文地址:https://www.cnblogs.com/wkfvawl/p/9772447.html