資料結構與演算法C++之二分搜尋樹的刪除節點,刪除任意節點
阿新 • • 發佈:2018-12-22
上篇部落格介紹了怎樣刪除二分搜尋樹的最大值和最小值節點,下面介紹怎樣刪除樹的任意一個節點
上篇刪除最大值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有左節點,
同樣,刪除最小值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有右節點
(1)刪除只有左節點的節點,如刪除節點58,只需要將58刪除掉,然後將其左節點50替換其位置即可
(2)刪除只有右節點的節點,如刪除節點58,只需要將58刪除掉,然後將其右節點60替換其位置即可
(3)刪除既有左節點又有右節點的節點是最複雜的操作,在1962年,Hibbard提出了一種刪除方法,稱為 Habbard Deletion,如下圖所示,如果需要刪除既有左節點又有右節點的節點58(稱為d),那麼需要找出58的右節點中最小的那個節點s,那麼s就是節點59,將節點59放到58的位置即可
具體操作步驟為,首先刪除掉s節點,然後將s節點的右節點指向原來d的右節點60,將s的左節點指向原來d的左節點50
最後就可以徹底刪除節點58了,將節點59作為新的在該位置的節點
下面是刪除節點的程式實現
#include <iostream>
#include <vector>
#include <string>
#include <ctime> //time()函式
#include <queue>
#include <cassert>
#include "FileOps.h"
using namespace std;
template<typename Key, typename Value>
class BST{
private:
struct Node{
Key key;
Value value;
Node *left;
Node *right;
Node(Key key, Value value){
this->key = key;
this->value = value;
this->left = this-> right = NULL;
}
Node(Node *node){
this->key = node->key;
this->value = node->value;
this->left = node->left;
this->right = node->right;
}
};
Node *root;
int count;
public:
BST(){
root = NULL;
count = 0;
}
~BST(){
// TODO: ~BST()
destroy(root);
}
int size(){
return count;
}
bool isEmpty(){
return count == 0;
}
void insert(Key key, Value value){
root = insert(root, key, value);
}
bool contain(Key key){
return contain(root, key);
}
Value *search(Key key){
return search(root, key);
}
//前序遍歷
void preOrder(){
preOrder(root);
}
//中序遍歷
void inOrder(){
inOrder(root);
}
//後序遍歷
void postOrder(){
postOrder(root);
}
//層序遍歷
void levelOrder(){
quene<Node*> q;
q.push(root);
while( !q.empty() ){
Node *node = q.front();
q.pop();
cout<<node->key<<endl;
if (node->left)
q.push(node->left);
if (node->right)
q.push(node->right);
}
}
//尋找最小的鍵值
Key minimum(){
assert(count != 0);
Node* minNode = minimum(root);
return minNode->key;
}
//尋找最大的鍵值
Key maximum(){
assert(count != 0);
Node* maxNode = maximum(root);
return maxNode->key;
}
//從二叉樹中刪除最小值所在節點
void removeMin(){
if (root)
root = removeMin(root);
}
//從二叉樹中刪除最大值所在節點
void removeMax(){
if (root)
root = removeMax(root);
}
//從二叉樹中刪除鍵值為key的節點
void remove(Key key){
root = remove(root, key);
}
private:
//向以node為根的二叉搜尋樹中,插入節點(key, value)
//返回插入新節點後的二叉搜尋樹的根
//遞迴插入
Node* insert(Node *node, Key key, Value value){
if (node == NULL){
count++;
return new Node(key, value);
}
if(node->key == key)
node->value = value;
else if (key < node->key)
node->left = insert(node->left, key, value);
else
node->right = insert(node->right, key, value);
return node;
}
//查詢以node為根的二叉搜尋樹中是否包含鍵值為key的節點
bool contain(Node *node, Key key){
if (node == NULL){
return false;
}
if (key == node->key)
return true;
else if (key < node->key)
return contain(node->left, key);
else
return contain(node->right, key);
}
//在以node為根的二叉搜尋樹中查詢key對應的value
Value* search(Node *node, Key key){
if (node == NULL)
return NULL;
if (key == node->key)
return &(node->value);
else if (key < node->key)
return search(node->left, key);
else
return search(node->right, key);
}
//對以node為根的二叉搜尋樹進行前序遍歷
void preOrder(Node* node){
if (node != NULL){
cout<<node->key<<endl;
preOrder(node->left);
preOrder(node->right);
}
}
//對以node為根的二叉搜尋樹進行中序遍歷
void inOrder(Node *node){
if (node != NULL){
inOrder(node->left);
cout<<node->key<<endl;
inOrder(node->right);
}
}
//對以node為根的二叉搜尋樹進行後序遍歷
void postOrder(Node *node){
if(node != NULL){
postOrder(node->left);
postOrder(node->right);
cout<<node->key<<endl;
}
}
void destroy(Node *node){
if (node != NULL){
destroy(node->left);
destroy(node->right);
delete node;
count--;
}
}
//在以node為根的二叉搜尋樹中,返回最小鍵值的節點
Node* minimum(Node *node){
if (node->left == NULL)
return node;
return minimum(node->left);
}
//在以node為根的二叉搜尋樹中,返回最大鍵值的節點
Node* maximum(Node *node){
if (node->right == NULL)
return node;
return maximum(node->right);
}
//刪除掉以node為根的二分搜尋樹中的最小節點
//返回刪除節點後新的二分搜尋樹的根
Node* removeMin(Node* node){
if (node->left == NULL){
Node *rightNode = node->right;
delete node;
count--;
return rightNode;
}
node->left = removeMin(node->left);
return node;
}
//刪除掉以node為根的二分搜尋樹中的最大節點
//返回刪除節點後新的二分搜尋樹的根
Node* removeMax(Node* node){
if (node->right == NULL){
Node *leftNode = node->left;
delete node;
count--;
return leftNode;
}
node->right = removeMin(node->right);
return node;
}
//刪除掉以node為根的二分搜尋樹中鍵值為key的節點
//返回刪除節點後新的二分搜尋樹的根
Node* remove(Node *node, Key key){
if(node == NULL)
return NULL;
if (key < node->key){
node->left = remove(node->left, key);
return node;
}
else if (key > node->key){
node->right = remove(node->right, key);
return 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->left != NULL && node->right != NULL
//Node *delNode = node;
Node *successor = new Node(minimum(node->right));
count++;
successor->right = removeMin(node->right);
successor->left = node->left;
//delete delNode;
delete node;
count--;
return successor;
}
}
};
上面刪除既有左節點又有右節點的節點時,使用的是該節點後驅59替代該節點,其實也可以用該節點的前驅53替代該節點。如下圖所示