通過二叉樹的遍歷理解遞歸

前言
對於遞歸自己一直處於迷迷糊糊的狀態,看了超多和遞歸有關的資料,但還是不是特別理解,今天又看了一上午,覺得有些收穫,打算寫下了,加深理解。

前一段時間寫的三種遍歷的可視化,有興趣的同學可以參考
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);    
        }
    }

對代碼的幾點說明

  1. divlist爲一個數組,是一個全局變量,存儲最終遍歷結果
  2. 可能有的同學不熟悉JavaScript,node.firstElementChildnode.lastElementChild分別指父節點的第一個元素節點和最後一個元素節點,即對應父節點的左孩子和右孩子。
  3. 二叉樹是以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三個元素節點

總結
遞歸也沒有那麼可怕,該執行的代碼還是會執行,不過順序可能和我們平常的思維不一致。它會不斷的調用自身直到一個停止條件的滿足,然後再回溯會第一個節點。

思維可能不清晰,如發現問題懇請指正,小女子不勝感謝~

發佈了44 篇原創文章 · 獲贊 117 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章