C++ 归并排序

一.算法介绍

        归并排序是一种基于分治思想,时间复杂度为O(nlgn),空间复杂度为O(n)的排序算法

二.算法思路

       首先我们先来看看一个子问题:怎么把两个有序的数组合并为一个有序的数组。答案很简单,我们可以先把两个数组的数据连为一个数组,再用一个排序算法给它排序。那用什么算法呢,冒泡?显然时间复杂度O(n^2)不好。我们可以换种思路在O(n)的时间复杂度内排好序。为什么呢?因为两个数组都是有序的。我们可以同时遍历两个数组,取出元素较小的那个放进目标数组,再将被取出元素的数组下标加一。

const int N=505;

int a[N],b[N],c[2*N];

//n为有序数组a的长度,m为有序数组b的长度,现在将a,b数组合并到c中 
void merge(int n,int m){
	int i,j,k=0;
	for(i=0,j=0;i<n&&j<m;){
		if(a[i]<b[j]){
			c[k]=a[i];
			i++;
		} 
		else{
			c[k]=b[j];
			j++;
		}
		k++;
	}
//	当a或者b中某一个数组遍历完啦,另外一个数组直接复制到c后面
	if(i<n){
		while(i<n){
			c[k++]=a[i];
			i++;
		} 
	}
	if(j<m){
		while(j<m){
			c[k++]=b[j];
			j++;
		} 
	} 
} 

可以看出,这样我们就实现O(n)时间复杂度合并两个有序数组啦。

那么好有了这一个函数,又怎么样来实现O(nlgn)的归并排序呢。这里我们就用分治来思考,我们可以在O(n)时间复杂度将两个有序数组合并为一个有序数组,那我们只要能将一个乱序数组(n个元素)变成两个有序数组(n/2个元素)就好啦。然而,这两个有序数组,在初始也是乱序的,我们只要能将两个乱序数组变成四个有序数组(n/4)就好啦,同理,四个变八个(n/8),八个变十六个,...............直到最后变为n个有序数组(1个元素)。一个元素,它本身就是有序的。

好,我们再来看看每一层的时间复杂度,第一层,两个有序数组合并得到一个有序。这里时间复杂度是O(n/2)+O(n/2) =O(n)。第二层:四个有序数组合并得到两个有序,O(n/4)+O(n/4) =O(n/2),O(n/4)+O(n/4) =O(n/2).最后还是O(n/2)+O(n/2) =O(n),第三层第四层,都一样为O(n)

好,得到了每一层的时间复杂度为O(n),我们再来看看有多少层,从上面的分析可以看出,我们每一层要分割数组元素,直到最后分割为一个数组一个元素停止,所以我们要分割出n个数组。1->2,2->4,4->8,8->16,......我们可以看出要分出n个数组,只需要lgn次。一共就需要有lgn层。这也就是为什么归并排序的时间复杂度为O(nlgn)

好,下面来看它的实现。

#include <bits/stdc++.h>
using namespace std;

const int N=505;

int a[N],b[N];//a为原数组,b为辅助数组
void merge(int l,int mid,int r){
    int i=l,j=mid+1,k=l;
    for(;i<=mid&&j<=r;){
        if(a[i]<a[j]){
            b[k]=a[i];
            i++;
        }
        else{
            b[k]=a[j];
            j++;
        }
        k++;
    }
//	当左边部分或者右边部分遍历完啦,另外一个部分直接复杂到c后面
    while(i<=mid){
        b[k++]=a[i];
        i++;
    }
    while(j<=r){
        b[k++]=a[j];
        j++;
    }

//	将对应的辅助数组信息写回原数组
    for(i=l;i<=r;i++){
        a[i]=b[i];
    }
}

void mergeSort(int l,int r){
    int mid = (l+r)/2;
    //作为划分数组的中间点
    if(r-l>=1){
        mergeSort(l,mid);
        mergeSort(mid+1,r);
        merge(l,mid,r);
    }
}

void solve(){
//  "输入数组的长度:";
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
//  左右都是闭区间实现
    mergeSort(0,n-1);
    for(int i=0;i<n;i++){
        cout<<a[i]<<" ";
    }
}
signed main(){
//    ios::sync_with_stdio(0);
//    cin.tie(0);
//    cout.tie(0);
//    ofstream cout("Eout.txt");
        solve();
    return 0;
}

三.总结

        找到可递推的性质是用递归实现算法,大幅度减少时间复杂度的关键

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值