二叉查詢樹要求,在樹中的任意乙個節點,其左子樹中的每個節點的值,都要小於這個節點的值,而右子樹節點的值都大於這個節點的值。
/** * 刪除的情況比較複雜
* 第一種情況是,如果要刪除的節點沒有子節點,我們只需要直接將父節點中,指向要刪除節點的
* 指標置為 null。
* * 第二種情況是,如果要刪除的節點只有乙個子節點(只有左子節點或者右子節點),我們只需要
* 更新父節點中,指向要刪除節點的指標,讓它指向要刪除節點的子節點就可以了。
* * 第三種情況是,如果要刪除的節點有兩個子節點,這就比較複雜了。我們需要找到這個節點的右
* 子樹中的最小節點,把它替換到要刪除的節點上(比要刪除的節點大一點點的數)。
* 然後再刪除掉這個最小節點(父節點的指標改變),因為最小節點肯定沒有左子節點(如果有左子結點,那就不是最小節點了),
* 所以,我們可以應用上面兩條規則來刪除這個最小節點
* * 注:左子樹最大節點是可能有子節點的,左子樹總是小於根節點的,右子樹總是大於根節點的
** @param data
*/public
void
delete
(int data)
else}if
(treenode == null)
if(treenode.
getleftnode()
!= null && treenode.
getrightnode()
!= null)
treenode.
setdata
(minnode.
getdata()
);//接下來刪除這個最小節點,走下面的流程
treenode = minnode;
parentnode = minparentnode;
}//證明有乙個節點或者0個節點的時候
treenode child;
//刪除節點的子節點
if(treenode.
getleftnode()
!= null)
else
if(parentnode == null)
if(parentnode.
getleftnode()
== treenode)
if(parentnode.
getrightnode()
== treenode)
}public
void
printnode()
private
void
inprint
(treenode treenode)
system.out.
println
(treenode.
getdata()
);if(treenode.
getrightnode()
!=null)
}}通過上面的分析可知,我們的查詢刪除新增,其時間複雜度都和樹的高度成正比,為o(height),遍歷的時間複雜度是o(n),樹的高度等於最大層數-1
包含 n個節點的完全二叉樹中,第一層包含 1 個節點,第二層包含 2 個節點,第三層包含 4 個節點。
依次類推,下面一層節點個數是上一層的 2 倍,第 k 層包含的節點個數就是 2^(k-1)。
不過,對於完全二叉樹來說,最後一層的節點個數有點兒不遵守上面的規律了。它包含的節點個
數在 1 個到 2^(l-1) 個之間(我們假設最大層數是 l)。如果我們把每一層的節點個數加起來
就是總的節點個數 n。也就是說,如果節點的個數是 n,那麼 n 滿足這樣乙個關係:
n >= 1+2+4+8+…+2^(l-2)+1 最後一層只有1個借助等比數列的求和公式,我們可以計算出,l 的範圍是 [log 2^(n+1), log2^(n) +1]。n <= 1+2+4+8+…+2^(l-2) + 2^(l-1) 最後一層滿了
完全二叉樹的層數小於等於 log2^(n) +1,
也就是說,完全二叉樹的高度小於等於 log2^n。
顯然,極度不平衡的二叉查詢樹,它的查詢效能肯定不能滿足我們的需求。我們需要構建一種不
管怎麼刪除、插入資料,在任何時候,都能保持任意節點左右子樹都比較平衡的二叉查詢樹,一種特殊的二叉查詢樹,平衡二叉查詢樹。平衡二叉查詢樹的高度接近 log2^n,所以插入、刪除、查詢操作的時間複雜度也比較穩定,是 o(logn)。
相對於hash表來講,其刪除,增加,查詢的時間複雜度都是o(1),為什麼還要用二叉查詢樹呢;
第一,雜湊表中的資料是無序儲存的,如果要輸出有序的資料,需要先進行排序。而對於二叉查詢樹來說,我們只需要中序遍歷,就可以在 o(n) 的時間複雜度內,輸出有序的資料序列。
第二,雜湊表擴容耗時很多,而且當遇到雜湊衝突時,效能不穩定,儘管二叉查詢樹的效能不穩定,但是在工程中,我們最常用的平衡二叉查詢樹的效能非常穩定,時間複雜度穩定在o(logn)。
第三,籠統地來說,儘管雜湊表的查詢等操作的時間複雜度是常量級的,但因為雜湊衝突的存在,這個常量不一定比 logn 小,所以實際的查詢速度可能不一定比 o(logn) 快。加上雜湊函式的耗時,也不一定就比平衡二叉查詢樹的效率高。
第四,雜湊表的構造比二叉查詢樹要複雜,需要考慮的東西很多。比如雜湊函式的設計、衝突解決辦法、擴容、縮容等。平衡二叉查詢樹只需要考慮平衡性這乙個問題,而且這個問題的解決方案比較成熟、固定。
最後,為了避免過多的雜湊衝突,雜湊表裝載因子不能太大,特別是基於開放定址法解決衝突的雜湊表,不然會浪費一定的儲存空間。
綜合這幾點,平衡二叉查詢樹在某些方面還是優於雜湊表的,所以,這兩者的存在並不衝突。我們在實際的開發過程中,需要結合具體的需求來選擇使用哪乙個。
二叉樹 二叉查詢樹
構建二叉樹,判斷是否為二叉查詢樹,遞迴先序遍歷,非遞迴中序遍歷 include include include include using namespace std 二叉樹結點 struct treenode 鍊錶結點 struct listnode struct tempnodetempnode...
二叉樹 二叉查詢樹
二叉樹 binary tree 一種樹型結構,每個節點最多擁有兩個節點。如下圖 幾種型別的二叉樹 1.full binary tree 每個節點的孩子數 是 0 或者 2.對高度沒有要求。如下圖 2.perfect binary tree 這個就是最完美的樹,顧名思義,所有葉子節點都有相同的深度,並...
查詢演算法總結 3 二叉查詢樹
當所有的靜態查詢結構新增和刪除乙個資料的時候,整個結構都需要重建。這對於常常需要在查詢過程中動態改變資料而言,是災難性的。因此人們就必須去尋找高效的動態查詢結構,我們在這討論乙個非常常用的動態查詢樹 二叉查詢樹 二叉查詢樹的特點 1 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值 2 ...