二叉樹
二叉樹(Binary Tree)是每個節點最多隻有兩個子節點的結構,通常左邊的叫左子樹,右邊的叫右子樹,二叉樹的節點是具有左右次序的,不能隨意顛倒。
二叉樹的 4 種形態
1.僅僅只有一個根節點,沒有子節點。
2.根節點只有左子樹。
3.根節點只有右子樹。
4.根節點既有左子樹,又有右子樹。
二叉樹的分類
1.完全二叉樹
假設其深度為 d(d>1)。除了第 d 層外,其它各層的節點數目均已達最大值,且第 d 層所有節點從左向右連續地緊密排列,這樣的二叉樹被稱為完全二叉樹。
所有葉子節點全都出現在最底層的完全二叉樹就叫滿二叉樹。就相當於這棵樹的第一層是 1 個節點,第二層是 2 個節點,第三層是 4 個節點,第五層是 8 個節點,以此類推。 3.斜樹
所有的節點都只有左子樹的二叉樹叫左斜樹,所有的節點都只有右子樹的二叉樹叫右子樹,它們都叫斜樹。實際上這棵二叉樹看起來像一撇或者一捺。 4.二叉搜尋樹(也叫二叉查詢樹或者二叉排序樹)
若它的左子樹不為空,則左子樹上所有節點的值均小於它的根節點的值;若它的右子樹不為空,則右子樹上所有節點的值均大於它的根節點的值;它的左、右子樹也分別是二叉排序樹。說明它是一顆有順序的樹,左子樹節點的值小於根節點的值,右子樹節點的值大於根節點的值。 5.平衡二叉樹
它的左右兩個子樹的高度差的絕對值不超過 1,並且左右兩個子樹都是一棵平衡二叉樹。
二叉樹的儲存
以下面的二叉樹為例
二叉樹的順序儲存結構就是用一維陣列儲存二叉樹中的節點,並且節點的儲存位置,也就是陣列的下標要能體現節點之間的邏輯關係。如果某個節點的索引為 i,(假設根節點的索引為 0)則在它左子節點的索引會是 2i+1,以及右子節點會是 2i+2。 2.鏈式儲存
因為在二叉樹中,一個父節點最多隻允許 2 個子節點,所以我們只需要一個儲存資料和左右子節點的指標,這樣的結構就是鏈式儲存,也叫二叉連結串列。
二叉樹的遍歷
以下面的二叉樹為例
1.前序遍歷先訪問根節點,然後前序遍歷左子樹,再前序遍歷右子樹。根據上面的二叉樹前序遍歷結果是 ECBADGFH。
2.中序遍歷
從根節點開始(注意並不是先訪問根節點),中序遍歷根節點的左子樹,然後是訪問根節點,最後中序遍歷右子樹。根據上面的二叉樹中序遍歷結果是 ABCDEFGH。
3.後序遍歷
從左到右先葉子節點後父節點的方式遍歷訪問左右子樹,最後是訪問根節點。根據上面的二叉樹後序遍歷結果是 ABDCFHGE。
4.層序遍歷
從樹的第一層,也就是根節點開始訪問,從上而下逐層遍歷,在同一層中,按從左到右的順序對節點逐個訪問。根據上面的二叉樹層序遍歷結果是 ECGBDFHA。
總結
二叉樹有多種形態,多種型別,多種儲存方式和多種遍歷方法。完全二叉樹和滿二叉樹還是難以理解的,滿二叉樹一定是一棵完全二叉樹,但完全二叉樹不一定是滿二叉樹,主要是「滿」和「完全」的區別分清楚。
由於線性查詢需要遍歷全部資料,在資料量大的時候效率就非常低下,到底有多低,在資料庫有幾百萬幾千萬以上資料量寫過查詢語句的就知道有索引和沒索引的區別。那為什麼有索引的就那麼快呢?當然資料庫的索引不是用二叉樹來實現的,想想如果使用二叉樹來實現,那這個索引樹得多高啊。而是採用更適合資料庫查詢的 B+樹 來實現的,不過 B+樹 也是由二叉樹進化而來的。
二叉搜尋樹由於它是有序的,左子樹節點的值小於根節點的值,右子樹節點的值大於根節點的值,那麼就可以利用二分查詢來查詢對應的值,也叫折半查詢。但二叉搜尋樹最壞的情況下可能變異成斜樹,斜樹的查詢時間複雜度就是 O(n),就跟線性查詢沒區別了。那麼平衡二叉樹就是來解決這個問題的,因為它限定了左右兩個子樹的高度差的絕對值不超過 1,當插入和刪除時,不滿足這種情況時,通過左旋和右旋來保持這個規則。所以,它是時間複雜度是 O(log(n));
PS:清山綠水始於塵,博學多識貴於勤。我有酒,你有故事嗎?公眾號:「清塵閒聊」,歡迎一起談天說地,聊程式碼。