資料結構和演算法 二叉樹基礎(下)二叉查詢樹

2021-09-30 19:09:53 字數 3558 閱讀 5451

二叉查詢樹顧名思義,他是為了快速查詢而生的,不過他除了快速查詢,還支援快速插入,快速刪除,這些都依賴於二叉查詢樹的特殊結構

二叉查詢樹要求,在樹中任意乙個節點,其左子樹的每個節點都要小於這個節點值,其右子樹的每個節點都要大於這個節點的值如下圖:

二叉樹查詢

如何在二叉查詢樹中查詢乙個資料呢? 首先我麼你需要首先選取根節點,如果他等於我們查詢的數就返回,如果查詢的數比這個根節點小,就在左子樹中遞迴查詢,如果查詢的數比根節點大,就在右子樹中遞迴查詢

}}二叉樹插入操作二叉樹插入操作和二叉樹查詢差不多,一般插入都會插入到葉子節點上,所以我們拿到根節點,依次比較要插入的資料和節點的關係

如果插入的資料比根節點大,並且右子樹為空,那麼就直接插入到右子樹上,如果右子樹不為空,那就遞迴遍歷右子樹,查詢插入位置,如果插入的資料比根節點小,且左子樹為空,那就直接插入左子樹,如果左子樹不為空,就遞迴遍歷左子樹,查詢插入的位置

二叉查詢樹的刪除操作這個比較複雜,我們分成三種情況操作

1 如果刪除的節點沒有子節點,我們只需要將其父節點指向要刪除的子節點的指標設定為null,比如圖中的刪除節點55

2 如果要刪除的節點只有乙個子節點(只有左子節點或只有右子節點),我們只需要更父節點中,指向要刪除節點的指標,讓他指向要刪除節點的子節點就行,比如圖中刪除節點13

3 如果要刪除的節點有倆個子節點,這個比較複雜,我們需要找到這個節點的右子樹的最小節點,我們把它替換到要刪除的節點上,然後刪除最小節點,因為這個節點肯定沒有左子節點(如果有左子節點的話就不是最小節點了),所以可以用上邊的規則去刪除,比如刪除圖中的18

if (p == null) return; // 沒有找到

// 要刪除的節點有兩個子節點

if (p.left != null && p.right != null)

p.data = minp.data; // 將 minp 的資料替換到 p 中

p = minp; // 下面就變成了刪除 minp 了

pp = minpp;

} //給要刪除節點的子節點賦值

node child; // p 的子節點

if (p.left != null) child = p.left;

else if (p.right != null) child = p.right;

else child = null;

// 刪除節點是葉子節點或者僅有乙個子節點

if (pp == null) tree = child; // 刪除的是根節點

else if (pp.left == p) pp.left = child;

else pp.right = child;

}中序遍歷二叉查詢樹,就會輸出乙個有序資料序列,時間複雜度為o(n),非常高效,因此二叉查詢樹也叫做二叉排序樹之前我們都是沒有重複的資料,如果樹中有重複的資料該怎麼辦呢?有倆中方法

第一種 直接在每個節點處放置乙個鍊錶,儲存相同的值

第二種 不好理解,但更加優雅

每當插入的值在樹中有相同節點,那麼就把他插入到這個節點的右子樹中尋找合適的位置插入,就是當做大於這個節點去操作

但查詢資料的時候,遇到了值相同的節點,我們並不停止查詢,而是在右子樹中繼續查詢,直到遇到葉子節點,這樣就可以查詢到所有和值相同的節點

對於刪除操作,我們也需要查詢出所有需要刪除的節點,按照上方的方法依次刪除

實際上,二叉查詢樹的形態各式各樣,例如下面同一組資料,三種不同的形態,第一種已經退化成了乙個鍊錶,時間複雜度為o(n)

第乙個是最糟糕的一種情況,我們分析一下乙個理想的二叉查詢樹(完全二叉樹和滿二叉樹)的時間複雜度

從前面的**看,不管插入刪除和查詢,時間複雜度都和樹的高度成正比,也就是o(height),那現在問題變成了如何求乙個樹的高度

我們可以看出n個結點,樹的第一層1個結點,第二層2個節點,第三層4個,第k層2k-1個結點

不過對於完全二叉樹來說,就不遵守上邊的規律了,假如有l層,那麼完全二叉樹的結點在1–2l-1個之間,我們每一層的節點加起來就是n,得出公式

n >= 1+2+4+8+...+2^(l-2)+1

n <= 1+2+4+8+...+2^(l-2)+2^(l-1)

借助等比數列公式求和,可以計算出,完全二叉樹的高度小於等於log2n,時間複雜度為o(logn)

我們可以看出二叉查詢樹節點分布極度不平衡,他的效能肯定不滿足我們的要求,,我們需要一種任何時候左右子樹都比較平衡的二叉查詢樹,這個就是我們之後要講的平衡二叉查詢樹

雜湊表查詢,刪除,插入時間複雜度o(1),而二叉查詢樹的查詢,刪除,插入的時間複雜度為o(logn),二叉樹並沒有什麼優勢,為什麼要用他呢

有以下幾個原因

1 雜湊表時無序儲存,要輸出有序資料,需要重新排序,而二叉查詢樹只需要中序遍歷就能得到有序資料

2 雜湊表擴容耗時,當遇到雜湊衝突就會效能不穩,但是我們平時用到的平衡二叉查詢樹可以穩定在o(logn)

3由於有雜湊表有雜湊衝突的存在,還有雜湊函式的耗時,所以o(1),不一定比o(logn)小

4雜湊錶比二叉樹設計複雜,需要考慮到雜湊衝突,雜湊函式的設計,擴容,縮容等,而平衡二叉樹只需要考慮平衡就行,這個方案比較固定穩定

資料結構 二叉樹 反轉二叉樹

include using namespace std define maxsize 1000 struct binary tree node class queue queue queue void queue push binary tree node btn binary tree node ...

資料結構 樹和二叉樹 二叉線索樹

遍歷二叉樹就是以一定的規則將二叉樹中的結點排列成乙個線性序列,從而得到二叉樹結點的各種遍歷序列。其實質就是對乙個非線性結構進行線性化操作,使在這個訪問序列中每乙個結點 除了第乙個和最後乙個 都有乙個直接前驅和直接後繼。在二叉樹的鏈式儲存中,只能體現出父子關係,不能直接得到結點在遍歷中的前驅和後繼。前...

資料結構 樹結構 二叉樹 完全二叉樹 滿二叉樹

樹結構是一種描述非線性層次關係的資料結構。除根結點外,其餘每個結點有且僅有乙個直接前驅。每個結點可以有任意多個直接後繼。英文名詞表示 tree,root,node,leaf,edge,child,subtree 要麼二叉樹沒有根結點,是一棵空樹。要麼二叉樹由根結點,左子樹,右子樹組成,且左子樹和右子...