日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

發(fā)布時(shí)間:2023/12/4 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本節(jié)主要說了遞歸的設(shè)計(jì)和算法實(shí)現(xiàn),以及遞歸的基本例程斐波拉契數(shù)列、strlen的遞歸解法、漢諾塔和全排列遞歸算法。

一、遞歸的設(shè)計(jì)和實(shí)現(xiàn)

1.遞歸從實(shí)質(zhì)上是一種數(shù)學(xué)的解決問題的思維,是一種分而治之的思想。

這個(gè)是常見的一種數(shù)學(xué)算法,其實(shí)它就是遞歸的本質(zhì)。我們要求的是所有數(shù)的乘積,那么我們就先求出兩個(gè)數(shù)的乘積,然后再根據(jù)這兩個(gè)數(shù)的乘積去求第三個(gè)數(shù)的乘積,這樣每一次我們實(shí)際上都是進(jìn)行的兩個(gè)數(shù)的相乘,也就是我們把一個(gè)很多個(gè)數(shù)的相乘轉(zhuǎn)換為了兩個(gè)數(shù)的相乘。

2.通過上面的例子可以發(fā)現(xiàn),遞歸就是將大型復(fù)雜問題轉(zhuǎn)化為與原問題相同,但是規(guī)模變小的問題進(jìn)行處理。

4.同時(shí)我們可以發(fā)現(xiàn)a1 這個(gè)時(shí)候n==1,是一個(gè)特殊的條件。這就是遞歸的邊界條件,最后的最后我們都會(huì)執(zhí)行到遞歸的邊界條件,然后再?gòu)倪吔鐥l件返回。等到都返回結(jié)束后我們就真正實(shí)現(xiàn)了我們想要的結(jié)果。

5.如果遞歸沒有邊界條件,那么我們的遞歸將永遠(yuǎn)無(wú)法跳出,也就是這個(gè)問題遞歸是無(wú)法解決的。

6.在解決遞歸問題的時(shí)候首先要建立遞歸模型,這是解決遞歸類問題的第一步。但是說來容易,其實(shí)這是一個(gè)痛苦的過程,說白了,算法不是一般人能搞的。

二、斐波拉切數(shù)列的遞歸實(shí)現(xiàn)

1.斐波拉切數(shù)列實(shí)際上就是一個(gè)遞歸的典型表現(xiàn),它的具體要求如下:

通過上圖我們可以知道,斐波拉契數(shù)列的要求就是求相鄰兩個(gè)的數(shù)和然后賦給第三個(gè)數(shù)。這樣我們可以先求前兩個(gè)數(shù)的和,然后再求第二個(gè)與第三個(gè)數(shù)的和,一直求到最后,然后再返回。

2.假定我們要求的數(shù)列的元素個(gè)數(shù)為10

那么具體程序如下所示:

#include <stdio.h>int fibonacci(int n) {if( n > 1 ){return fibonacci(n-1) + fibonacci(n-2);}else if( n == 1 ){return 1;}else if( n == 0 ){return 0;} }int main() {int i = 0;for(i=1; i<=10; i++){printf("fibonacci(%d) = %d\n", i, fibonacci(i));}return 0; }

通過上面的程序可以看出:我們首先通過主函數(shù)調(diào)用fibonacci函數(shù),然后通過for循環(huán)依次向里面?zhèn)鬟f值,第一次傳遞的值為1,返回的值為1,所以打印1.第二次傳遞的值為2,符合if(n>1)的條件,執(zhí)行語(yǔ)句

fibonacci(n-1) + fibonacci(n-2);

這個(gè)時(shí)候產(chǎn)生第一輪遞歸,也就是先執(zhí)行函數(shù)fibonacci(1)執(zhí)行以后的返回結(jié)果是1,再執(zhí)行fibonacci(0),執(zhí)行以后的返回結(jié)果是0,所以這一輪的返回結(jié)果是是1.

繼續(xù)調(diào)用fibonacci函數(shù),傳遞的參數(shù)是3,然后依次向后執(zhí)行,每一次的遞歸深度都在加深。

