1. 程式人生 > >遞迴的呼叫順序--c實現

遞迴的呼叫順序--c實現

 首先說說遞迴的呼叫過程,直接上程式碼:

#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,

作者:dreamcatcher-cx,

文章:圖解排序演算法(四)之歸併排序

歸併排序,直接上程式碼:

#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.按照位置進行。(快速排序是按照值進行排序)。合併排序重在合併劃分之後的子問題的解,而快速排序演算法的主要工作在於劃分,在於如何進行劃分。切記。

快速排序

快速排序是另一個利用分治法進行排序的方法