文 | 太陽雪html
來源:Python 技術「ID: pythonall」python
編程之因此魅力無比,其中一個重要的緣由是,一次寫入,屢次運行,你可能和我同樣想象過這樣的場景:半躺在椅子上,優雅的點擊一個按鈕,新的宇宙啓動了……程序員
不要以爲這是個幻想,也別隻將其停留在幻想之中,這個幻想說明了一個問題,程序能夠幫助咱們完成更多的事情,而起始點無比的簡單,今天咱們一塊兒聊聊遞歸的事情,也許它就是啓動宇宙的那個小小按鈕算法
一種計算過程,若是其中每一步都要用到前一步或前幾步的結果,稱爲遞歸的。用遞歸過程定義的函數,稱爲遞歸函數,例如連加、連乘及階乘等。凡是遞歸的函數,都是可計算的,便可行的。編程
古典遞歸函數,是一種定義在天然數集合上的函數,它的未知值每每要經過有限次運算迴歸到已知值來求出,故稱爲「遞歸」。它是古典遞歸函數論的研究對象編程語言
遞歸做爲一種算法思想,應用的場景不少,例如著名的漢諾塔問題,即有三個柱子,最左邊的上面從小到大串着必定數量的盤子,如今須要將它們移動到最右邊的柱子上,原則是移動過程當中,以及最終的結果,必須保存小盤子在大盤子上面ide
漢諾塔函數
還有斐波那契數列,即除了第一個和第二個數爲1,其他的數都是前兩個數之和,例如 1,1,2,3,5,8……,還有階乘算法,即,正整數列中,個數爲 n 的數相乘,等等舉不勝舉工具
在計算機算法中遞歸更經常使用,例如二分法查找,快速排序,樹的遍歷,即對於執行規模不肯定,但能拆解爲簡單步驟的算法,遞歸幾乎都有用武之地,不但能夠解決問題,並且語義也更清晰優化
平常應用中,遞歸也很廣泛,例如遍歷文件夾查找文件,處理 XML 文件,再例如 應收帳款和收款的匹配,還有最近我 在 TMS 項目遇到的處理箱單層層包裹的關係問題,等等舉不勝舉
遞歸與其說是一種編程語言的能力,不如說是一種分析和思考問題的能力,從問題中發現規律,將大問題轉換爲小問題,知道能夠簡單計算爲止,或者正向思考,前面步驟是後面步驟的計算條件,不斷的計算前面的結果,最終獲得預訂步驟的結果。
既然遞歸如此好,有沒有限制呢?固然有,任何事物都具備兩面性,解決問題時要揚長避短
終於到了實踐部分了,爲您的耐心點贊,咱們用遞歸算法畫一棵分形樹
分形樹就是一棵樹的局部形狀和總體形狀類似,天然界中很常見,例如一片葉子上的形狀,和整棵樹的形狀類似,即整棵樹由樣式相同的無數個從小到大的形狀構成
天然分形樹
那麼如何用程序畫出一個分形樹呢?能夠先畫最小的,而後畫次大的,最後組成整個形狀,就是今天聊的 遞歸算法
既然要畫,就須要安裝一個畫庫工具,Python 中有各式各樣的繪圖包,咱們選用 Turtle 庫,庫如其名,能夠將 Turtle 想象成一個小烏龜,逐漸在海灘上移動,畫出一個圖形來,經過將簡單圖形組合起來,能夠輕鬆地繪製出精美的形狀和圖案
安裝
> pip install turtle
有了這些概念,就能夠經過代碼來設置畫布,控制畫筆繪製圖形了,代碼很簡單:
from turtle import Turtle myTurtle = Turtle() myTurtle.forward(100)
有了繪製工具,就解決了技術問題,如今能夠專心思考算法了
爲了簡便,選擇最簡單的二叉分形樹來畫,最基本形狀是一個二叉樹,由樹幹和左右兩個枝叉組成,左右樹杈於樹幹的夾角設置爲 20 度,像一個 Y 字
常規思惟:先畫根樹幹,而後分別畫兩個樹杈,每一個樹杈又是一棵樹,接着在各自的樹幹上再畫出兩個樹杈,如此循環往復,直到畫出最小樹的兩個樹杈爲止
是否是有點繞?下面的圖片展現了部分繪製過程,可能更直觀:
直接上代碼:
from turtle import Turtle # 分形樹遞歸方法 def fractalTree(branchLen, t): if branchLen > 0: t.forward(branchLen) t.right(20) fractalTree(branchLen - 15, t) t.left(40) fractalTree(branchLen - 15, t) t.right(20) t.backward(branchLen) # 初始化畫布和畫筆 t = Turtle() # 建立畫布實例 t.screen.delay(3) # 設置繪製顯示延遲,以便觀察過程 t.pensize(2) # 設置畫筆粗細爲 2 個像素 t.color('green') # 設置畫筆顏色爲 綠色 t.left(90) # 向左旋轉 90 度,即讓畫筆朝上 t.up() # 擡起畫筆,即在移動時不會繪製 t.backward(300) # 相對畫筆朝向,向後退 300 個像素 t.down() # 落下畫筆,準備繪製 # 繪製分形樹,根樹幹長度爲 105 像素 fractalTree(105, t) # 獲取畫布窗口,並設置關閉條件爲點擊窗口,以便在執行完成後保留繪圖窗口 t.getscreen().exitonclick()
上面代碼分爲三部分,Turtle 引入、分形樹方法定義,以及分形樹繪製
Turtle 引入沒必要解釋,分形樹繪製部分有詳細註釋,也沒必要多說,主要分析下分形樹方法 fractalTree:
總體上看,過程就是,畫樹幹,而後畫右側分枝,再畫左側分枝,最後回到起點,不過在畫兩側分枝時,咱們用了遞歸,讓畫樹的過程獲得重複利用,若是順利,就會看到上面展現的繪製過程,趕忙試試吧
看似上面過程很順利,其實否則,我在編寫代碼時,不斷的陷入思惟的漏洞,要麼是設置錯了畫筆方向,要麼是畫筆沒有回退到位,等等,烏龍無數(汗!),看下翻車記錄:
失敗案例1
再來一個
失敗案例2
不過也挺好看的,不是嗎
今天經過畫一顆分形樹,瞭解了一下遞歸的概念和應用,總體感受遞歸代碼短小,但思考過程比正常編程過程要複雜的多,不過這就是編程的魅力,更確切的說是數學的魅力,用簡單的符號語言,描繪紛繁複雜的世界…… 最重要的是,Python 支持遞歸 示例代碼中,不只有分形樹方法及翻車代碼,還有個彩蛋,歡迎把玩