三、strlen函數(shù)使用遞歸方式實(shí)現(xiàn)

1.我們都知道strlen函數(shù)的使用方法,它是通過傳遞進(jìn)來的字符串來判斷字符串的大小,但遇見"\0"的時(shí)候返回字符的個(gè)數(shù),"\0"不包括在內(nèi)。
2.假定我們要求一個(gè)"12345"的字符串的長(zhǎng)度,具體例程如下:

#include <stdio.h>int strlen(const char* s) {if( s == NULL ){return -1;}else if( *s == '\0' ){return 0;}else{return strlen(s+1) + 1;} }int main() {printf("strlen(\"12345\") = %d\n", strlen("12345"));printf("strlen(NULL) = %d\n", strlen(NULL));printf("strlen(\"\") = %d\n", strlen(""));return 0; }

程序分析:我們?cè)谥骱瘮?shù)中調(diào)用strlen函數(shù),在我們第一次進(jìn)入strlen函數(shù)的時(shí)候,程序執(zhí)行判定,都不滿足前兩個(gè)判定,程序繼續(xù)向下執(zhí)行,再次調(diào)用strlen函數(shù),然后再進(jìn)行判定,仍然不滿足判定條件,一直執(zhí)行到s指針指向'\0',這個(gè)時(shí)候各個(gè)調(diào)用函數(shù)開始返回,最外層的返回0,0+1,第二層返回1,1+1,第三層返回1,1+1 。直至所有函數(shù)全部返回。程序打印結(jié)果如下所示:

整個(gè)程序我們是把一個(gè)字符串的長(zhǎng)度求解過程轉(zhuǎn)變成了對(duì)每一個(gè)字符長(zhǎng)度的求解,然后再進(jìn)行相加,邊界條件就是'\0'。

四、漢諾塔遞歸算法的實(shí)現(xiàn)

1.漢諾塔的要求我就不詳細(xì)說了,漢諾塔的問題我想了足足一天,其實(shí)最后也是單步調(diào)試加上草稿紙才把它搞定,這里拿三個(gè)盤子作為分析。

2.漢諾塔的遞歸思想:第一,把a(bǔ)上的n-1個(gè)盤通過c移動(dòng)到b。第二,把a(bǔ)上的最下面的盤移到c。第三,因?yàn)閚-1個(gè)盤全在b上了,所以把b當(dāng)做a重復(fù)以上步驟就好了。
?

?3.漢諾塔的具體代碼實(shí)現(xiàn):

#include <stdio.h>void hanoi(int n, char a, char b, char c) {if( n > 0 ){if( n == 1 ){printf("%c -> %c\n", a, c);}else{hanoi(n-1, a, c, b);printf("%c -> %c\n", a, c);hanoi(n-1, b, a, c);}} }int main() {hanoi(3, 'a', 'b', 'c');getchar(); return 0; }

程序打印結(jié)果如下:

五、漢諾塔遞歸調(diào)用分析

