高斯求和如何用遞歸實現,Python詳解遞歸那些事,看這1篇足夠!

2020-12-11 python高手養成

前段時間,有小夥伴留言,想了解一些有關Python遞歸函數的知識。最近,小編也惡補了一些這方面的內容。說實話,對於遞歸的認識過程,確實能讓我們從中探索出一些很有意思的內容。今天,我們來一探究竟。

01什麼是遞歸?

關於遞歸,網上有一大堆描述資料,很專業,也很詳細。感興趣的小夥伴可以隨手搜一搜。但是,用我們自己聽得懂的話來講,就是「自己調用自己」的方式;那麼,很容易理解,遞歸函數就是在函數實現過程中,直接或間接調用了函數本身的函數

【舉個例子】我們知道,國外有一個很出名的數學家高斯,在他9歲的時候,用很短的時間計算出了小學老師布置的任務,對自然數從1到100的求和。

數學家高斯

他所使用的方法是:對50對構造成和101的數列求和(1+100,2+99,3+98……),同時得到結果:5050。

數學小王子

「數學王子」並非浪得虛名,他9歲時的思維方式確實很獨特。在數學方面,以他名字「高斯」命名的成果達110個,屬數學家中之最。

頗有建樹的數學王子

我們今天不討論這個,回到正題,如何用遞歸的思路解決這個問題呢?作為普通人,我們思考這個問題的方式應該是這樣的:

典型遞歸問題的解題思路

很簡單,不是嗎?解決遞歸問題就三點:

【首先】確定你要幹啥?就是定義一個函數fn(n),你要用fn(n)實現哪個功能?

【其次】確定限定範圍!不要被參數n嚇住,它沒那麼可怕,僅僅代表一個數而已。這個限定範圍就是遞歸開始和結束的條件(即上例中的1和100)。

【最後】確定函數等價關係。遞歸的過程實際是不斷縮小參數的過程,這一步的終極目標就是確定參數n和參數n-1之間的關係。

方法步驟很重要

一位從11歲就開始寫程序的「神童」L Peter Deutsch這樣描述遞歸:「Iterative is human, recursive is God.」翻譯過來就是「迭代的是人,遞歸的是神」。這個大牛把遞歸的使用提升到了「神」的高度。

迭代與遞歸

其實也沒這麼誇張,遞歸作為一種奇妙的思維方式,我們總是驚嘆於它描述問題的能力和編寫代碼的簡潔(在實際應用中,它確實能減少很多不必要的代碼,看這個例子的Python實現)。

但在實際應用中,要想真正領悟遞歸的精髓,達到靈活運用的境界,其實並不容易。這其實就是大牛將遞歸提升到「神」的高度的真正原因。

我們先來看下上面例子的Python實現。

02Python解決高斯求和問題!

問題理清楚了,實現起來就簡單多了!我們將求解n以內自然數之和的問題,定義一個函數fn(n),n是需要求解的最大數(此例中n為100)。那麼,解決該問題有以下2種情況:

當n=1時,fn(1) = 1;當n>1時,fn(n) = fn(n-1) + n程序原始碼如圖所示

例子的Python實現

沒錯,幾行代碼搞定了,上例的輸出結果就是5050。

03哪些問題可以使用遞歸方法來求解?

理論上來講,類似這樣的問題可以使用遞歸方法來解決:

首先,大問題可以分解為相同方法解決的一系列小問題。而大問題解決需要一系列小問題解決作為前提;

其次,有明確的界定範圍,前提必須是最終的大小問題有解。

舉幾個現實中的例子

很繞口,舉幾個生活方面的例子,如果碰上問題與這個例子相似,那麼,用遞歸方法解決就沒錯。

案例一:剝洋蔥。我想要拿到洋蔥芯,別問我為什麼要拿?現實是我只能從洋蔥的最外層入手,一層一層剝。而剝洋蔥的方法各層都一樣。

案例二:類似俄羅斯套娃的問題。我想拿到最裡面最小的娃娃,得先打開最外層的套娃。而我每次打開套娃使用的方法是一樣的。

案例三:你在一個網紅小吃店門口排隊,很長的隊伍,曲曲折折你數不清前面排了多少人,你前面的人也不知道自己是第幾個,但他也想知道,假定你前面排隊的人都想知道自己是第幾個,則從你開始,一個一個往前問,當問到第一個排隊的時,他從1開始一個個往前反饋,知道反饋到你,這時候你前面的人就都知道自己是第幾個了。

專業一點的內容

這些問題很通俗易懂,還有哪些經典編程案例呢?作為Python初學者,「樹」的定義、等比等差數列、階乘、Fibonacci數列等等,這些問題,我們同樣是可以通過遞歸方式去解決的。下面,我們舉幾個稍微複雜的例子。

04遞歸方法的經典案例

【案例一】求某數的階乘

def factorial(n):

''' n表示要求的數的階乘 '''

if n==1:

return n

return n * factorial(n-1)

【案例二】斐波那契數列

def fabonacci(n):

''' n為斐波那契數列 '''

if n <= 2:

