Python—遞歸函數

来源:https://www.cnblogs.com/Golanguage/archive/2020/02/15/12315400.html
-Advertisement-
Play Games

楔子 在講今天的內容之前,我們先來講一個故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢...... ...


楔子

在講今天的內容之前,我們先來講一個故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢?從前有座山,山裡有座廟,廟裡有個老和尚講故事,講的什麼呢......這個故事你們不喊停我能講一天!我們說,生活中的例子也能被寫成程式,剛剛這個故事,讓你們寫,你們怎麼寫呀?

while True:
    story = "
    從前有個山,山裡有座廟,廟裡老和尚講故事,
    講的什麼呢?   
    "
    print(story)

你肯定是要這麼寫的,但是,現在我們已經學了函數了,什麼東西都要放到函數里去調用、執行。於是你肯定會說,我就這麼寫:

def story():
    s = """
    從前有個山,山裡有座廟,廟裡老和尚講故事,
    講的什麼呢?
    """
    print(s)
    
while True:
    story()

但是大家來看看,我是怎麼寫的!

def story():
    s = """
    從前有個山,山裡有座廟,廟裡老和尚講故事,
    講的什麼呢?
    """
    print(s)
    story()
    
story()

先不管函數最後的報錯,除了報錯之外,我們能看的出來,這一段代碼和上面的代碼執行效果是一樣的。

初識遞歸

遞歸的定義——在一個函數里再調用這個函數本身

現在我們已經大概知道剛剛講的story函數做了什麼,就是在一個函數里再調用這個函數本身,這種魔性的使用函數的方式就叫做遞歸

剛剛我們就已經寫了一個最簡單的遞歸函數。

遞歸的最大深度——997

正如你們剛剛看到的,遞歸函數如果不受到外力的阻止會一直執行下去。但是我們之前已經說過關於函數調用的問題,每一次函數調用都會產生一個屬於它自己的名稱空間,如果一直調用下去,就會造成名稱空間占用太多記憶體的問題,於是python為了杜絕此類現象,強制的將遞歸層數控制在了997(只要997!你買不了吃虧,買不了上當...).

拿什麼來證明這個“997理論”呢?這裡我們可以做一個實驗:

def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)

由此我們可以看出,未報錯之前能看到的最大數字就是997.當然了,997是python為了我們程式的記憶體優化所設定的一個預設值,我們當然還可以通過一些手段去修改它:

import sys
print(sys.setrecursionlimit(100000))

我們可以通過這種方式來修改遞歸的最大深度,剛剛我們將python允許的遞歸深度設置為了10w,至於實際可以達到的深度就取決於電腦的性能了。不過我們還是不推薦修改這個預設的遞歸深度,因為如果用997層遞歸都沒有解決的問題要麼是不適合使用遞歸來解決要麼是你代碼寫的太爛了~~~

看到這裡,你可能會覺得遞歸也並不是多麼好的東西,不如while True好用呢!然而,江湖上流傳這這樣一句話叫做:人理解迴圈,神理解遞歸。所以你可別小看了遞歸函數,很多人被攔在大神的門檻外這麼多年,就是因為沒能領悟遞歸的真諦。而且之後我們學習的很多演算法都會和遞歸有關係。來吧,只有學會了才有資本嫌棄!

再談遞歸

這裡我們又要舉個例子來說明遞歸能做的事情。

例一:

現在你們問我,alex老師多大了?我說我不告訴你,但alex比 egon 大兩歲。

你想知道alex多大,你是不是還得去問egon?egon說,我也不告訴你,但我比武sir大兩歲。

你又問武sir,武sir也不告訴你,他說他比金鑫大兩歲。

那你問金鑫,金鑫告訴你,他40了。。。

這個時候你是不是就知道了?alex多大?

1 金鑫   40
2 武sir   42
3 egon   44
4 alex    46

你為什麼能知道的?

