先指出在实现过程中容易出错的几点:
- 插入节点算法 treeInsert 中,由于当初始为空树时,在函数中需要将根节点的指针指向新插入的节点,所以参数列表中一定要用指向根节点指针的引用。
- 删除节点算法 treeDelete 和 treeDelete_v2 中,由于有可能对根节点的指向做修改,所以参数列表中一定要用指向根节点指针的引用。
#include <iostream>
using namespace std;
//BST节点定义
struct TreeNode {
int key;
TreeNode* left;
TreeNode* right;
TreeNode* parent;
TreeNode(int x) : key(x), left(NULL), right(NULL), parent(NULL) {}
};
//BST中插入一个关键值为value的节点
//注意:参数必须使用根节点指针的引用,否则当为空树时,无法改变原函数中的根节点
void treeInsert(TreeNode* &T, int value) {
TreeNode* z = new TreeNode(value);
TreeNode* x = T;
TreeNode* y = NULL;
while (x != NULL) {
y = x;
if (z->key < x->key)
x = x->left;
else if (z->key > x->key)
x = x->right;
else { //BST中有值相同的节点时不插入
delete z;
return;
}
}
z->parent = y;
if (y == NULL)
T = z; //树为空的情况
else if (z->key < y->key)
y->left = z;
else y->right = z;
}
//查找BST中关键字最小的节点,返回一个指向改节点的指针
TreeNode* treeMinimum(TreeNode* T) {
TreeNode* x = T;
while (x->left != NULL)
x = x->left;
return x;
}
//查找BST中关键字最大的节点,返回一个指向改节点的指针
TreeNode* treeMaximum(TreeNode* T) {
TreeNode* x = T;
while (x->right != NULL)
x = x->right;
return x;
}
//查找一个关键字为k的节点,返回一个指向该节点的指针
TreeNode* treeSearch(TreeNode* T, int k) {
TreeNode* x = T;
while (x != NULL && x->key != k)
if (k < x->key)
x = x->left;
else x = x->right;
return x;
}
//查找给定节点的后继节点,并返回指向后继节点的指针
TreeNode* treeSuccessor(TreeNode* x) {
if (x->right != NULL)
return treeMinimum(x->right);
TreeNode* y = x->parent;
while (y != NULL && x == y->right) {
x = y;
y = x->parent;
}
return y;
}
//查找给定节点的前驱节点,并返回指向前驱节点的指针
TreeNode* treePrecursor(TreeNode* x) {
if (x->left != NULL)
return treeMaximum(x->left);
TreeNode* y = x->parent;
while (y != NULL && x == y->left) {
x = y;
y = x->parent;
}
return y;
}
//中序遍历BST
void inorderTreeWalk(TreeNode* T) {
if (T != NULL) {
inorderTreeWalk(T->left);
cout << T->key << " ";
inorderTreeWalk(T->right);
}
}
//用子树v替换子树u并成为其双亲的孩子节点
void transplant(TreeNode* &T, TreeNode* u, TreeNode* v) {
if (u->parent == NULL) //u是T的树根的情况
T = v;
else if (u == u->parent->left)
u->parent->left = v;
else u->parent->right = v;
if (v != NULL)
v->parent = u->parent;
}
//在BST中删除z指向的节点
//删除节点为根节点时,调用transplant函数时对T的指向做了修改,所以参数列表要用T引用
void treeDelete(TreeNode* &T, TreeNode* z) {
if (z->left == NULL)
transplant(T, z, z->right);
else if (z->right == NULL)
transplant(T, z, z->left);
else { //当z有左右孩子时
TreeNode* y = treeMinimum(z->right); //z的右子树中的最小节点为z的后继节点
if (y->parent != z) {
transplant(T, y, y->right);
y->right = z->right;
y->right->parent = y;
}
transplant(T, z, y);
y->left = z->left;
y->left->parent = y;
}
delete z;
}
//在BST中删除z指向的节点 ———— version_2
void treeDelete_v2(TreeNode* &T, TreeNode* z) {
if (z->left == NULL)
transplant(T, z, z->right);
else if (z->right == NULL)
transplant(T, z, z->left);
else { //当z有左右孩子时
TreeNode* p = treeMinimum(z->right); //z的右子树中的最小节点为z的后继节点
z->key = p->key; //用z后继节点的关键字替代z的关键字,转化为删除p的问题
transplant(T, p, p->right); //p->left一定为NULL
z = p;
}
delete z;
}
int main() {
TreeNode* T = NULL;
treeInsert(T, 10);
treeInsert(T, 5);
treeInsert(T, 15);
treeInsert(T, 20);
treeInsert(T, 13);
treeInsert(T, 13);
inorderTreeWalk(T);
cout << endl;
cout << treeSearch(T, 10)->key << endl;
cout << treeMinimum(T)->key << endl;
cout << treeMaximum(T)->key << endl;
cout << treeSuccessor(T->left)->key << endl;
cout << treePrecursor(T->right)->key << endl;
treeDelete(T, T);
inorderTreeWalk(T);
cout << endl;
treeDelete_v2(T, T);
inorderTreeWalk(T);
cout << endl;
return 0;
}
输出结果:
5 10 13 15 20
10
5
20
10
13
5 13 15 20
5 15 20