v = 1

return v

return fabonacci(n-1)+fabonacci(n-2)

【案例三】二分法查找

data = [1,3,6,13,56,123,345,1024,3223,6688]

def dichotomy(min,max,data,number):

'''min表示有序列表頭部索引

max表示有序列表尾部索引

data表示有序列表

number表示需要尋找的元素

'''

mid = (min + max)// 2

if mid == 0:

return 'None'

elif data[mid] < number:

print('向右側找!')

return dichotomy(mid,max,data,number)

elif data[mid] > number:

print('向左側找!')

return dichotomy(min,mid,data,number)

else:

print('找到了%s'% data[mid])

return

res = dichotomy(0,len(data),data,123)

print(res)

利用遞歸進行二分法查找

05遞歸函數的局限性

上面講解了遞歸的特點和一些案例,但是遞歸方法並不是每一個適用問題都可以解決的。它也有一些局限性。

在計算機中,函數調用時通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,就會導致棧溢出。

在進行二分法查找時,如果需要查找的數據不在提供的列表中,當多次查找達到棧的極限時,就會棧溢出,拋出異常。

棧溢出拋出異常

那麼,如何獲取默認最大遞歸限制呢?

import sys

print(sys.getrecursionlimit())

輸出:3000

其實,還可以設置,但是對於新手來講,這裡就最好不要設置了。使用函數如下:

sys.setrecursionlimit(999999999)

print(sys.getrecursionlimit())

這個設置對於我們問題解決是起不到任何作用滴!自己分析……

好了,今天的內容就到這裡了,喜歡Python編程的小夥伴關注我,後續會推出更加精彩的內容。還有哪些有意思的遞歸用法呢?歡迎大家下方留言!

轉載請註明出處,百家號:Python高手養成

