目錄
1、. 函式的嵌套呼叫和鏈式訪問
1.1函式的嵌套呼叫
1.2函式的鏈式訪問
2、函式的宣告與定義
2.1函式的宣告
2.2 函式定義
3、函式遞回
3.1遞回的定義
3.2遞回的條件
例題1:根據下面遞回函式:呼叫函式Fun(2),回傳值是多少?
例題2:遞回方式實作列印一個整數的每一位
3.3遞回與迭代
例題1 求n的階乘
例題2 求第n個斐波那契數列
例題 3撰寫一個函式 reverse_string(char * string)(遞回實作)
例題4 寫一個遞回函式DigitSum(n),輸入一個非負整數,回傳組成它的數字之和
1、. 函式的嵌套呼叫和鏈式訪問
1.1函式的嵌套呼叫
函式與函式之間可以嵌套呼叫,但不可以嵌套定義,我們來仔細分析以下幾個例子,
#include <stdio.h>
void test2()
{
printf("MIT\n");
}
void test1()
{
int i = 0;
for (i = 0; i < 3; i++)
{
test2();//在test1函式中呼叫test2函式;
}
}
int main()
{
test1();//呼叫test1函式;
return 0;
}

可以看到,主函式呼叫test1 而test1函式回圈呼叫了test2函式列印MIT 也就是說 在函式體內部呼叫其他自定義函式,就是所謂的函式嵌套呼叫,但函式不能嵌套定義,以下是錯誤例子,

1.2函式的鏈式訪問
把一個函式的回傳值作為另外一個函式的引數,就是鏈式訪問,我們來看幾個例子,
#include<stdio.h>
#include<string.h>
int main()
{
printf("%d", strlen("abc"));//strlen("abc")的回傳值作為printf函式的引數
return 0;
}
來思考以下這段代碼
#include<stdio.h>
#include<string.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}//這段代碼的結果是4321 需要注意的是,printf函式以它列印成功的字符個數作為回傳值 具體分析程序如下,

2、函式的宣告與定義
2.1函式的宣告
1. 告訴編譯器有一個函式叫什么,引數是什么,回傳型別是什么,
2. 函式的宣告一般出現在函式的使用之前,要滿足先宣告后使用,
3. 函式的宣告一般要放在頭檔案中的,
2.2 函式定義
函式的定義是指函式的具體實作,交待函式的功能實作,
3、函式遞回
3.1遞回的定義
程式呼叫自身的編程技巧稱為遞回,其核心思想就是分解,把大事層層剝離,大事化小,
3.2遞回的條件
1、具有限制條件,當不滿足這個限制條件時退出遞回,
2、每次遞回呼叫之后越來越接近這個限制條件,
下面我們通過幾個例子來理解遞回,
例題1:根據下面遞回函式:呼叫函式Fun(2),回傳值是多少?
int Fun(int n)
{
if(n==5)
return 2;
else
return 2*Fun(n+1);
}
分析程序如下:
Fun(2)--->回傳16
return 2*Fun(3) 2*8=16
|__Fun(3):8
return 2*Fun(4) 2*4=8
|__Fun(4):4
return 2*Fun(5) 2*2=4
|__Fun(5):2
return 2
例題2:遞回方式實作列印一個整數的每一位
void Print(unsigned int n)
{
if (n > 9)
{
Print(n / 10);//遞回程序,自己呼叫自己,
}
printf("%d ", n % 10);//要注意這里不能加上else
}
int main()
{
unsigned int num = 0;
scanf("%u",&num);
Print(num);//對這個函式具體的遞回程序,我們可以用數字123理解 具體分析如下圖
return 0;
}


3.3遞回與迭代
我們先通過幾個例子來理解,
例題1 求n的階乘
int Fun(int n)//遞回實作求n的階乘
{
if (n <= 1)
return 1;
else
return n * Fun(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = 1;
ret = Fun(n);
printf("%d\n", ret);
}
例題2 求第n個斐波那契數列
int Fci(int n)//遞回方式實作斐波那契數列
{
if (n <= 2)
return 1;
else
return Fci(n - 1) + Fci(n - 2);
}
int main()
{
int n = 0;
int ret = 0;
while (~scanf("%d", &n))
{
ret = Fci(n);
printf("ret=%d\n", ret);
}
return 0;
}
但是,以上兩種實作方式,均是不考慮n非常大的情況,如果n非常大,則會導致堆疊溢位,我們可以通過一個例子來理解一下,例如,我們可以來計算一下 當n=40的時候,第三個斐波那契數被重復計算了幾次,


可見,當n非常大的時候,程式進行了大量重復計算,效率比較低,那我們該怎么優化這個代碼呢?這時候我們想到迭代,以下是通過迭代的方法來實作斐波那契數列,
int Fib(int n)//非遞回實作
{
int a = 1;
int b = 1;
int c = 1;
while (n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
int ret = 0;
while (~scanf("%d", &n))
{
ret = Fib(n);
printf("ret=%d\n", ret);
}
return 0;
}
例題 3撰寫一個函式 reverse_string(char * string)(遞回實作)
實作:將引數字串中的字符反向排列,不是逆序列印,
**要求:**不能使用C函式庫中的字串操作函式,
void reverse_string(char* arr)
{
char *left = arr;
char *right = arr+strlen(arr)-1;//這是用非遞回方式來實作,
while(left<right)
{
char t = *left;
*left = *right;
*right = t;
left++;
right--;
}
}
實作思路就是創建兩個指標(首元素跟最后一個元素);left作為左端點,right作為右端點,首末兩個元素交換,則通過創立臨時變數,因為不是一次交換,所以需要一個回圈,回圈的條件是左端點小于右端點,
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
void reverse_string(char* str)
{
char tmp = *str;
int len = my_strlen(str);
*str = *(str + len - 1);//遞回方式來實作,
*(str + len - 1) = '\0';
if (my_strlen(str + 1) >= 2)
{
reverse_string(str + 1);
}
*(str + len - 1) = tmp;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s\n", arr);
return 0;
}
對于字串“abcdef”,遞回實作的大概原理: 1. 交換a和f, 2. 在兩個字符交換后,再看成對中間四個字符實作逆序,大事化小,具體程序如下
1、創立一個臨時變數,把a賦給這個變數;
2、把f付給a原來所在的位置;
3、將原來f所在位置賦值為'\0',因為如果不改成\0而將a直接傳在這個位置,在下一次逆序時,就變成bcdea的逆序了,
4、將bcde看成要逆序的內容;
5、a移到f原來的位置,
具體原理如下

例題4 寫一個遞回函式DigitSum(n),輸入一個非負整數,回傳組成它的數字之和
例如,呼叫DigitSum(1729),則應該回傳1+7+2+9,它的和是19
輸入:1729,輸出:19
int DigitSum(int n)
{
if (n > 9)
return DigitSum(n / 10) + n % 10;//n%10是為了獲得這個數字的每一位
else
return n;
}
int main()
{
int n = 0;
int ret = 0;
while (~scanf("%d", &n))
{
ret = DigitSum(n);
printf("ret=%d\n", ret);
}
return 0;
}

對DigitSum(1729),我們采用大事化小思路,可以看成DigitSum(172)+9,而DigitSum(172)則又可以分解為DigitSum(17)+2+9 以此類推,因此 在DigitSum(n / 10) + n % 10中,DigitSum(n / 10)可以實作 DigitSum(172) DigitSum(17) 而n%10則獲得了每一位數字,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/351027.html
標籤:其他
上一篇:資料結構--堆疊
