計算機編程必備技巧——使用遞歸

2021-02-08 努力的浩浩

1、引言

今天我們來學習遞歸,如果單說學習算法, 遞歸併不能說是算法,而是一種編程的手法,為什麼現在要學習這個呢?因為後面在學習其他算法時,要牽涉一些遞歸的調用方法,是為以後理解學習的內容做好鋪墊。

遞歸方法作為一種優雅的解題方法,是大多數程式設計師比較喜歡的編寫方式之一。遞歸把程式設計師分為三類:一種是恨它的,第二種是愛它的,最後一種是恨了一段時間之後接觸之後又愛上了它。我平時編寫代碼的時候可能很少用到,但我對遞歸的印象還是蠻喜歡的。今天就來比較深入的學習一下遞歸的相關知識吧。

2、遞歸

2.1.1 什麼是遞歸

遞歸說白了就是用一個函數不斷調用自己的過程,遞歸的使用可以讓代碼邏輯很清晰,但並沒有實質性能的提升。實質上,在有些情況下,使用循環的性能可能會更佳。

2.1.2 遞歸中的兩大元帥

上面介紹到遞歸是一個函數不斷調用自己的過程,但如果沒有限制結束調用的條件,就會讓遞歸無限的循環下去。於是編寫遞歸函數時,必須告訴函數什麼時候要停止遞歸調用。這就引出了遞歸的兩大元帥,分別為基線條件(base case)和遞歸條件(recursive case)。遞歸條件是指讓函數調用自身,而基線條件就是通知函數不要再調用自己,從而避免了無限循環。

2.2.1 棧

使用遞歸必須需要了解棧的概念,棧是一種簡單的數據結構,它的特點可以舉一個簡單的例子你就明白了。在餐廳吃飯的時候,我們通常是在收銀臺進行點餐,然後點餐付款成功之後會將信息傳送給後廚師傅手裡,以一個先來後到的原則,廚師每次看到的信息都是最早來點餐的人的信息,而且做完之後便刪掉了這個點餐信息,接著去做下一個人點的餐,而收銀員每回都只在待做餐列表中添加點餐信息,而不管究竟現在有多少點餐信息。因此這個待做餐列表就只有兩種操作:存入和刪除。棧這種數據結構就是這麼一個工作原理,理解了這個原理之後,我們就可以繼續後面的內容了。

2.2.2 調用棧

計算機在內部使用被稱為調用棧的棧。以一段代碼解釋一下計算機是如何調用棧的。

public static void main(String[] args) {

//調用方法1

Greet("努力的浩浩");

}

//定義一個問候的方法1

private static void Greet(String name){

System.out.println("hello,"+name+"!");

Greet2(name);

System.out.println("getting ready to say bye");

bye();

}

//定義一個問候的方法2

private static void Greet2(String name){

System.out.println("how are you,"+name+"?");

}

//定義一個再見的方法

private static void bye(){

System.out.println("ok,bye!");

}

下面詳細介紹調用函數時內存的變化情況。

如main方法中調用了Greet("努力的浩浩");計算機會為該方法開闢一塊內存空間,且存儲變量name的值為"努力的浩浩",接下來執行該方法,列印出"hello,努力的浩浩!"之後,程序開始執行Greet2的方法。

當然,計算機也會為這個方法開闢一塊內存空間,並且存儲變量name的值為"努力的浩浩"。那麼這兩個方法執行的過程中,計算機就開闢了兩個內存單元,於是乎計算機採用棧存儲這些內存塊,其中第二個內存單元位於第一個內存塊的上方,列印出"how are you,努力的浩浩?"之後,從Greet2()方法中返回,此時,棧頂被彈出,於是Greet()中的變量成為了棧頂,而繼續執行程序,應先列印出"getting ready to say bye"之後,再調用bye()列印出"ok,bye!"的語句。

上面這個棧由於存儲了多個函數的變量,稱為了調用棧。

2.2.3 遞歸調用棧

遞歸函數其實也是使用的是調用棧,我們先來定義一個遞歸函數,該函數完成的功能就是求數的階乘,函數名為factorial,

如factorial(5)記作5!,其定義為5!= 5 x 4 x 3 x 2 x 1。下面是遞歸函數階乘的代碼!

//定義一個遞歸函數階乘

private static int factorial(int number){

if(number == 1)

{

return 1;

}

else {

return number * factorial(number - 1);

}

}

下面以一幅圖來講解遞歸調用棧的原理,詳細分析fact(3)調用棧是如何變化的。

