1. 程式人生 > >詳細解說遞迴與分治演算法,一文帶你入門到熟悉

詳細解說遞迴與分治演算法,一文帶你入門到熟悉

全文共 2114 字,閱讀文字大概需要 3.8 分鐘。

前言

這幾天看到交流有人群裡說有關遞迴的棧溢問題,剛好小編又看到有關遞迴的東西,給大家闡述一下遞迴和分治的內容,讓各位更加理解有關前賢的各種化整為零。

正文

很多人認為遞迴是語言中最為難以理解的內容之一,其實不需要有什麼特別對待,只要理解了有關地址,指標和棧的呼叫就會發現很平常,當然如果你看了一下下後面的內容你也會有此感。

首先遞迴的定義:

遞迴:參見“遞迴”

what?,這個定義什麼也沒說吧。

改一下吧

遞迴:如果還沒有遞迴是什麼意思,參見“遞迴”

哈哈!這次你應該就能明白了,遞迴原來就是“自己用到自己”。這個定義明顯比上面的定義簡介明瞭多了。既然明白了其中原理後,那就需用在繼續參見下去了。當然這個讓很多人感到有點東西的遞迴定義不止這些:

“A主管:這個事不歸我管,你去找 B 主管吧。"你去了 B 那裡

"B主管:這個事不歸我管,你去找A 主管吧~” 你有回到了 A 這裡

這種踢皮球原則想必有很多人碰到過,A,B主管的所言不變,假設你始終聽話,你就會始終往復於此。(這個叫做:無限遞迴,這個是你個人和計算機無法忍受的)。上面的你並沒有自己想往復與兩個主管之間,這中“間接的使用自己”也是遞迴的一種形式。

這就是遞迴的定義,簡潔而嚴密~

都講遞迴使用到棧,上面的定義好像是少了點什麼?瞭解一下棧的特點先進後出(FILO)結構,棧頂指標始終指向棧頂(如果不是太瞭解不急,我後面介紹)。現在要了解,如果語言執行一個函式的時候會有一棧幀——遞迴函式也是如此,每一次呼叫遞迴過程中都對產生一個棧幀實現引數的傳遞。並且跳到程式的開頭。這時被呼叫的棧叫做堆疊段(這一段有自己的大小)這個也不能被越界,但是每次呼叫都會生成一個棧幀,在這個過程中可能會發生棧的溢位問題(不理解的話可以理解為上面主管的踢皮球你來回跑自己累的嗝屁了)。

上面的一段應該就是那種低層的讓人很焦慮的東西。下面介紹幾個小栗子

舉栗子

為了讓大家很熟悉就能理解。(分為幾種情況舉栗子,從簡到繁)

我總結了遞迴問題的三找求解辦法:

找重複(在重複中找到一種劃分,通過遞推公式或者等價轉化成子問題)

找變化的量(變化的量通常是轉化成引數的)

找到出口(根據引數變化規律找到邊界條件,像上面的踢皮球問題總得把球把握在自己的手上)

單層遞迴問題 – n!階乘問題(n >= 1)

首先找到重複的和變化的量 n!可以轉化為 > n*(n-1)!> 直到 1 的階乘為 1。為這個遞迴的出口條件。

通過分析可以很容易的寫出遞迴定義:
在這裡插入圖片描述

有了遞迴定義就可以很簡單的寫出對應程式碼(程式碼獲取方式在文末)

(Markdown 語法寫出的程式碼格式無法顯示換行,小編研究一下以後採用Markdown )

在這裡插入圖片描述

這個單層遞迴形式為線性的水花四濺複雜度為O(n)

雙分枝遞迴問題 – Fibonacci 數列

斐波那契數列是一個很為經典多分枝遞迴問題,也叫做“兔子繁殖問題”。斐波那契數列的內容如下:無窮數列 1、1、2、3、5、8、13、21、34、55…這種後一項為前兩項的和的數列(第1、2項已被定義)為 Fibonacci 數列。

這個問題可以等價為兩個問題的子問題,兩個子問題的和為整個問題。

由此可以寫成函式的遞迴定義:

在這裡插入圖片描述

有了遞迴定義可以簡單的寫出對應的程式碼:

在這裡插入圖片描述

這個演算法的時間複雜度為O(2(N/2))~~O(2N)

雙遞迴函式 – Ackerman 函式(這個稍微有點難度)

這個函式是有兩個自變數引數所構成,他的最為原始的形式可以到維基百科中瀏覽,這裡介紹函式的一般形式。

直接給出定義:
在這裡插入圖片描述

這個遞迴函式中的有著多重遞迴的形式可以通過定義寫出程式碼:

在這裡插入圖片描述

程式碼相對來講比較簡單,但是函式呼叫很多次如果想更加了解這個函式可以自己手動模擬ack(3,3)這個函式,最終答案為 61 。

遞迴經典問題 – Hanoi 塔問題

Hanoi 塔問題內容是:有a、b、c三個塔,初始狀態是:在 a 塔上放了 n 個圓盤從上到下,從小到大。(大盤不允許放在小盤上)要求把 a 塔上的盤子放到 c 塔上。每次只能拿一個盤子。

為了更好的解決這個問題小編專門到 4399小遊戲 上找了漢諾塔的遊戲玩了一下。

首先要解決這個問題我們要知道把盤子移動到另一個柱子需要有一個柱子作為輔助。

這是我們就可以把問題理解為 1-n 從 a -> c ,c作為輔助

1.1 到 n-1 從 a 移動到 c ,b 為輔助

2.把第 n 個柱子移動到 b

3.1 到 n-1 從 c 移動到 b ,a 為輔助

在這裡插入圖片描述

通過遞推公式T(n)=2T(n-1)+1

所以漢諾塔問題的時間複雜度為O(2^n)

相對於的問題還有:

二分搜尋就是使用分治

二分查詢的遞迴形式

希爾排序的問題

只要能實現主問題轉化為多個小問題解決的基本都可以採用遞迴。還有一點是遞迴都可以轉化為非遞迴形式。

今天只能寫這麼多了

真誠希望各位能夠轉發擴散

歡迎關注微信公眾號:「挑戰演算法與程式設計」更多能容將在公眾號第一時間推出