二叉搜尋樹2

2022-06-18 19:48:12 字數 3059 閱讀 5565

1.判斷bst的合法性

這裡是有坑的,如果很簡單的認為只需要節點與左子樹和右子樹進行比較的話,那麼**就是

boolean isvalidbst(treenode root)
但是這個演算法出現了錯誤,bst 的每個節點應該要小於右邊子樹的所有節點,下面這個二叉樹顯然不是 bst,因為節點 10 的右子樹中有乙個節點 6,但是我們的演算法會把它判定為合法 bst:

出現問題的原因在於,對於每乙個節點root,**值檢查了它的左右孩子節點是否符合左小右大的原則;但是根據 bst 的定義,root的整個左子樹都要小於root.val,整個右子樹都要大於root.val

問題是,對於某乙個節點root,他只能管得了自己的左右子節點,怎麼把root的約束傳遞給左右子樹呢?

請看正確的**:

boolean isvalidbst(treenode root) 

/* 限定以 root 為根的子樹節點必須滿足 max.val > root.val > min.val */

boolean isvalidbst(treenode root, treenode min, treenode max)

我們通過使用輔助函式,增加函式引數列表,在引數中攜帶額外資訊,將這種約束傳遞給子樹的所有節點,這也是二叉樹演算法的乙個小技巧吧

!!!!!!!!!!!!!!!!!!!!!!!!!!!!在遞迴的題目中,通過額外的引數來加以限制的技巧用的很多。

2.在 bst 中搜尋乙個數

如果是在二叉樹中尋找元素,可以這樣寫**:

boolean isinbst(treenode root, int target)
首先這種寫法中的()|| () 就很有技巧,表示兩種之中只要有乙個符合就行,很常用

但是這種寫法針對的是普通二叉樹,完全沒有利用二叉搜尋樹的特性那麼應該如何充分利用資訊,把 bst 這個「左小右大」的特性用上?

很簡單,其實不需要遞迴地搜尋兩邊,類似二分查詢思想,根據targetroot.val的大小比較,就能排除一邊。我們把上面的思路稍稍改動:

boolean isinbst(treenode root, int target)
這裡可以抽象出一套針對 bst 的遍歷框架:!!!!!!!!!!!!!!!!!!!!!

void bst(treenode root, int target)
這個**框架其實和二叉樹的遍歷框架差不多,無非就是利用了 bst 左小右大的特性而已。

3.在 bst 中插入乙個數

對資料結構的操作無非遍歷 + 訪問,遍歷就是「找」,訪問就是「改」。具體到這個問題,插入乙個數,就是先找到插入位置,然後進行插入操作。

上乙個問題,我們總結了 bst 中的遍歷框架,就是「找」的問題。直接套框架,加上「改」的操作即可。一旦涉及「改」,函式就要返回treenode型別,並且對遞迴呼叫的返回值進行接收

框架與上圖一樣:

treenode deletenode(treenode root, int key)  else if (root.val > key)  else if (root.val < key) 

return root;

}

至於這裡刪除的情況,可以做一下分類討論的:

如果刪除的是葉子節點,即bts的末尾,那麼直接刪除

if (root.left == null && root.right == null)

return null;

如果只有乙個非空子節點,那麼它要讓這個孩子接替自己的位置。

// 排除了情況 1 之後

if (root.left == null) return root.right;

if (root.right == null) return root.left;

如果該節點有有兩個子節點,麻煩了,為了不破壞 bst 的性質,a必須找到左子樹中最大的那個節點,或者右子樹中最小的那個節點來接替自己。我們以第二種方式講解。

if (root.left != null && root.right != null)
總體**如下:

treenode deletenode(treenode root, int key)  else if (root.val > key)  else if (root.val < key) 

return root;

}treenode getmin(treenode node)

刪除操作就完成了。注意一下,這個刪除操作並不完美,因為我們一般不會通過root.val = minnode.val修改節點內部的值來交換節點,而是通過一系列略微複雜的鍊錶操作交換rootminnode兩個節點。

因為具體應用中,val域可能會是乙個複雜的資料結構,修改起來非常麻煩;而鍊錶操作無非改一改指標,而不會去碰內部資料。

不過這裡我們暫時忽略這個細節,旨在突出 bst 基本操作的共性,以及借助框架逐層細化問題的思維方式。

1、如果當前節點會對下面的子節點有整體影響,可以通過輔助函式增長引數列表,借助引數傳遞資訊。

2、在二叉樹遞迴框架之上,擴充套件出一套 bst **框架:

void bst(treenode root, int target)
3、根據**框架掌握了 bst 的增刪查改操作。

二叉搜尋樹2

include using namespace std struct node void insertt node tree,int value 注意要加 取位址符 才能每次更新tree 否則不能實現對tree的改變 相當 於swap交換兩個值,不加取位址只能相當於乙個函式,裡邊的tree不會 時時...

二叉搜尋樹 二叉搜尋樹

題目 二叉搜尋樹 time limit 2000 1000 ms j a others memory limit 32768 32768 k j a others total submission s 6945 accepted submission s 3077 problem descripti...

二叉搜尋樹 修剪二叉搜尋樹

第一反應是重構,看來別人的解答發現,其實不用重構那麼複雜。treenode trimbst treenode root,int low,int high if root val high 下一層處理完左子樹的結果賦給root left,處理完右子樹的結果賦給root right。root left ...