版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/majinlei121/article/details/84147159
上篇博客介绍了怎样删除二分搜索树的最大值和最小值节点,下面介绍怎样删除树的任意一个节点
上篇删除最大值节点的操作,其实删除的节点要么没有左右子节点,要么只可能有左节点,
同样,删除最小值节点的操作,其实删除的节点要么没有左右子节点,要么只可能有右节点
(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替代该节点。如下图所示