因?yàn)闉榱苏{(diào)試方便觀看值,所以我把a(bǔ),b,c字符重新定義成了整型變量,具體程序如下:

#include <stdio.h>void hanoi(int n, int a, int b, int c) {if( n > 0 ) {if( n == 1 ){printf("%d -> %d\n", a, c);}else{hanoi(n-1, a, c, b);printf("%d -> %d\n", a, c);hanoi(n-1, b, a, c);}} }int main() {hanoi(3, 5, 6, 7);return 0; }

1.從主函數(shù)中調(diào)用hannoi函數(shù),傳遞的參數(shù)是:n=3,a(1)=5,b(1)=6,c(1)=7
2.第1次進(jìn)入hannoi函數(shù),執(zhí)行if(n==1)判定,不符合條件,調(diào)用hanoi(n-1,a,c,b)函數(shù)
3.向hannoi傳遞的參數(shù)是:n=2,a(2)=a(1),b(2)=c(1),c(2)=b(1)
4.第2次進(jìn)入hannoi函數(shù),執(zhí)行if(n==1),不符合條件,調(diào)用hanoi(n-1,a,c,b)函數(shù)
5.向hannoi傳遞的參數(shù):n=1,a(3)=a(2),b(3)=c(2),c(3)=b(2)
6.第3次進(jìn)入hannoi函數(shù),執(zhí)行if(n==1)判定,符合條件,執(zhí)行打印函數(shù)printf("%d->%d\n",a,c)這個(gè)時(shí)候打印函數(shù)里面的a,c是第3次調(diào)用hannoi函數(shù)傳遞進(jìn)來的參數(shù),也就是a3),c(3),追到原始值也就是a(1),c(1)。打印結(jié)果是:5->7
7.n=3的hannoi函數(shù)調(diào)用結(jié)束,子函數(shù)第1次執(zhí)行結(jié)束。返回到n=2的hannoi函數(shù)調(diào)用位置,程序繼續(xù)向下執(zhí)行
8.調(diào)用打印函數(shù):printf("%d->%d\n",a,c),這個(gè)時(shí)候打印函數(shù)的參數(shù)是n=2的時(shí)候hannoi函數(shù)的參數(shù),也就是
a(2),c(2),追到原始值a(1),b(1)。打印結(jié)果是:5->6
9.執(zhí)行完打印函數(shù)以后程序繼續(xù)向下執(zhí)行,調(diào)用hanoi(n-1,b,a,c)函數(shù)
10.這次調(diào)用hanoi(n-1,b,a,c)是從n=2的hannoi函數(shù)開始的,所以向hannoi函數(shù)傳遞的參數(shù)是:n=1,a(4)=b(2),b(4)=a(2),c(4)=c(2)
11.第4次進(jìn)入hannoi函數(shù),指定if(n==1)判定,符合條件,執(zhí)行打印函數(shù)printf("%d->%d\n",a,c)這個(gè)時(shí)候打印函數(shù)里的a,c是a(4),c(4),追到原始值c(1),b(1),打印結(jié)果是:7->6.
12.調(diào)用hanoi(n-1,b,a,c)函數(shù)結(jié)束,程序返回到調(diào)用hanoi(n-1,b,a,c)函數(shù)的位置,接下來程序沒有語(yǔ)句,子函數(shù)再次結(jié)束,程序返回到n=3調(diào)用hannoi函數(shù)的位置,執(zhí)行印函printf("%d->%d\n",a,c),這個(gè)時(shí)候打印函數(shù)里的參數(shù)a,c是n=3的時(shí)候的參數(shù),也就是a(1),c(1),追到原始值。打印結(jié)果是:5->7。
13.程序繼續(xù)向下執(zhí)行,調(diào)用hanoi(n-1,b,a,c)函數(shù)
14.這個(gè)時(shí)候第一輪遞歸已經(jīng)結(jié)束,向hannoi傳遞的參數(shù)是:n=2,a(5)=b(1),b(5)=a(1),c(5)=c(1)
15.第5次進(jìn)入hannoi函數(shù),執(zhí)行if(n==1)判定,不符合條件,調(diào)用hannoi(n-1,a,c,b)函數(shù)
16.向hannoi傳遞的參數(shù)是:n=1,a(6)=a(5),b(6)=c(5),c(6)=b(5)
17.第6次進(jìn)入hannoi函數(shù),執(zhí)行if(n==1)判定,符合條件,執(zhí)行打印函數(shù)printf("%d->%d\n",a,c)這個(gè)打印函數(shù)里面的參數(shù)a,c是第6次調(diào)用hannoi函數(shù)的參數(shù),也就是a(6),c(6),即b(1),a(1),追到原始值為6,5,打印結(jié)果是6->5
18.這個(gè)時(shí)候第6次進(jìn)入hannoi函數(shù)執(zhí)行完畢,程序返回到第六次調(diào)用hannoi函數(shù)的位置,繼續(xù)向下執(zhí)行。
19.調(diào)用打印函數(shù)printf("%d->%d\n",a,c),這個(gè)時(shí)候打印函數(shù)的參數(shù)a,c是n=2的時(shí)候第5次調(diào)用hannoi函數(shù)傳遞的參數(shù),也就是a(5),c(5),追到原始值是b(1),c(1),即6,7.打印結(jié)果是6->7
20.程序繼續(xù)向下執(zhí)行,調(diào)用hanoi(n-1,b,a,c)函數(shù),這個(gè)時(shí)候程序是從n=2的hannoi函數(shù)位置繼續(xù)向下執(zhí)行的,參數(shù)是:n=1,a(7)=b(5),b(7)=a(5),c(7)=c(5)
21.第七次進(jìn)入hannoi函數(shù),進(jìn)行if(n==1)判定,符合條件,執(zhí)行打印函數(shù)printf("%d->%d\n",a,c),這個(gè)時(shí)候打印函數(shù)的參數(shù)是第七次調(diào)用hannoi函數(shù)的參數(shù),也就是a(7),c(7)即b(5),c(5),追到原始值5,7打印結(jié)果是:5->7
22.程序最后再一次返回兩次調(diào)用hanoi(n-1,b,a,c)函數(shù)的位置,但是每一次返回都沒有其他動(dòng)作,直至程序結(jié)束。

