在這一小節中,我們會介紹二分搜尋樹中如何查詢最小最大值、最小最大值的刪除、刪除任意節點(刪除只有左孩子的節點、刪除只有右孩子的節點和刪除左右孩子都存在的節點);下面我們一一講解:
一. 查詢最小最大值及其刪除
- 查詢最小最大值
其實很簡單,首先我們想一想二分搜尋樹的定義就會明白,最小值在以跟節點的左孩子節點的左孩子節點………上,看圖吧:
直接看程式碼吧!
在public中定義:
// 尋找二分搜尋樹的最小的鍵值
Node* minmum(){
assert(count != 0);
Node* minnode = minmum(root);
return minnode->left;
}
在private中定義:
// 尋找二分搜尋樹的最小的鍵值
Node* minmum(Node* node){
if(node != NULL){
minmum(node->left);
}
return node;
對於最大值嘛,邏輯一樣的這裡就省略了
直接上程式碼吧!
在public中定義:
// 尋找二分搜尋樹的最大的鍵值
Node* maxmum(){
assert(count != 0);
Node* maxnode = maxmum(root);
return maxnode ->right;
}
在private中定義:
// 尋找二分搜尋樹的最大的鍵值
Node* maxmum(Node* node){
if(node != NULL){
maxmum(node->right);
}
return node;
}
2.刪除最小值最大值
以最大值為例:
其實就是將最大值找到,然後刪除(
我們在public中定義:
//刪除最大值的node
void removeMax(){
if(root){
root = removeMax(root);
}
}
在private中定義:
//從二分搜尋樹中刪除最大值所在的節點
Node* removeMax(Node* node){
if(node->right == NULL){
Node* NODE = node->left;
delete node;
count--;
return NODE;
}
node->right = removeMax(node->right);
return node;
}
同理,刪除最小值也就是將最小值查詢到,然後刪除:
我們依然在public中定義:
void removeMin(){
if(root){
root = removeMin(root);
}
}
在private中定義:
Node* removeMin(Node* node){
if(node->left == NULL){
Node* NODE = node->right;
delete node;
return NODE;
}
node->left = removeMin(node->left);
return node;
}
二.刪除二分搜尋樹中任意節點
- 情況一:刪除只有左孩子(右孩子)的節點
例如下圖,我們刪除節點58,但此時它存在左孩子,而從二分搜尋樹的定義可知如果將58刪除,就應該將50節點作為41節點的右孩子節點;所以我們需要在刪除58節點之前將50節點變成41節點的右孩子。
最後41節點的右子樹應該變成:
41
\
50
/ \
42 53
同理對於只有右孩子的節點是相同的邏輯(在這裡省略)
下面看程式碼:(c++實現)
在public中定義:
//刪除二分搜尋樹中值的任意節點
void remove( Key key){
root = remove(root, key);
}
在private中定義:
//刪除二分搜尋樹中值的任意節點
Node* remove(Node* node, Key key){
//判斷node是否為空
if(node == NULL) {
return NULL;
}
//先找到需要刪除的值的node
else if(key < node->key) { //key為需要刪除的,node->key為當前位置
node->left = remove(node->left, key);
return node;
}
else if(key > node->key) {
node->right = remove(node->right, key);
return node;
}
//這裡就找到了需要delete的node
else { //key == node->key)
// 待刪除節點左子樹為空的情況
if(node->left == NULL){
Node* rightNode = node->right;
delete node;
count--;
return rightNode;
}
// 待刪除節點右子樹為空的情況
if(node->right == NULL){
Node* leftNode = node->left;
delete node;
count--;
return leftNode;
}
}
- 情況二:刪除同時擁有左右孩子的節點
如圖,我們現在要刪除圖中58節點,如果直接刪除58則41節點的右子樹就不再是在該二分搜尋樹中了
所以,現在我們需要將59拿出來,作為41節點的右孩子(這裡只有59,53位置滿足條件)
繼續往下看:
這裡需要將原來58節點的右孩子變成59節點的右孩子s->right = delMin(d->right)
s->right = delMin(d->right)就變成了下圖:
再將50節點變成59的左孩子s->left = d->left
:
最後將58節點刪除即可;利用遞迴將59節點返回給41節點(成為41節點的右孩子)。
下面看程式碼:
在public中定義:
//刪除二分搜尋樹中值的任意節點
void remove( Key key){
root = remove(root, key);
}
在private中定義:
//刪除二分搜尋樹中值的任意節點
Node* remove(Node* node, Key key){
//判斷node是否為空
if(node == NULL) {
return NULL;
}
//先找到需要刪除的值的node
else if(key < node->key) { //key為需要刪除的,node->key為當前位置
node->left = remove(node->left, key);
return node;
}
else if(key > node->key) {
node->right = remove(node->right, key);
return node;
}
//這裡就找到了需要delete的node
else { //key == node->key)
// 待刪除節點左子樹為空的情況
if(node->left == NULL){
Node* rightNode = node->right;
delete node;
count--;
return rightNode;
}
// 待刪除節點右子樹為空的情況
if(node->right == NULL){
Node* leftNode = node->left;
delete node;
count--;
return leftNode;
}
// 待刪除節點左右子樹都不為為空的情況
Node *succeer =new Node(minmum(node->right)); //找到最小key值的節點返回給succeer
count ++;
succeer->right = removeMin(node->right); //將最小key值的node刪除,並將返回值給succeer的右孩子
succeer->left = node->left;
delete node;
count--;
return succeer;
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結