第一次調用
第二次調用
返回

2.3 溫馨提示

使用棧雖然很方便,但是也有很大代價:如果要存儲信息可能需要大量內存,每個函數調用都將佔用內存,如果棧摞的很高必將

導致計算機存儲大量函數調用的信息。這個時候怎麼辦呢?

有兩種解決方案:

1、使用循環

2、使用尾遞歸(這個我也不懂是啥,書上就是這麼寫的,並非所有程式語言都支持尾遞歸)

相關焦點

  • 計算機編程必備技巧——遞歸使用
    1、引言 今天我們來學習遞歸,如果單說學習算法, 遞歸併不能說是算法,而是一種編程的手法,為什麼現在要學習這個呢?因為後面在學習其他算法時,要牽涉一些遞歸的調用方法,是為以後理解學習的內容做好鋪墊。
  • 少兒Python編程培訓手冊系列之——函數的定義及遞歸思想
    前面在C語言教學視頻中講過,函數是一段獨立的子程序,由相關代碼組成,可以重複多次使用。有了函數:模塊化編程,可以使代碼的層次更清晰。函數分系統函數(內置函數、內建函數)和自定義函數。這裡再分享一些常用的內置函數:bin() 十進位轉二進位oct() 十進位轉八進位,以0開頭的數字hex() 十進位轉十六進位,以0X開頭的數字計算機採用的是二進位計數系統,運算速度會很快。而人類採用的是十進位的計數系統。除此之外,還有八進位、十六進位數制系統。通過這些函數就可以獲取到對應的轉換數值,非常方便。sum()是求和函數。
  • LabVIEW編程實例:計算階乘,學習for循環+移位寄存器+遞歸調用
    也可以用遞歸方式定義為如下形式:n!=(n-1)!×n,且0!=1根據這兩種定義方式,下面給出在LabVIEW中編程實現求解n!的兩種方法。階乘求解方法2:使用遞歸調用方法實現這種方法根據階乘的遞歸方式的定義進行實現。遞歸VI程序顧名思義是指一個VI在運行中可以調用自身的VI程序,在LabVIEW中可以容易的實現遞歸VI程序的設置。
  • memoization:讓遞歸算法更高效
    21CTO導讀:本文為學習如何使用稱為memoization的技術通過動態編程使遞歸算法變得高效。
  • python算法遞歸於尾遞歸!
    遞歸概念遞歸:程序調用自身的編程技巧稱為遞歸( recursion)。用一種通俗的話來說就是自己調用自己,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的、但是規模較小的問題來求解,當問題小到一定規模的時候,需要一個遞歸出口返回。
  • Python進階之遞歸函數的用法及其示例
    遞歸是指函數/過程/子程序在運行過程序中直接或間接調用自身而產生的重入現象。在計算機編程裡,遞歸指的是一個過程:函數不斷引用自身,直到引用的對象已知。使用遞歸解決問題,思路清晰,代碼少。但是在主流高級語言中(如C語言、Pascal語言等)使用遞歸算法要耗用更多的棧空間,所以在堆棧尺寸受限制時(如嵌入式系統或者內核態編程),應避免採用。所有的遞歸算法都可以改寫成與之等價的非遞歸算法。
  • 如何理解遞歸?
    作者:劉半仙  來源:http://1t.click/eWx# 遞歸是什麼?定義:程序調用自身的編程技巧稱為遞歸。它分為調用階段和回退階段,遞歸的回退順序是它調用順序的逆序。遞歸使用的是選擇結構:if/switch。而for,while,do while使用的是循環結構。
  • 學習編程的人,怎麼能不知道什麼叫遞歸?
    話不多說,開始今天的學習:遞歸:不要看這個名字好像挺高大上的樣子,其實理解起來還是蠻容易的。在學習遞歸之前,我們先學習下目錄的遍歷,遞歸的主要使用途徑就需要它。其中上述兩種方法中:for循環的方法要更加地實用簡潔,使用遞歸的話效率會很低,一般使用的很少。那為何還要學遞歸?因為它在文件操作中會使用到它,並且既然是學習Java,也有必要理解下遞歸的概念。
  • 為什麼說學計算機科學比學編程重要得多?計算機專業學生看過來
    如果說教授編程是授之以魚,那麼教授計算機科學就是授之以漁。為什麼說學習計算機科學比學會編程要重要得多?來聽聽Yevgeniy Brikman的解釋。相反,有些課程只是教會你如何使用一種工具,比如如何駕駛某種型號的飛機。類似的,我們應該專注於教授計算機科學,而不僅僅是編程:前者能夠教會我們一般性的思考方式,而後者只是一種特定的工具。
  • Python 進階之遞歸函數一點都不難!
    出品 |  AI科技大本營(ID:rgznai100)本篇文章主要介紹了Python進階之遞歸函數的用法及其示例,現在分享給大家,也給大家做個參考
  • 什麼是計算機編程?
    導語隨著科技水平的發展,編程已不僅僅是專業程式設計師的職業技能,更是每個人必備的基本技能之一。但對於大多數人來說,編程還是顯得很「專業」。我想把針對初學者的計算機編程和軟體開發放在一起介紹,從計算機編程開始,到學習計算機程式語言,接著我會談到軟體和軟體開發,最後,我會談談計算機編程當前的趨勢和未來。如果你正在考慮進入編程領域,或者只是對學習編程感興趣,這些將為你提供一個沒有過多技術用語的概要介紹。
  • 我是計算機專業的,身邊沒有一個是在三年級前讓孩子學編程的……
    1我自己學編程的經歷我們大一剛進校,就開了一門C++程序設計的課,老師一上來只簡單介紹了一下面向對象程序設計,然後就開始教怎麼編程。一學期下來,這門課我是聽得雲裡霧裡,但老師講的那些語法指令、各種排序方法、什麼迭代遞歸遍歷等等我還是都記住了,期末考試還考了90分。
  • 高斯求和如何用遞歸實現,Python詳解遞歸那些事,看這1篇足夠!
    這個大牛把遞歸的使用提升到了「神」的高度。03哪些問題可以使用遞歸方法來求解?專業一點的內容這些問題很通俗易懂,還有哪些經典編程案例呢?在計算機中,函數調用時通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,就會導致棧溢出。
  • 藍橋杯簡單java遞歸算法
    首先先簡介下遞歸算法:遞歸算法(英語:recursion algorithm)在計算機科學中是指一種通過重複將問題分解為同類的子問題而解決問題的方法。遞歸式方法可以被用於解決很多的計算機科學問題,因此它是計算機科學中十分重要的一個概念。
  • 這可能是最全的計算機程式語言列表了,你知道多少?
    Game Maker 語言它是一種解釋型的計算機程式語言,旨在與 Game Maker 配合使用—— Game Maker 是一種遊戲製作應用程式。荷蘭計算機科學家馬克·奧馬斯(Mark Overmars)設計了這種語言。
  • 計算機編程雙語班開放,讓編程和英文齊飛
    ②培養專注力和細心度調試程序和排錯是編程中必不可少的步驟,有時只是少打一個字母或分號,程序都無法運行通過。排錯過程需要聚精會神,可以有效改正孩子粗心馬虎的小毛病。③提高抽象思維能力編程是人類和機器交流的語言。
  • 具體數學:計算機科學基礎(第2版) 電子書
    《具體數學:計算機科學基礎(第 2版)》是一本在大學中廣泛使用的經典數學教科書。書中講解了許多計算機科學中用到的數學知識及技巧,教你如何把一個實際問題一步步演化為數學模型,然後通過計算機解決它,特別著墨於算法分析方面。其主要內容涉及和式、整值函數、數論、二項式係數、特殊的數、生成函數、離散概率、漸近式等,都是編程所必 備的知識。
  • 最受歡迎的25本計算機編程書籍
    電腦程式的構建和解釋《電腦程式的構建和解釋(原書第2版)》1984年出版,成型於美國麻省理工學院(MIT)多年使用的一本教材,1996年修訂為第2版。在過去的二十多年裡,《電腦程式的構建和解釋(原書第2版)》對於計算機科學的教育計劃產生了深刻的影響。第2版中大部分重要程序設計系統都重新修改並做過測試,包括各種解釋器和編譯器。
  • 關於編程,系列書籍
    書中專門討論了線性規劃,介紹了動態規劃的兩個應用,隨機化和線性規劃技術的近似算法等,還有有關遞歸求解、快速排序中用到的劃分方法與期望線性時間順序統計算法,以及對貪心算法元素的討論。此書還介紹了對強連通子圖算法正確性的證明,對哈密頓迴路和子集求和問題的NP完全性的證明等內容。
  • 詳細解讀Python 遞歸函數!
    遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。/sum.py循環求和: 5050遞歸求和: 5050遞歸函數的優點是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,但循環的邏輯不如遞歸清晰。***使用遞歸函數需要注意防止棧溢出。在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。