程序分析的結(jié)果十分復(fù)雜和繁瑣,而且這僅僅是三層盤子。同時(shí)由于自己的畫圖水平不好,所以也沒有畫流程圖,同時(shí)網(wǎng)上好多大牛說是可以用樹的想法去想漢諾塔問題,但是我沒學(xué)習(xí)到樹,所以只能用上面那種最笨額方法了。


六、全排列的遞歸調(diào)用

1.問題的提出:假定有三個(gè)元素a,b,c,那么這三個(gè)元素的全排列有六種方式:abc,acb,bac,bca,cba,cab。那么兩個(gè)元素的全排列的是ab,ba,一個(gè)元素的全排列就是元素本身,所以一個(gè)元素的全排列就是遞歸的邊界條件。

2.我們這里以三個(gè)元素的全排列,程序例程如下:

#include <stdio.h>void permutation(char s[], int b, int e) {if( (0 <= b) && (b <= e) ){if( b == e ){printf("%s\n", s);}else{int i = 0;for(i=b; i<=e; i++){char c = s[b];s[b] = s[i];s[i] = c;permutation(s, b+1, e);c = s[b];s[b] = s[i];s[i] = c;}}} }int main() {char s[] = "abcd";permutation(s, 0, 3);return 0; }

?程序的遞歸算法框圖如下所示:

?

?由于我們傳進(jìn)子函數(shù)的四個(gè)字符的字符數(shù)組,所以這里我們直接執(zhí)行else部分的函數(shù),首先執(zhí)行for循環(huán),for循環(huán)從i=b開始,這樣我們第一輪for循環(huán)先做的交換代碼如下:

char c = s[b]; s[b] = s[i]; s[i] = c;

其實(shí)這個(gè)時(shí)候我們沒有完成任何交換,然后繼續(xù)調(diào)用permutation(s, b+1, e)函數(shù),再次進(jìn)入for循環(huán),這個(gè)時(shí)候for循環(huán)是從i=b+1開始的,這個(gè)時(shí)候執(zhí)行交換部分的代碼還會(huì)完成另一個(gè)元素的交換。實(shí)質(zhì)上這個(gè)交換部分的代碼完成的就是將每一個(gè)元素作為第一個(gè)位置的作用,然后再進(jìn)行其他操作。
for循環(huán)里的第二部分主要代碼如下:

c = s[b]; s[b] = s[i]; s[i] = c;

這一部分代碼的主要作用是在每一個(gè)permutation(s, b+1, e)進(jìn)行彈出操作的時(shí)候開始執(zhí)行,這樣我們就可以對(duì)后面的數(shù)進(jìn)行全排列了。我們也就完成圖示的全排列操作。具體的遞歸過程可以例程單步調(diào)試來進(jìn)行理解。

總結(jié)

以上是生活随笔為你收集整理的C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。