網站首頁 編程語言 正文
遞歸的認識
基本認識:
1.首先遞歸的本質還是函數調用,也要形成和釋放棧幀。
2.函數的調用是有成本的,這個成本在時間和空間上表現為函數棧幀的形成和銷毀。
3.遞歸就是 不斷形成棧幀和銷毀的過程。
理論認識:
1.內存和cpu中的資源有限,也就決定啦,合理的遞歸是絕對不可以無限遞歸下去的。
2.遞歸不是什么時候都可以使用的,而是要滿足自身的場景,即目標函數的子問題可以用該算法解決,本質是分治的思想。
3.遞歸的核心:大事化小,遞歸出口。
main函數可以遞歸嗎
相信有些讀者就在疑惑啦?main函數是主函數呀,這個怎么可以自己調用自己呢?
實際上,main函數本質也是函數,所以也就會形成棧幀,所以是可以自己調用自己的。
代碼和運行結果如下:
int main()
{
printf("胡楊樹下\n");
Sleep(100);//睡眠0.1秒
main();
return 0;
}
結果顯示是可以調用的,那么我們也能過看出來,這個main函數的遞歸是不會自動停止的,停止時就是發生棧溢出,那么函數的棧幀是怎么形成的呢?
是最下面的main函數進行調用自身形成棧幀,如圖示,我們可以看出,這些函數調用都開辟了空間,所以要占用內存,而且形成棧幀后需要釋放,形成和釋放過程中有時間消耗。這也就是遞歸有成本的原因。
遞歸核心思想講解
我們在平時中見過這個題目,叫做求字符串長度。
這個我們可以用遞歸的寫法求解,順帶我們看下遞歸的核心。
首先假設我們求的字符為 "abcdefg123",我們用遞歸的解法可以轉化為,1+"bcdefg123",把"bcdefg123"進而再轉化為1+"cdefg123",進行求解,如圖示:
經過一次次的大事化小,我們最后把問題變成了,求1+空字符串的長度,這個其實也就是我們想要的遞歸出口,當沒有字符時我們就該結束啦。
代碼如下:
int My_strlen(const char *str)
{
if (*str == '\0')//函數出口
{
return 0;
}
return 1 + My_strlen(str + 1);//繼續
}
int main()
{
int len = My_strlen("abcdefg123");
printf("len = %d\n", len);
return 0;
}
遞歸的缺點
我們來看下遞歸的另外一個經典例子,第n個菲波那切數列的實現
首先菲波那切數列是前兩個數之和等于第三個數,第一個和第二個我們設定為1,那么這個數列為 1,1,2,3,5,8,13....等等,那我們要求第n個斐波那契數列的話,只要轉化為求前兩個數的和就好了,最后的遞歸出口為第一個或者第二個數時停止,結束函數。
代碼如下:求第十個菲波那切數
int fib(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
return fib(n - 1) + fib(n - 2);
}
int main()
{
printf("fib(%d) = %d\n", 10, fib(10));
return 0;
}
我們如果求的 n 的數字比較大就會非常慢。這個本質就是上述說的成本問題。
如果求的是第42個菲波那切數呢?這次我們把時間也計算上。
int fib(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 42;
double start = GetTickCount();
int x = fib(n);
double end = GetTickCount();
printf("fib(%d) = %d count = %.1f S\n", n,x,(end - start)/1000);
return 0;
}
我們可以看出第42個時就已經10秒了,這個很長時間啦。我們用全局變量接收下次數,那我們看看他計算了多少次第3個菲波那切數計算了幾次? 計算了大概1億多次,所以遞歸的重
復計算是非常多的。
我們看個圖示:
其中單單是第六個菲波那切數就計算了3次,這個就很夸張啦。
所以遞歸的特點是代碼簡單,但是調用上可能會有大的成本。
最后一點就是:循環和遞歸是一定可以相互轉化的。只不過有些時候轉化會比較麻煩。
原文鏈接:https://huyang.blog.csdn.net/article/details/124612267
相關推薦
- 2023-01-19 使用python檢查值是否已經存在于字典列表中_python
- 2022-07-10 Popconfirm氣泡確認框無法觸發confirm函數
- 2022-06-25 EF?Core的CRUD(增刪改查)基本操作_實用技巧
- 2023-05-17 Android?Lock鎖實現原理詳細分析_Android
- 2022-03-06 C語言之快速排序算法(遞歸Hoare版)介紹_C 語言
- 2022-01-30 使用ref手動改變antd的搜索框Input.Search的搜索內容
- 2022-12-09 react?hooks?UI與業務邏輯分離必要性技術方案_React
- 2022-05-16 Qt數據庫應用之通用數據庫同步_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支