首先说说递归的调用过程,直接上代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int count = 0;
int xtrans(int a[],int left,int right){
int mid = (left+right)/2;
int i = 0;
if(mid <=left || mid >=right) return -1;
// printf("xtrans mid : %d left : %d,right: %d\n",mid,left,right);
printf("mid : %.2d ",mid);
printf("(%.2d)",count);
/*if(left >=10){
printf("--");
}else if(left >0 && left< 10){
printf("-");
}*/
for(i=0;i<left;i++){
printf("-");
}
printf("%d",left);
for(i =0; i<right-left+1;i++){
printf("-");
}
count++;
// printf("right : %d\n",right);
printf("%d\n",right);
xtrans(a,left,mid);
xtrans(a,mid+1,right);
}
int main(){
int a[51],i=0;
srand((int)time(0));
for(i=0;i<51;i++){
a[i] = rand()%50;
printf("init %d\n",a[i]);
}
xtrans(a,0,50);
return 0;
}
输出:
mid : 25 (00)0---------------------------------------------------50
mid : 12 (01)0--------------------------25
mid : 06 (02)0-------------12
mid : 03 (03)0-------6
mid : 01 (04)0----3
mid : 05 (05)----4---6
mid : 09 (06)-------7------12
mid : 08 (07)-------7---9
mid : 11 (08)----------10---12
mid : 19 (09)-------------13-------------25
mid : 16 (10)-------------13-------19
mid : 14 (11)-------------13----16
mid : 18 (12)-----------------17---19
mid : 22 (13)--------------------20------25
mid : 21 (14)--------------------20---22
mid : 24 (15)-----------------------23---25
mid : 38 (16)--------------------------26-------------------------50
mid : 32 (17)--------------------------26-------------38
mid : 29 (18)--------------------------26-------32
mid : 27 (19)--------------------------26----29
mid : 31 (20)------------------------------30---32
mid : 35 (21)---------------------------------33------38
mid : 34 (22)---------------------------------33---35
mid : 37 (23)------------------------------------36---38
mid : 44 (24)---------------------------------------39------------50
mid : 41 (25)---------------------------------------39------44
mid : 40 (26)---------------------------------------39---41
mid : 43 (27)------------------------------------------42---44
mid : 47 (28)---------------------------------------------45------50
mid : 46 (29)---------------------------------------------45---47
mid : 49 (30)------------------------------------------------48---50
从上面输出可以看到,递归的调用和我猜测的差不多,就是一路向左向下,然后合并右行,然后右行之向左向下。。。。,就是不断的把大问题分解为小问题,小问题分解为更小的问题,直到更更更小的问题可以得到答案。
根据上面的递归调用可以引申到归并排序中的
1)归,就是递归分解的意思
2)并,就是把更更更小的问题答案进行合并
总的意思就是递归分解然后逐项小答案合并最终得到问题的解,其算法策略是分治法,如图:
治:
(上面的两个图都来自于:
https://www.cnblogs.com/chengxiao/p/6194356.html,
归并排序,直接上代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int mergeSort(int a[],int left,int mid,int right,int temp[]){
int i = left,j=mid+1,k=right;
int t = 0;
while(i<=mid && j <= right){
if(a[i]<=a[j]){
temp[t++] = a[i++];
}else{
temp[t++] = a[j++];
}
}
while(i<=mid){
temp[t++] = a[i++];
}
while(j<=right){
temp[t++] = a[j++];
}
t = 0;
while(left<=right){
a[left++] = temp[t++];
}
}
int divideMerge(int acx[],int left,int right,int temp[]){
int mid;
if(left < right){
mid = (left+right)/2;
divideMerge(acx,left,mid,temp);
divideMerge(acx,mid+1,right,temp);
mergeSort(acx,left,mid,right,temp);
}
}
int main(){
const int L = 50;
int i = 0,ax[L],temp[L];
srand((int)(time(0)));
for(i = 0; i < L;i++){
ax[i] = rand()%L;
printf("%d ",ax[i]);
temp[i] = 0;
}
printf("\n\n");
divideMerge(ax,0,L,temp);
for(i = 0; i < L;i++){
printf("%d ",ax[i]);
}
printf("\n\n");
}
归并排序的列子(见《算法设计与分析基础 第三版》 134p)
归并排序的特点:
1.需要额外的空间,比如上面的代码中的temp[]数组
2.平均,最坏都是nlogn,
3.稳定
4.按照位置进行。(快速排序是按照值进行排序)。合并排序重在合并划分之后的子问题的解,而快速排序算法的主要工作在于划分,在于如何进行划分。切记。
快速排序
快速排序是另一个利用分治法进行排序的方法