1. 程式人生 > >python--遞歸函數--景麗洋

python--遞歸函數--景麗洋

報錯 ron col ble 現象 默認值 代碼執行 都沒有 rip

楔子

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

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 技術分享技術分享 技術分享
 1 def threeLM(dic):
 2     while True:
 3         for k in dic:print(k)
 4         key = input(‘input>>‘).strip()
 5         if key == ‘b‘ or key == ‘q‘:return key
 6         elif key in dic.keys() and dic[key]:
 7             ret = threeLM(dic[key])
 8             if ret == ‘q‘: return ‘q‘
 9         elif (not dic.get(key)) or (not dic[key]) :
10             continue
11 
12 threeLM(menu)

python--遞歸函數--景麗洋