分治概念:
把一个任务分成更小的相同的小任务(一般分成两个),然后先处理小的任务,最后在综合处理大的任务即可完成任务。
举例:
有16枚硬币,只有1个假币,且重量比较轻。问最短需要多少次能找到假币?
解析:
如果我们用1-1测试的方法。需要8次才能测完。但是如果8-8的测试呢?
8-8,则若有假币,必定有一方倾斜,对翘起的一方继续测量。
4-4
2-2
1-1
只需要经过4次,就可以找到那枚硬币,是不是很简单呢?这就是分治的思想之一。
------------------------------------------------------------------------------------------------------------------------------------
但是我们再说下本轮的重点,归并排序:
归并排序的思想:
1.把前一段排序
2.把后一段排序
3.把两半归并到一个新的有序数组。然后再拷贝回原数组,排序完成。
(前一段排序和后一段排序依旧是同样的过程,显然这是一个递归的过程)
那么递归的结束时刻是哪呢?即归并的起点和终点相同时,显然代表只有一个数,那么它本身就是有序的,直接返回即可。
复杂度:
时间复杂度O(nlogn):推导过程。
空间复杂度O(N):
因为需要一个tmp数组来存放排序好的数,然后赋值给本身。
如何排序:
思想了解了,我们思考如何对排序好的2段数进行归并:假设有2个已排序好的数组a和b,则可以
1.设置两个指针变量p0和p1。p0指向数组a,p1指向数组b。同时需要一个tmp数组用来存放排序好的数。用指针pb指向首部。
2.判断两个指针指向变量的值的大小,小的则将其赋值到tmp,同时它相对的指针向后移动。
当两段数组中的一个赋值完成,则剩下的一段直接赋值过去即可。(这里假设a赋值完成,则将b数组直接赋值过去)
while(i<=s)
tmp[pb++] = b[p1++];
![](https://i-blog.csdnimg.cn/blog_migrate/efc4e82f202c65b6b5babe82c8649c08.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5fe39d044ff588a1171e3eee44917bfd.png)
附上全部代码:
1.解释版:
#include <iostream>
using namespace std;
void Merge(int a[],int s,int m,int e,int tmp[])
{
//将数组a的局部a[s,m]和a[m+1,e]合并到tmp,并保证tmp有序
//然后再拷贝回a[s,e]
//归并操作时间复杂度:O(e-s+1),即O(n)
int pb = 0;//pb指向额外的数组tmp
int p1 = s,p2 = m+1;//p1指向前一个指针,p2指向后一个指针
//标记1:我这里些错过1会,写成了p2 = m,出错,自己思考下,应该是m+1.如果填的是m,则顺序只能与原来相同,不会改变。
while( p1 <= m && p2 <= e){//两者都没有走到头
if( a[p1] < a[p2])
tmp[pb++] = a[p1++];
else
tmp[pb++] = a[p2++];
}
//有一半走到头了,直接把另一半直接拷过去
while( p1 <= m)
tmp[pb++] = a[p1++];
while( p2 <= e)
tmp[pb++] = a[p2++];
//把排序好的tmp数组赋值到a数组中
for(int i=0;i<e-s+1;++i)
a[s+i] = tmp[i];
//标记2:我原来写成了a[i] = tmp[i];应该写成a[s+i],即把归并后的数放到原来的位置在进行新的归并。
}
//a数组,对s到e进行排序,依靠额外的数组tmp
void MergeSort(int a[],int s,int e,int tmp[])
{
//如果s = e,就是这个数本身,不用排序,直接返回
if( s < e){
int m = s + (e-s)/2;
MergeSort(a,s,m,tmp);
MergeSort(a,m+1,e,tmp);
Merge(a,s,m,e,tmp);
}
else return;//else return这句话是我自己加的,加了更容易理解,这是他的递归结束条件。不加程序也能运行
}
int a[10] = { 13,27,19,2,8,12,2,8,30,89};
int b[10];
int main()
{
int size = sizeof(a)/sizeof(int);
//对数组a的0~size-1位置进行归并排序,并依靠一个额外的数组b
MergeSort(a,0,size-1,b);
for(int i=0;i<size;++i)
cout << a[i] << ",";
cout << endl;
return 0;
}
2.套用版:
#include <iostream>
using namespace std;
void Merge(int a[],int s,int m,int e,int tmp[])
{
int pb = 0;
int p1 = s,p2 = m+1;
while( p1 <= m && p2 <= e){
if( a[p1] < a[p2])
tmp[pb++] = a[p1++];
else
tmp[pb++] = a[p2++];
}
while( p1 <= m)
tmp[pb++] = a[p1++];
while( p2 <= e)
tmp[pb++] = a[p2++];
for(int i=0;i<e-s+1;++i)
a[s+i] = tmp[i];
}
//a数组,对s到e进行排序,依靠额外的数组tmp
void MergeSort(int a[],int s,int e,int tmp[])
{
if( s < e){
int m = s + (e-s)/2;
MergeSort(a,s,m,tmp);
MergeSort(a,m+1,e,tmp);
Merge(a,s,m,e,tmp);
}
}
int a[10] = { 13,27,19,2,8,12,2,8,30,89};
int b[10];
int main()
{
int size = sizeof(a)/sizeof(int);
MergeSort(a,0,size-1,b);
for(int i=0;i<size;++i)
cout << a[i] << ",";
cout << endl;
return 0;
}