二叉樹的遍歷 → 不用遞迴,還能遍歷嗎

青石路發表於2021-12-27

開心一刻

  某同學牙齦發炎去看醫生,醫生說要動手術

  同學說:以前沒做過手術,有點緊張

  醫生說:不用緊張,我也是第一次做手術

  聽到醫生這麼說,同學更緊張了

  這時候護士走過來,問醫生:麻藥是打嘴裡面還是打在嘴外面?

  醫生說:打腿上吧,免得一會他跑了

前提準備

  關於什麼是二叉樹,不作過多介紹,不清楚的小夥先去充能下

  後續程式碼用 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、二叉樹遍歷是解決二叉樹相關問題的基礎,不同的遍歷可以解決不同的問題

    下一篇講二叉樹相關的具體案例,屆時大家結合這邊文章,找一找二叉樹問題的感覺

相關文章