前言
對於遞歸自己一直處於迷迷糊糊的狀態,看了超多和遞歸有關的資料,但還是不是特別理解,今天又看了一上午,覺得有些收穫,打算寫下了,加深理解。
前一段時間寫的三種遍歷的可視化,有興趣的同學可以參考
demo地址:
http://crystalyy.github.io/resume/task/task22/index.html
代碼地址:
https://github.com/crystalYY/resume/blob/gh-pages/task/task22/index.html
正文
說明:以JavaScript爲程序的實現語言
以下二叉樹是這篇博文的“主角”
重點介紹先序遍歷
具體實現代碼
function preorder(node){
if(!!node){//轉換爲布爾值
divlist.push(node);
preorder(node.firstElementChild);
preorder(node.lastElementChild);
}
}
對代碼的幾點說明
- divlist爲一個數組,是一個全局變量,存儲最終遍歷結果
- 可能有的同學不熟悉JavaScript,
node.firstElementChild
與node.lastElementChild
分別指父節點的第一個元素節點和最後一個元素節點,即對應父節點的左孩子和右孩子。 - 二叉樹是以DOM樹的形式模擬
所謂遞歸可以分爲兩部分來理解:“遞”和“歸”。
“遞”指按照代碼執行順序執行,這個和我們正常的思維一致不難理解。但有一點需要注意的是,在“遞”的同時會把節點按照訪問的順序逐次壓入到一個堆棧中。
“歸”是指“遞”進行到盡頭時,開始根據“遞”的過程中形成的堆棧進行出棧,最終得到結果。
對於二叉樹的先序遍歷,可以看出包含了兩個對自己的調用,及包含兩個遍歷。
我們首先傳進去的node是1,根據程序執行過程,我們可以知道在執行到一個階段的盡頭時,將會形成這樣一個堆棧
由於左子樹已經到了盡頭,所以第一個遍歷暫告一段落。按照代碼執行的順序,接下來需要執行preorder(node.lastElementChild);
也就是右子樹的遍歷,因爲4依然沒有右孩子,所以按照出棧的順序依次遍歷2和1的右子樹。爲了說明簡單,再次貼一下代碼
function preorder(node){
if(!!node){//轉換爲布爾值
divlist.push(node);
preorder(node.firstElementChild);
preorder(node.lastElementChild);
}
}
再來具體分析一下遍歷2的右孩子時的過程。
當把2的節點傳給preorder函數時,只執行了preorder(node.firstElementChild);
,preorder(node.lastElementChild);
還沒有執行,按照程序執行順序此時需要執行。
具體的執行步驟如下:
此時堆棧內又依次被壓入了5,6,7三個元素節點
總結
遞歸也沒有那麼可怕,該執行的代碼還是會執行,不過順序可能和我們平常的思維不一致。它會不斷的調用自身直到一個停止條件的滿足,然後再回溯會第一個節點。
思維可能不清晰,如發現問題懇請指正,小女子不勝感謝~