開心一刻
某同學牙齦發炎去看醫生,醫生說要動手術
同學說:以前沒做過手術,有點緊張
醫生說:不用緊張,我也是第一次做手術
聽到醫生這麼說,同學更緊張了
這時候護士走過來,問醫生:麻藥是打嘴裡面還是打在嘴外面?
醫生說:打腿上吧,免得一會他跑了
前提準備
關於什麼是二叉樹,不作過多介紹,不清楚的小夥先去充能下
後續程式碼用 java 實現,但涉及到的資料結構、演算法是通用的,希望大家不要被開發語言所禁錮
二叉樹節點定義類似如下
value 儲存資料, left 指向左子樹, right 指向右子樹
二叉樹結構類似如下
二叉樹的遍歷分兩種:深度遍歷 和 廣度遍歷
深度遍歷又分三種:先序遍歷、中序遍歷、後續遍歷,其中先序、中序、後續都是基於根(父)節點
先序遍歷:根(父)節點 -> 左子樹 -> 右子樹
中序遍歷:左子樹 -> 根(父)節點 -> 右子樹
後續遍歷:左子樹 -> 右子樹 -> 根(父)節點
廣度遍歷也指層次遍歷,從下至上或從下至上一層一層的從左至右遍歷
基於上圖中的二叉樹,我們來看看各種遍歷的結果
先序遍歷:a b q w t u c d
中序遍歷:q b t w u a c d
後續遍歷:q t u w b d c a
從上至下層次遍歷:a b c q w d t u
從下至上層次遍歷:t u q w d b c a
深度遍歷
當我們對各種遍歷有了概念上的瞭解之後,我們來看下具體實現
先序遍歷
遞迴實現很簡單,相信大家已經爛熟於心了
如果不用遞迴,我們怎麼實現先序遍歷?
我們知道,遞迴的時候,會保留現場資訊(上下文),這是一個入棧的過程,只是由系統實現;當子遞迴完成之後,會出棧來到上層遞迴,這也是系統完成的
如果我們將入棧、出棧的過程控制在我們自己的程式碼中,那麼就不需要遞迴了,實現如下
中續遍歷
遞迴實現
非遞迴實現
這個可能沒那麼好理解,結合具體的二叉樹示例,腦中逐行模擬下程式碼執行,慢慢的就有感覺了
後續遍歷
遞迴實現
非遞迴實現
用到了雙棧,大家仔細揣摩下程式碼
深度優先遍歷
指的就是先序遍歷,前面已經實現過,這裡就不再贅述
廣度遍歷
一層一層的遍歷二叉樹,如果未明確指明,都是從左至右遍歷
廣度遍歷不滿足遞迴的條件(至於是什麼條件,自行去查),所以沒法用遞迴處理
從上至下層次遍歷
從根節點出發,從上至下,相當於先進先出,先進先出這樣的關鍵字,我們第一時間想到的資料結構往往是:佇列
所以需要藉助佇列來實現從上至下的層次遍歷,具體實現如下
還是很簡單的,也容易理解
從下至上層次遍歷
前面已經實現了從上至下層次遍歷,那是不是將其倒置一下就能實現從下至上層次遍歷了?
有這種感覺我們就去嘗試,廣度遍歷需要用到佇列,倒置需要用到棧,具體實現如下
是不是覺得很有意思?
廣度優先遍歷
指的就是從上至下層次遍歷,不再贅述
總結
1、遞迴的實現往往比迭代實現要簡單,也更好理解,但兩者存在控制元件使用率的差異
遞迴沒有我們想象的那麼簡單,不同的問題有不同的決策過程
而如何正確的找到決策過程,沒有答案,全憑個人的感覺,可以通過多練題來提高這種感覺
2、二叉樹遍歷是解決二叉樹相關問題的基礎,不同的遍歷可以解決不同的問題
下一篇講二叉樹相關的具體案例,屆時大家結合這邊文章,找一找二叉樹問題的感覺