归并排序(详解)

归并排序 O(nlogn)
千灯:归并排序很快的呵,我今天看懂了呢。
子诩:你怎么不用sort呢sort是无限接近O(n)。

【千灯】甩了【子诩】一巴掌。
子诩:***


千灯:归并的核心就是拆开来。
子诩:嗯对没错,然后在用两组对比。
千灯:你装不懂行吗,是我给你讲诶。
子诩:…(脸上隐隐作痛)
千灯:先不看拆开,对于两个有序的序列,我们可以用暴力排序

序列1: 1 2 7 9
序列2: 3 4 5 6

千灯:这是两个有序的序列,我们完全可以用O(n)算法把他们合并到序列3
子诩:…
千灯:快问怎么做!
子诩:怎么做…
千灯:我们用序列2的首个(最小的)对序列1进行比较,如果序列1的比序列2的最小还小,那么必定是序列3中最小的,就把这个数字放入序列3,在序列1踢出
子诩:…
千灯:说‘对,没错’
子诩:对,没错。
千灯:剩下我们要做的就是继续找出次小的,次次小的,直到序列1的最小>序列2的最小,那么此时的序列2的最小,是序列1,2中的最小,我们就把他放入序列3,我们再用剩下的序列2中的最小去比较…
子诩:…我不懂(隐隐作痛)。
千灯:给你讲清楚吧

序列1: 1 2 7 9
序列2: 3 4 5 6
序列3: 
---------
此时3是序列2最小的,与序列1的最小对比
1<3,1是两个序列最小的
序列1: 2 7 9
序列2: 3 4 5 6
序列3: 1
---------
此时3是序列2最小的,与序列1最小对比
2<3,2是两个序列最小的
序列1: 7 9
序列2: 3 4 5 6
序列3:1 2
---------
此时3是序列2最小的,与序列1最小对比
7>3,3是两个序列最小的
序列1: 7 9
序列2: 4 5 6
序列3: 1 2 3
........

子诩:所以说序列3每次找序列1和序列2中最小的数加入自己的序列。
千灯:没错,这样就可以保证序列3是从小到大排序的。
千灯:因为序列1和序列2都是有序的(序列1的第一个数字是序列1最小的,序列2的第一个数字是序列2最小的),所以min(序列1的第一个数,序列2的第一个数)才是序列1,2的最小数。
千灯:当然还要打补丁

序列1: 7 9
序列2: 
序列3: 1 2 3 4 5 6
这个时候就不能再比较了,因为序列2没东西可以比了。。
所以还要一个while暴力把剩下的强制加入序列3

千灯:根据上面说的我们可以这样写

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int tmp=1,i=1,j=1,k=4,p=4;	//k是第一个序列的长度,p是第二个序列的长度
    int a1[5]={0,1,2,7,9};
    int a2[5]={0,3,4,5,6};
    int a3[k+p+1];
    while(i<=k&&j<=p)	
    {
    	if(a2[j]>a1[i])
    		a3[tmp]=a1[i],++tmp,++i;
     	else a3[tmp]=a2[j],++tmp,++j;
    }
    //下面两个while实际上只可能执行一个,序列1和序列2最多只可能有一个空
    while(i<=k)
   	a3[tmp]=a1[i],++tmp,++i;
    while(j<=p)
    	a3[tmp]=a2[j],++tmp,++j;
    //那么a3就是有序的了
}

子诩:…你好厉害QAQ…
千灯:…演技浮夸。
千灯:当然最重要的,归并还得保证序列1和序列2是有序的
千灯:这就是归并的核心,我们认为只有一个数字的序列是有序的(没什么毛病),那么归并动过递归,不断把原来的序列拆分,直到拆分成只有一个数字,那么这个时候就保证了该序列的有序,那么我们再和另外一个有序的对比(经行上面的排序),就可以得到新的有序序列3,序列3作为序列1再和其他的序列对比,直到序列3的长度为n,就给n个数字排序了。
子诩:听不懂…
千灯:第七人民医院不欢迎您。

比如给{1,4,3,1,2,7}排序
1.a1={1},a2={4},a3={1,4}
2.a1={3},a2={1},a3={1,3}
3.a1={2},a2={7},a3={2,7}
那么这个时候变为
{{1,4},{1,3},{2,7}}
1.a1={1,4},a2={1,3},a3={1,1,3,4}
这个时候变为
{{1,1,3,4},{2,7}}
1.a1={1,1,3,4},a2={2,7},a3={1,1,2,3,4,7}
原数组排序结果为
{1,1,2,3,4,7}

千灯:我们很显然不能正着去做,这样太复杂,其实用递归就可以实现,我们每次把这一段分成两半,直到有一段长度刚好是2,分开来是1,就返回,比较。

merge_sort (int left,int right,int merge[])
{     
	if(left==right) return;//就是分到一个数字的时候,返回
	int mid=(left+right)>>1;//相当于/2
 	merge_sort(left,mid,merge);
 	merge_sort(mid+1,right,merge);
 	/*
 	在分到一个数字返回后就会执行该区域的操作
 	因为已经枚举到了有序的两个序列:
 	merge[left]~merge[mid]<----a1
 	merge[mid+1]~merge[right]<----a2
 	那么合并完的a3自然要加回merge数组
 	这个时候merge[left]~merge[right]就是有序的了
 	*/
}

那么把代码补充完整

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
int a[maxn],n,merge_array[maxn];
void merge_sort(int merge_left,int merge_right,int the_merge[])
{
    if(merge_left==merge_right) return;
    int merge_mid=(merge_left+merge_right)/2;
    merge_sort(merge_left,merge_mid,the_merge);
    merge_sort(merge_mid+1,merge_right,the_merge);
    int merge_i=merge_left,merge_j=merge_mid+1,merge_tmp=merge_left-1;
    while(merge_i<=merge_mid&&merge_j<=merge_right)
        if(the_merge[merge_i]>the_merge[merge_j]) 
        	merge_array[++merge_tmp]=the_merge[++merge_j-1];
        else merge_array[++merge_tmp]=the_merge[++merge_i-1];
    while(merge_i<=merge_mid) merge_array[++merge_tmp]=the_merge[++merge_i-1];
    while(merge_j<=merge_right) merge_array[++merge_tmp]=the_merge[++merge_j-1];
    for(register int i=merge_left;i<=merge_right;++i) the_merge[i]=merge_array[i];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    merge_sort(1,n,a);
}

子诩:…
千灯:讲完了QAQ
归并=二分 O(logn)+暴力排序 O(n)=O(nlogn)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值