微信公衆號:小超說這是查找算法系列文章的第一篇,助你快速入門二叉樹算法
咱們首先來看一些圖片:數組
其中,第1、2、四個都是樹,第三個不是。樹的特色很明顯吧!微信
其中每一個元素叫作「節點」;用來鏈接相鄰節點之間的關係,咱們稱之爲「父子關係」。例如在圖一中,A節點是B節點的父節點,B節點是A節點的子結點,同時,B節點和Q節點是同一個父節點A的子節點,因此它們之間互相成爲兄弟節點。咱們把沒有父節點的節點稱爲根節點,也就是圖一中的A節點。咱們把沒有子節點的節點稱爲葉子節點,好比圖一中的D、E、F、G節點。這些概念都是顯而易見,但倒是最基本的東西。數據結構
二叉樹,天然就是每一個節點最多有兩個分支,即兩個子節點的一種樹,兩個分支分別稱爲左子樹和右子樹。仍是那上面那張圖舉例,圖1、圖二和圖四都是二叉樹,由於它們每一個節點都最多含有兩個子節點。其中,圖一又稱爲滿二叉樹,圖四又稱爲徹底二叉樹。而之因此出現徹底二叉樹的概念,實際上是基於二叉樹的物理存儲方式。函數
鏈式存儲法:spa
咱們爲每一個節點建立一個Node對象
:設計
class Node{ int data; Node left,right; }
每一個節點都是一個Node對象,它包含咱們所須要存儲的數據,指向左子節點的引用,直向右子節點的引用,就像鏈表同樣將整個樹串起來。若是該節點沒有左子節點,則Node.left==null
或者Node.right==null
.code
順序存儲法:對象
咱們把根節點儲存在下標爲i=1
的位置,那麼左子節點儲存在2*i=2
的位置,右子節點儲存在下標爲2*i+1=2
的位置。依此類推,完成樹的存儲。藉助下標運算,咱們能夠很輕鬆的從父節點跳轉到左子節點和右子節點或者從任意一個子節點找到它的父節點。若是X的位置爲i,則它的兩個子節點的下標分別爲2i
和2i+1
,它的父節點的位置爲i/2
(這裏結果向下取整)。遞歸
具體以下圖所示:能夠發現,只有徹底二叉樹存儲的效率才最高,最省內存
二叉樹的遍歷操做主要有三種
前序遍歷是指,對於樹中的任意節點來講,先打印這個節點,而後再打印它的左子樹,最後打印它的右子樹。
中序遍歷是指,對於樹中的任意節點來講,先打印它的左子樹,而後再打印它自己,最後打印它的右子樹。
後序遍歷是指,對於樹中的任意節點來講,先打印它的左子樹,而後再打印它的右子樹,最後打印這個節點自己。
注意,這其中有點遞歸的味道
仍是以剛纔的圖爲例:
具體的代碼實現(寫出遞歸便可):
public void preOrder(Node root){ if(root==null) return; System.out.println(root.data);//打印root節點的值 preOrder(root.left); preOrder(root.right); } public void inOrder(Node root){ if(root==null) return; inOrder(root.left); Systrm.out.println(root.data); inOrder(root.right); } public void inOrder(Node root){ if(root==null) return; inOrder(root.left) inOrder(root.right); Systrm.out.println(root.data); }
二叉樹遍歷的時間複雜度是O(n),這是由於每一個節點最多會被訪問兩次,(遞歸時函數進棧和出棧),因此遍歷操做的訪問次數跟節點的個數 n 成正比,也就是說二叉樹遍歷的時間複雜度是 O(n)。
通過上面的介紹,咱們已經大體對二叉樹有了一個基本的認識,那麼,二叉樹存在的意義是什麼呢?咱們能夠基於這種數據結構設計出哪些高效的算法呢?下一次咱們將介紹二叉查找樹(Binary Search Tree),咱們將定義一種數據結構並維護它的性質。
題外話:對於算法初學者,推薦一本十分 nice 的書籍 《算法第四版》,裏面各類配圖十分詳細。若是你須要電子版文件,後臺回覆算法4便可得到下載連接。後臺回覆 算法01 送你一份 算法與數據結構思惟導圖。最後,但願咱們一塊兒進步,一塊兒成長!