3 分鐘理解完全二叉樹、平衡二叉樹、二叉查詢樹
大傢伙,我是張拭心,今天給大家分享的是常見的三種二叉樹:完全二叉樹、平衡二叉樹、二叉查詢樹,至於標題的 3 分鐘理解是我胡謅的,能不能這麼快就看你領悟能力了哈哈。
完全二叉樹
完全二叉樹是一種特殊的二叉樹,滿足以下要求:
所有葉子節點都出現在 k 或者 k-1 層,而且從 1 到 k-1 層必須達到最大節點數;
第 k 層可以不是滿的,但是第 k 層的所有節點必須集中在最左邊。
需要注意的是不要把完全二叉樹和“滿二叉樹”搞混了,完全二叉樹不要求所有樹都有左右子樹,但它要求:任何一個節點不能只有左子樹沒有右子樹
葉子節點出現在最後一層或者倒數第二層,不能再往上
用一張圖對比下“完全二叉樹”和“滿二叉樹”:
當我們用陣列實現一個完全二叉樹時,葉子節點可以按從上到下、從左到右的順序依次新增到陣列中,然後知道一個節點的位置,就可以輕鬆地算出它的父節點
以上面圖中完全二叉樹為例,標號為 2 的節點,它在陣列中的位置也是 2,它的父節點就是 (k/2 = 1),它的孩子節點分別是 (2k=4) 和 (2k+1=5),別的節點也是類似。
完全二叉樹使用場景:
根據前面的學習,我們瞭解到完全二叉樹的特點是:“葉子節點的位置比較規律”。因此在對資料進行排序或者查詢時可以用到它,比如堆排序就使用了它,後面學到了再詳細介紹。
二叉查詢樹
二叉樹的提出其實主要就是為了提高查詢效率,比如我們常用的HashMap
在處理雜湊衝突嚴重時,拉鍊過長導致查詢效率降低,就引入了紅黑樹。
我們知道,二分查詢可以縮短查詢的時間,但是它要求查詢的資料必須是有序的。每次查詢、操作時都要維護一個有序的資料集,於是有了二叉查詢樹這個概念。
二叉查詢樹(又叫二叉排序樹),它是具有下列性質的二叉樹:
若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
若右子樹不空,則右子樹上所有結點的值均大於或等於它的根結點的值;
左、右子樹也分別為二叉排序樹。
如下圖所示:
也就是說,二叉查詢樹中,左子樹都比節點小,右子樹都比節點大,遞迴定義。
根據二叉排序樹這個特點我們可以知道:二叉排序樹的中序遍歷一定是從小到大的。
比如上圖,中序遍歷結果是:
1 3 4 6 7 8 10 13 14
二叉排序樹的效能
在最好的情況下,二叉排序樹的查詢效率比較高,是 O(logn),其訪問效能近似於折半查詢;
但最差時候會是 O(n),比如插入的元素是有序的,生成的二叉排序樹就是一個連結串列,這種情況下,需要遍歷全部元素才行(見下圖 b)。
如果我們可以保證二叉排序樹不出現上面提到的極端情況(插入的元素是有序的,導致變成一個連結串列),就可以保證很高的效率了。
但這在插入有序的元素時不太好控制,按二叉排序樹的定義,我們無法判斷當前的樹是否需要調整。
因此就要用到平衡二叉樹(AVL 樹)了。
平衡二叉樹
平衡二叉樹的提出就是為了保證樹不至於太傾斜,儘量保證兩邊平衡。因此它的定義如下:
平衡二叉樹要麼是一棵空樹
要麼保證左右子樹的高度之差不大於 1
子樹也必須是一顆平衡二叉樹
也就是說,樹的兩個左子樹的高度差別不會太大。
那我們接著看前面的極端情況的二叉排序樹,現在用它來構造一棵平衡二叉樹。
以 12 為根節點,當新增 24 為它的右子樹後,根節點的左右子樹高度差為 1,這時還算平衡,這時再新增一個元素 28:
這時根節點 12 覺得不平衡了,我左孩子一個都沒有,右邊都有倆了,超過了之前說的最大為 1,不行,給我調整!
於是我們就需要調整當前的樹結構,讓它進行旋轉。
因為最後一個節點加到了右子樹的右子樹,就要想辦法給右子樹的左子樹加點料,因此需要逆時針旋轉,將 24 變成根節點,12 右旋成 24 的左子樹,就變成了這樣(有點醜哈哈):
這時又恢復了平衡,再新增 37 到 28 的右子樹,還算平衡:
這時如果再新增一個 30,它就需要在 37 的左子樹:
這時我們可以看到這個樹又不平衡了,以 24 為根節點的樹,明顯右邊太重,左邊太稀,想要保持平衡就 24 得讓位給 28,然後變成這樣:
醜了點,但的確保持了平衡。
依次類推,平衡二叉樹在新增和刪除時需要進行旋轉保持整個樹的平衡,內部做了這麼複雜的工作後,我們在使用它時,插入、查詢的時間複雜度都是 O(logn),效能已經相當好了。
總結
閱讀完這篇文章,相信你對“完全二叉樹、二叉查詢樹和平衡二叉樹”這三個二叉樹有了更加深刻的認識,有了這個基礎,再去看 B+ B- 紅黑樹,就相對容易些了,後面有機會的話我再寫兩篇這種的。
推薦閱讀