6.归并排序:
基本思想:经典的分治思想。
分治法:个人理解的分治思想就是,想要解决一个大的问题,就需要把一个大的问题分解成若干个小的子问题,把每个小的子问题逐个击破,最终就把一个大的问题给解决掉了。
介绍了一下什么是分治,那么问题来了,这个问题和归并排序有什么关联呢?
归并排序思想:假设把一组数分成俩个部分,每个部分其实都是有序的(从小到大,或者从大到小),然后把每组数的头一个数字相互比较,谁小谁放在前面,那么最终把俩组数据合并为一组数据的时候,这个数据就是有序状态
就相当于鲤鱼越龙门一样,小的先过!
上面介绍的是总体想法,那么怎么实现这个总体想法呢?
就是,本来一串数据本来是无序的,怎么把一串无序数据变成俩个有序数据,然后像鲤鱼越龙门一样,小的先过,最终变成有序状态?
这就是开始运用分治思想了(递归开始),把数据分成俩部分,然后排序,把每个部分再分成俩部分,一直到只有一个数据的时候为止:
具体代码如下:
void guibing(int a[max],int p,int r){//归并算法
int mid;
if(p<r){
mid=(p+r)/2;//分界点
guibing(a,p,mid);//第一部分,已经有序
guibing(a,mid+1,r);//第二部分,已经有序
guibingsort(a,p,mid,r);//把俩个部分合成一个部分
}
}
这是总体设计,接下来该解决具体怎么实现把俩个部分合成一个部分的算法也就是上图中的方法guibingsort(a,p,mid,r),方法的具体实现。
void guibingsort(int a[max],int p,int mid,int r){
int b[max];
int current;
int left;
int right;
int i;
left=p;//第一部分所用指针
right=mid+1;//第二部分所用指针
current=p;
for(i=0;i<max;i++){
b[i]=a[i];
}//复制一个新的数组
while(left<=mid&&right<=r){
if(b[left]<=b[right]){//谁小谁先过
a[current]=b[left];
current++;
left++;
}else{
a[current]=b[right];
current++;
right++;
}
}
while(left<=mid){//如果左边还没有到边界那么就把左边的值放到序列的后面
a[current]=b[left];
current++;
left++;
}
}
注意:不是每次左右指针都是刚好移动到终点,假设如果左边的数整体比右边的数小那么左指针走到地了,右指针才能开始移动,再假设右边的数整体比左边的数小,那么当右指针走到低了,左指针才开始移动
针对第一种情况:首先我们是按照复制的对照数组把原数组进行改变,如果左边比右边小,那么当左指针走到低了,右指针就不需要移动,因为剩下的数字就是右边的全部数字
针对第二种情况A: 右边走到低了,左边还有没走完的,那么就需要把左边的数字依次按照顺序添加到整个序列的后面
while(left<=mid){
a[current]=b[left];
current++;
left++;
}
接下来完整的归并排序代码如下:
void guibingsort(int a[max],int p,int mid,int r);//7
void guibing(int a[max],int p,int r){
int mid;
if(p<r){
mid=(p+r)/2;
guibing(a,p,mid);
guibing(a,mid+1,r);
guibingsort(a,p,mid,r);
}
}
void guibingsort(int a[max],int p,int mid,int r){
int b[max];
int current;
int left;
int right;
int i;
left=p;
right=mid+1;
current=p;
for(i=0;i<max;i++){
b[i]=a[i];
}
while(left<=mid&&right<=r){
if(b[left]<=b[right]){
a[current]=b[left];
current++;
left++;
}else{
a[current]=b[right];
current++;
right++;
}
}
while(left<=mid){
a[current]=b[left];
current++;
left++;
}
}
喜欢的记得点个关注哟!
我会经常分享的!