二叉搜尋樹刪除節點就涉及到結構調整了。
❞給定乙個二叉搜尋樹的根節點 root 和乙個值 key,刪除二叉搜尋樹中的 key 對應的節點,並保證二叉搜尋樹的性質不變。返回二叉搜尋樹(有可能被更新)的根節點的引用。
一般來說,刪除節點可分為兩個步驟:
首先找到需要刪除的節點;如果找到了,刪除它。說明:要求演算法時間複雜度為 o(h),h 為樹的高度。
示例:
搜尋樹的節點刪除要比節點增加複雜的多,有很多情況需要考慮,做好心裡準備。
遞迴三部曲:
說道遞迴函式的返回值,在二叉樹:搜尋樹中的插入操作中通過遞迴返回值來加入新節點, 這裡也可以通過遞迴返回值刪除節點。
**如下:
treenode* deletenode(treenode* root, int key)
遇到空返回,其實這也說明沒找到刪除的節點,遍歷到空節點直接返回了
if (root == nullptr) return root;
這裡就把平衡二叉樹中刪除節點遇到的情況都搞清楚。
有以下五種情況:
第五種情況有點難以理解,看下面動畫:
動畫中顆二叉搜尋樹中,刪除元素7, 那麼刪除節點(元素7)的左孩子就是5,刪除節點(元素7)的右子樹的最左面節點是元素8。
將刪除節點(元素7)的左孩子放到刪除節點(元素7)的右子樹的最左面節點(元素8)的左孩子上,就是把5為根節點的子樹移到了8的左孩子的位置。
要刪除的節點(元素7)的右孩子(元素9)為新的根節點。.
這樣就完成刪除元素7的邏輯,最好動手畫乙個圖,嘗試刪除乙個節點試試。
**如下:
if (root->val == key)
cur->left = root->left; // 把要刪除的節點(root)左子樹放在cur的左孩子的位置
treenode* tmp = root; // 把root節點儲存一下,下面來刪除
root = root->right; // 返回舊root的右孩子作為新root
delete tmp; // 釋放節點記憶體(這裡不寫也可以,但c++最好手動釋放一下吧)
return root;}}
if (root->val > key) root->left = deletenode(root->left, key);
if (root->val right = deletenode(root->right, key);
return root;
「整體**如下:(注釋中:情況1,2,3,4,5和上面分析嚴格對應)」
class solution
cur->left = root->left; // 把要刪除的節點(root)左子樹放在cur的左孩子的位置
treenode* tmp = root; // 把root節點儲存一下,下面來刪除
root = root->right; // 返回舊root的右孩子作為新root
delete tmp; // 釋放節點記憶體(這裡不寫也可以,但c++最好手動釋放一下吧)
return root;}}
if (root->val > key) root->left = deletenode(root->left, key);
if (root->val right = deletenode(root->right, key);
return root;}};
這裡我再介紹一種通用的刪除,普通二叉樹的刪除方式(沒有使用搜尋樹的特性,遍歷整棵樹),用交換值的操作來刪除目標節點。
**中目標節點(要刪除的節點)被操作了兩次:
思路有點繞,感興趣的同學可以畫圖自己理解一下。
**如下:(關鍵部分已經注釋)
class solution
treenode *cur = root->right;
while (cur->left)
swap(root->val, cur->val); // 這裡第一次操作目標值:交換目標值其右子樹最左面節點。
}root->left = deletenode(root->left, key);
root->right = deletenode(root->right, key);
return root;}};
這個**是簡短一些,思路也巧妙,但是不太好想,實操性不強,推薦第一種寫法!
刪除節點的迭代法還是複雜一些的,但其本質我在遞迴法里都介紹了,最關鍵就是刪除節點的操作(動畫模擬的過程)
**如下:
class solution
cur->left = target->left;
return target->right;
}public:
treenode* deletenode(treenode* root, int key)
if (pre == nullptr)
// pre 要知道是刪左孩子還是右孩子
if (pre->left && pre->left->val == key)
if (pre->right && pre->right->val == key)
return root;}};
讀完本篇,大家會發現二叉搜尋樹刪除節點比增加節點複雜的多。
「因為二叉搜尋樹新增節點只需要在葉子上新增就可以的,不涉及到結構的調整,而刪除節點操作涉及到結構的調整」。
這裡我們依然使用遞迴函式的返回值來完成把節點從二叉樹中移除的操作。
「這裡最關鍵的邏輯就是第五種情況(刪除乙個左右孩子都不為空的節點),這種情況一定要想清楚」。
而且就算想清楚了,對應的**也未必可以寫出來,所以「這道題目即考察思維邏輯,也考察**能力」。
遞迴中我給出了兩種寫法,推薦大家學會第一種(利用搜尋樹的特性)就可以了,第二種遞迴寫法其實是比較繞的。
最後我也給出了相應的迭代法,就是模擬遞迴法中的邏輯來刪除節點,但需要乙個pre記錄cur的父節點,方便做刪除操作。
迭代法其實不太容易寫出來,所以如果是初學者的話,徹底掌握第一種遞迴寫法就夠了。
「就醬,又是乾貨滿滿的一篇,順便**給身邊需要的同學吧!」
-------end-------
我將演算法學習相關的資料已經整理到了github :裡面還有leetcode刷題攻略、各個型別經典題目刷題順序、思維導圖看一看一定會有所收穫,如果給你有幫助給乙個star支援一下吧!
趕緊給「**隨想錄」加乙個星標吧,方便第一時間閱讀文章。往期
精彩回顧二叉樹:搜尋樹中的插入操作二叉樹:搜尋樹的公共祖先問題本週小結!(二叉樹系列四)二叉樹:公共祖先問題二叉樹:我的眾數是多少?二叉樹:搜尋樹的最小絕對差二叉樹:我是不是一棵二叉搜尋樹二叉樹:二叉搜尋樹登場!二叉樹:合併兩個二叉樹本週小結!(二叉樹系列三)二叉樹:構造一棵最大的二叉樹二叉樹:構造二叉樹登場!
「**隨想錄」期待你的關注!
每天8:35準時推送一道經典演算法題目,推送的每道題目都不是孤立的,而是由淺入深,環環相扣,幫你梳理演算法知識脈絡,輕鬆學演算法!
樹 二叉樹 二叉搜尋樹
給定乙個二叉樹,判斷其是否是乙個有效的二叉搜尋樹。假設乙個二叉搜尋樹具有如下特徵 節點的左子樹只包含小於當前節點的數。節點的右子樹只包含大於當前節點的數。所有左子樹和右子樹自身必須也是二叉搜尋樹。示例 1 輸入 2 13輸出 true 示例 2 輸入 5 14 3 6輸出 false 解釋 輸入為 ...
二叉搜尋樹 二叉搜尋樹
題目 二叉搜尋樹 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...
二叉樹 還原二叉樹 二叉搜尋樹
先序遍歷的特點 先遍歷根結點,再遍歷左子樹,最後再遍歷右子樹 中序遍歷的特點 先遍歷左子樹,再遍歷根結點,最後再遍歷右子樹 後序遍歷的特點 先遍歷左子樹,再遍歷右子樹,最後再遍歷根結點 舉例 先序遍歷 a b d f g h i e c 中序遍歷 f d h g i b e a c 如上,根據先序遍...