相關焦點

  • 詳細解讀Python 遞歸函數!
    由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)先舉個簡單的例子:計算1到100之間相加之和;通過循環和遞歸兩種方式實現#!/sum.py循環求和: 5050遞歸求和: 5050遞歸函數的優點是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,但循環的邏輯不如遞歸清晰。***使用遞歸函數需要注意防止棧溢出。在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。
  • python遞歸算法(上)
    要實現重複列印,可能我們立馬就會想到使用循環。如果要求不能使用循環呢,那我們就可以通過下面的方法來實現。原理很好理解,就是不斷的調用自身,如果前面不加上if條件判斷,理論上是會陷入死循環的,但是實際上遞歸到一定次數(最大遞歸次數)就會報錯停止。
  • Python遞歸函數、閉包和裝飾器
    >遞歸函數recursion1.遞歸一定要控制遞歸的層數,當符合某一條件時要終止遞歸,幾乎所有的遞歸都能用while循環來代替。i +=1print(result)緊接著我們看下階乘的規律:1!n+1)]print(a)擴充面試題目:如何獲取計算機當中的最大的遞歸層數?
  • python算法遞歸於尾遞歸!
    遞歸概念遞歸:程序調用自身的編程技巧稱為遞歸( recursion)。用一種通俗的話來說就是自己調用自己,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的、但是規模較小的問題來求解,當問題小到一定規模的時候,需要一個遞歸出口返回。
  • C/C++中的遞歸的應用
    (3)遞歸運行過程中,相互嵌套的多層之間會有參數傳遞,多層之間是否會相互影響?二、遞歸兩個要素遞歸的兩個要素分別是遞歸邊界和遞歸的邏輯,即遞歸"公式"。遞歸的過程一定有參數的變化,並且參數的變化和遞歸邊界有關係。在難度較大的程序設計中,這兩者均不易直接得到。下面通過幾個簡單的例子來解釋遞歸。
  • 零基礎入門深度學習 |最終篇:遞歸神經網絡
    零基礎意味著你不需要太多的數學知識,只要會寫程序就行了,沒錯,這是專門為程式設計師寫的文章。雖然文中會有很多公式你也許看不懂,但同時也會有更多的代碼,程式設計師的你一定能看懂的(我周圍是一群狂熱的Clean Code程式設計師,所以我寫的代碼也不會很差)。
  • Java之遞歸求階層
    Java之使用遞歸計算1-n之間的和,這次小編要介紹的是,用遞歸求階乘。=n*(n-1)*……*3*2*1分析:其實這與累和類似,之不過換成了乘法運算,推理得出:n!=n*(n-1)!=5*(5-1)*(5-2)*……*(5-4)遞歸結束的條件:獲取到1的時候結束遞歸的目的:獲取下一個被乘的數字(n-1)*/private static int sum(int n) {
  • Python進階之遞歸函數的用法及其示例
    (來源於百度,看不懂正常,術語就是不說人話)下面是筆者的個人理解:遞歸就是在函數內部調用自己的函數被稱之為遞歸。看不懂?形象的舉幾個例子!一個洋蔥是一個帶著一層洋蔥皮的洋蔥。# age(n)=age(n-1)+2 #n>1 遞歸終止條件# age(1)=18 #n=1 等於終止條件遞歸的回溯與遞推遞推:像上邊遞歸實現所拆解,遞歸每一次都是基於上一次進行下一次的執行,這叫遞推。
  • 如何理解遞歸?
    { return 1; }else{ return n+recursion(n-1); }}通過初體驗對比,不難發現以下遞歸有以下幾個要點。缺點:使用遞歸調用時,如果過多的調用容易造成java.lang.StackOverflowError即棧溢。出和程序執行過慢。這是一個潛在Bug和影響程序執行效率問題,需要謹慎使用。對於網際網路這種以速度和效率來維護用戶量,不得以用遞歸時,可以把處理的數據放入緩存,或者直接使用迭代等方式來解決。規律:遞歸要有出口,不然成了死循環。
  • 從1到100求和學算法思維(四)
    公眾號作者受邀加入微信官方洗稿投訴合議小組從1到100求和學算法思維(一)從1到100求和學算法思維(二)從1到100求和學算法思維(三)問題描述上一篇通過遞歸算法實現整數n從100逐漸遞減到1,然後將每一個遞減的整數累加到變量sum中,這是一種單向的遞減操作,如圖:單向的遞減最主要的問題在於下降速度過慢,是否有更快的遍歷速度呢?
  • 「通俗易懂的文字」+「經典的案例」希望能讓你順利入門「遞歸算法」
    遞歸是非常常見的一種算法,非常經典,可以解決非常多的問題。但我估計雖然大部分人知道遞歸,也能看得懂遞歸,但在實際運用中,很容易被遞歸給搞暈(數據,變量,函數等來回的出棧入棧)。今天寫篇文章分享下,或許,能夠給你帶來一些幫助。
  • 從1到100求和學算法思維(五)
    從1到100求和學算法思維(四)問題描述前面幾篇文章為大家介紹了多種遞歸算法來實現1到100求和,但是這些算法都無一例外利用static關鍵詞定義了一個sum變量,即:static int sum = 0;
  • Python 進階之遞歸函數一點都不難!
    出品 |  AI科技大本營(ID:rgznai100)本篇文章主要介紹了Python進階之遞歸函數的用法及其示例,現在分享給大家,也給大家做個參考
  • 如何優雅地使用javascript遞歸畫一棵結構樹
    舉個例子,我們來實現一下階乘,如果用普通的遞歸,實現將是這樣的:function factorial(n) {if (n === 1) return 1;return n * factorial(n - 1);
  • 詳解:遞歸神經網絡和LSTM網絡那些事兒
    【IT168 編譯】遞歸神經網絡是最先進的順序數據算法之一,在蘋果Siri和Google語音搜索中都使用到的算法。這是因為它是第一個記憶它的輸入的算法,由於內部存儲器,這使得它非常適合涉及順序數據的機器學習問題。它是過去幾年Deep Learning的驚人成就背後的算法之一。在這篇文章中,你將學習遞歸神經網絡如何工作的基本概念,最大的問題是什麼以及如何解決它們。
  • 通過一道面試題目,講一講遞歸算法的時間複雜度!
    ,那麼這篇來給大家通透的講一講。我們來分析一下,首先看遞歸了多少次呢,可以把遞歸抽象出一顆滿二叉樹。剛剛同學寫的這個算法,可以用一顆滿二叉樹來表示(為了方便表示,選擇n為偶數16),如圖:遞歸算法的時間複雜度當前這顆二叉樹就是求x的n次方,n為16的情況,n為16的時候,進行了多少次乘法運算呢?
  • 數據結構與算法的JavaScript實現及應用:Stack/遞歸/漢諾
    摘要在這篇文章裡,我將介紹數據結構Stack的基本操作和它的一些應用。我們將看到Stack在括號匹配檢測,表達式求值,函數調用上的應用。遞歸是一種特殊的函數調用,由於遞歸在程序設計中十分重要且不容易理解,所以我將闡述我對遞歸的理解。
  • Python內置函數、作用域、閉包、遞歸
    1.常見的內置函數常見的內置函數:查看內置函數:print(dir(__builtins__))常見函數type 查看對象類型len 求長度min 求最小值max 求最大值sorted 排序reversed 反向sum 求和
  • 二叉樹的所有遍歷非遞歸實現
    前言:二叉樹的遍歷形式有很多,比如前序、中序、後序、層序遍歷,在最近的一次面試中,面試官要求手寫層序遍歷代碼(非遞歸的形式),由此可見遍歷的重要性.本篇博客我們就來看一下二叉樹的幾種遍歷方式.本篇博客語言均採用java實現:目錄:一:二叉樹簡介二:前序遍歷三:中序遍歷
  • 少兒Python編程培訓手冊系列之——函數的定義及遞歸思想
    sum()是求和函數。比如下述代碼,先確定一個範圍,再調用函數求和即可。format()是格式化輸出函數,類似於C#裡面的格式輸出。字符串裡含有{},代表佔位符;然後,通過:字符串.format(內容)控制格式。上述兩行代碼是一樣的效果,大括號裡一個標了數字,一個沒有標註數字。默認序號從0開始。