归并排序 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)