首先,你是不是問alex的年齡,結果又找到egon、武sir、金鑫,你挨個兒問過去,一直到拿到一個確切的答案,然後順著這條線再找回來,才得到最終alex的年齡。這個過程已經非常接近遞歸的思想。我們就來具體的我分析一下,這幾個人之間的規律。

age(4) = age(3) + 2 
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 40

那這樣的情況下,我們的函數應該怎麼寫呢?

def age(n):
    if n == 1:
        return 40
    else:
        return age(n-1)+2

print(age(4))

遞歸函數與三級菜單

menu = {
    '北京': {
        '海澱': {
            '五道口': {
                'soho': {},
                '網易': {},
                'google': {}
            },
            '中關村': {
                '愛奇藝': {},
                '汽車之家': {},
                'youku': {},
            },
            '上地': {
                '百度': {},
            },
        },
        '昌平': {
            '沙河': {
                '老男孩': {},
                '北航': {},
            },
            '天通苑': {},
            '回龍觀': {},
        },
        '朝陽': {},
        '東城': {},
    },
    '上海': {
        '閔行': {
            "人民廣場": {
                '炸雞店': {}
            }
        },
        '閘北': {
            '火車戰': {
                '攜程': {}
            }
        },
        '浦東': {},
    },
    '山東': {},
}
menu
def threeLM(dic):
    while True:
        for k in dic:print(k)
        key = input('input>>').strip()
        if key == 'b' or key == 'q':return key
        elif key in dic.keys() and dic[key]:
            ret = threeLM(dic[key])
            if ret == 'q': return 'q'

threeLM(menu)
遞歸函數實現三級菜單

還記得之前寫過的三級菜單作業麽?現在咱們用遞歸來寫一下~

l = [menu]
while l:
    for key in l[-1]:print(key)
    k = input('input>>').strip()   # 北京
    if k in l[-1].keys() and l[-1][k]:l.append(l[-1][k])
    elif k == 'b':l.pop()
    elif k == 'q':break
堆棧實現

遞歸函數與二分查找演算法

http://www.cnblogs.com/Eva-J/articles/7197403.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 時間輪演算法 時間輪是一種高效、低延遲的調度數據結構。其在Linux內核中廣泛使用,是Linux內核定時器的實現方法和基礎之一。按使用場景,大致可以分為兩種時間輪:原始時間輪和分層時間輪。分層時間輪是原始時間輪的升級版本,來應對時間“槽”數量比較大的情況,對記憶體和精度都有很高要求的情況。延遲任務的場景 ...
  • 前言 預設的 Identity 實體類型在大多數時候已經基本夠用,很多時候也只是稍微在 IdentityUser 類中增加一些自定義數據欄位,比如頭像。這次,我要向園友隆重介紹我魔改之後的 Identity 實體類,能支持一些特別風騷的操作。當然也完全相容內置的 UserManager、RoleMa ...
  • 1、結構型設計模式 2、適配器模式 3、類適配器 4、對象適配器 ...
  • isinstance和issubclass isinstance(obj,cls)檢查是否obj是否是類 cls 的對象 class Foo(object): pass obj = Foo() isinstance(obj, Foo) issubclass(sub, super)檢查sub類是否是 ...
  • 楔子 你現在是一家游戲公司的開發人員,現在需要你開發一款叫做<人狗大戰>的游戲,你就思考呀,人狗作戰,那至少需要2個角色,一個是人, 一個是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎麼描述這種不同的角色和他們的功能呢? 你搜羅了自己掌握的所有技能,寫出了下麵的代碼來描述這兩個角色 ...
  • 包 包是一種通過使用‘.模塊名’來組織python模塊名稱空間的方式。 1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法 2. 包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是 ...
  • 什麼是模塊? 常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的尾碼。 但其實import載入的模塊分為四個通用類別: 1 使用python編寫的代碼(.py文件) 2 已被編譯為共用庫或DLL的C或C++擴展 3 包好一組模塊的包 4 使用C編寫並鏈接到 ...
  • https://www.cnblogs.com/WUXIAOCHANG/p/10886534.html https://blog.csdn.net/pengjwhx/article/details/84867112 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...