[英]How does this recursive function work in C++?
I'm currently taking a class for c++ and we are learning about recursion and in class my professor used this function as an example of recursion, the function is meant to return the smallest digit in a number and is:
int smallD(int n) {
if (n < 10) return n;
int x = smallD(n / 10);
if (x < n % 10) return x;
else return n % 10;
}
我對將 x 設置為遞歸調用的工作原理感到困惑,function 會不會一直運行 n / 10 直到 n < 10,我真的不明白這個概念,並且可以使用一些指針來說明這個 function 是如何工作的。
這里有一些有助於理解遞歸的東西。 添加打印語句以觀察代碼,因為它遞歸地調用自身並傳遞和“縮進級別”以提供幫助。
獲取原始的縮小代碼並將其擴展為更具可讀性的內容,並為其添加額外的調試信息。
int smallD(int n, const std::string& indent) {
cout << indent << "enter: smallD(n=" << n << ")" << endl;
if (n < 10) {
cout << indent << "n < 10 => returning: " << n << endl;
return n;
}
cout << indent << "about to recurse inovking smallD(" << n / 10 << ")" << endl;
int x = smallD(n / 10, indent+" "); // grow the indent by 2 spaces
cout << indent << "return from recursion, result is: " << x << endl;
cout << indent << "x=" << x << " n=" << n << " n%10=" << n % 10 << endl;
if (x < n % 10) {
cout << indent << "x is less than n%10, returning: " << x << endl;
return x;
}
cout << indent << "x is greater than or equal n%10, returning: " << n%10 << endl;
return n % 10;
}
讓我們通過調用smallD(8942468, "")
來嘗試一下
enter: smallD(n=8942468)
about to recurse inovking smallD(894246)
enter: smallD(n=894246)
about to recurse inovking smallD(89424)
enter: smallD(n=89424)
about to recurse inovking smallD(8942)
enter: smallD(n=8942)
about to recurse inovking smallD(894)
enter: smallD(n=894)
about to recurse inovking smallD(89)
enter: smallD(n=89)
about to recurse inovking smallD(8)
enter: smallD(n=8)
n < 10 => returning: 8
return from recursion, result is: 8
x=8 n=89 n%10=9
x is less than n%10, returning: 8
return from recursion, result is: 8
x=8 n=894 n%10=4
x is greater than or equal n%10, returning: 4
return from recursion, result is: 4
x=4 n=8942 n%10=2
x is greater than or equal n%10, returning: 2
return from recursion, result is: 2
x=2 n=89424 n%10=4
x is less than n%10, returning: 2
return from recursion, result is: 2
x=2 n=894246 n%10=6
x is less than n%10, returning: 2
return from recursion, result is: 2
x=2 n=8942468 n%10=8
x is less than n%10, returning: 2 // <== this is the final result
因此,希望這將幫助您了解遞歸的工作原理。
遞歸函數的工作方式與非遞歸函數完全相同。
一個常見的錯誤是嘗試一次考慮所有遞歸調用,就好像它們有一個共享的 state,但理解遞歸 function 的一個關鍵因素實際上是忽略遞歸而只是“本地思考”。
也許通過一個例子可以澄清事情。
讓我們看一下smallD(321)
,用它的值替換 function 主體中的n
。
smallD(321)
if (321 < 10) return 321;
int x = smallD(321 / 10);
if (x < 321 % 10) return x;
else return 321 % 10;
第一個條件顯然是錯誤的,為了確定x
,我們需要smallD(321/10)
,即smallD(32)
。
smallD(32)
if (32 < 10) return 32;
int x = smallD(32 / 10);
if (x < 32 % 10) return x;
else return 32 % 10;
第一個條件再次為假,所以我們繼續使用smallD(32/10)
。
smallD(3)
if (3 < 10) return 3;
int x = smallD(3 / 10);
if (x < 3 % 10) return x;
else return 3 % 10;
現在第一個條件為真,所以這里的結果顯然是3
。
現在我們可以返回 go 並在每個等待的調用中使用x
的值。
smallD(32)
...
if (3 < 32 % 10) return 3;
else return 32 % 10;
並且3 < 32 % 10
是假的,所以我們將32 % 10
- 2
返回給調用者。
smallD(321)
...
if (2 < 321 % 10) return 2;
else return 321 % 10;
並且2 < 321 % 10
是假的,所以我們返回321 % 10
,即1
。
你的直覺並沒有完全消失:function 確實“繼續運行 n/10 直到 n <10”——但它在對同一個 function 的不同調用中。
您的程序保留了一堆函數調用。 您調用的每個 function 都會在當前堆棧中的所有內容之上放置一個(所謂的)“框架”。 在該框架內“活動”所有“屬於”該 function 調用的變量。 當 function 退出時,它會從堆棧中刪除自己的幀。 當前正在執行的函數的框架位於棧頂。 所以,讓我們看看如果你調用smallD(123)
會發生什么:
你從堆棧上的其他東西開始,至少是你的main()
。 您對 smallD(123) 的調用將smallD(123)
smallD(123)
框架放在堆棧的頂部。 該幀包含變量n = 123
。 讓我們將此幀堆棧稱為幀A
。
由於n >= 10
,您的smallD(123)
調用smallD(123 / 10)
,即smallD(12)
(整數除法基本上在 C++ 中截斷)。 因此,您將另一個框架放在堆棧頂部。 此堆棧幀對應於smallD(12)
並包含變量n = 12
。 我們稱這個堆棧幀B
。
同樣, n >=10
,所以調用smallD(12 / 10)
(即smallD(1)
)發生。 為這個新調用創建了一個堆棧幀(稱為C
),其中n = 1
。
現在n < 10
成立! 最后的 function 調用(在堆棧幀C
中)返回值1
並刪除其自己的堆棧幀(幀C
)。
堆棧幀B
(其中n = 12
)現在位於頂部,並且smallD(12)
繼續執行。 由於堆棧幀C
已返回1
,因此堆棧幀B
現在包含x = 1
。 比較(x < n % 10)
為真 ( 1 < 2
),堆棧幀B
返回x = 1
。
同樣的情況再次發生在堆棧幀A
中,堆棧幀A
(對應於我們最初的smallD(123)
調用)返回1
。
所以你看,確實發生了“直到 n < 10 的除法”,但是在不同的(遞歸!)調用smallD
。
您可以將幾乎每個遞歸調用分解為基本案例(最簡單的)和遞歸案例。 在這種情況下:
if (n < 10) return n;
沒有其他數字可以比較,所以直接返回。x = smallD(n / 10)
了解除最后一位之外的所有數字中的最小數字是什么為了更好地理解調用背后的過程,您可以打印一些信息並觀察它。 嘗試這樣的事情:
int smallD(int n) {
if (n < 10){
std::cout << "Base case. Return " << n << std::endl;
return n;
}
std::cout << "Recursive case: " << n << std::endl;
std::cout << "Compare " << n % 10 << " with smallest of " << n/10 << std::endl;
int x = smallD(n / 10);
int ret;
if (x < n % 10) ret = x;
else ret = n % 10;
std::cout << "Smallest of " << n << " is " << ret << std::endl;
return ret;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.