遞迴的呼叫順序--c實現
阿新 • • 發佈:2018-11-29
首先說說遞迴的呼叫過程,直接上程式碼:
#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.按照位置進行。(快速排序是按照值進行排序)。合併排序重在合併劃分之後的子問題的解,而快速排序演算法的主要工作在於劃分,在於如何進行劃分。切記。
快速排序
快速排序是另一個利用分治法進行排序的方法