对于一个二叉排序树,要删除其某个结点,重点要找到两个关键结点(自身与父结点),代码实现如下:
#include<iostream>
#include<string>
using namespace std;
class Node{
public:
int value;
Node *left,*right;
int countt=1;
Node(int value){
this->value=value;
left = nullptr;
right = nullptr;
}
/**往二叉树里面插入结点**/
void addNode(Node *node){
if(node == nullptr){
return;
}
/**如果插入的结点的值小于当前结点的值,
* 则该插入的结点应该往左走**/
if(node->value<this->value){
if(this->left == nullptr){
this->left=node;
} else{
this->left->addNode(node);
}
}else{
if(this->right == nullptr){
this->right=node;
}else{
this->right->addNode(node);
}
}
}
/**中序遍历,结点值从小到大输出**/
void midShow(Node *node){
if(node == nullptr){
return;
}
midShow(node->left);
cout<<node->value<<" ";
midShow(node->right);
}
/**传入值,搜索整棵树中对应的结点,返回结点,如果找不到,返回空**/
Node* searchNode(int value){
//找到直接返回当前结点的值
if(this->value==value){
return this;
}else if(value<this->value){ //要搜索的值小于当前结点的值,向左子树中进行查找
if(left==nullptr){//左子树为空,说明找不到
return nullptr;
}
left->countt=this->countt+1;
return left->searchNode(value);//非空,递归查找
}else{// 同理,要搜索的值大于当前结点的值,向右子树中进行查找
if(right==nullptr){
return nullptr;
}
right->countt=this->countt+1;
return right->searchNode(value);
}
}
/**查找对应结点的父亲结点**/
Node* searchParentsNode(int value){
//如果当前结点的左孩子或者右孩子等于查找值,说明当前结点即为该查找值的父亲结点
if((this->left!=nullptr&&this->left->value==value)||(this->right!=nullptr&&this->right->value==value)){
return this;
}else{
// 如果查找值小于当前值,同时当前值的左孩子非空
if(value<this->value&&this->left!=nullptr){
//到左子树中查找
return this->left->searchParentsNode(value);
}else if(value>this->value&&this->right!=nullptr){
//到右子树中查找
return this->right->searchParentsNode(value);
}else{
//当前值既不等于查找值,也没有孩子结点,说明查找失败,返回空
return nullptr;
}
}
}
};
//binary sort tree
class BST{
Node *root;
public:
/**往二叉排序树中加入结点**/
void add(Node *node){
if(root==nullptr){
root=node;
}else{
root->addNode(node);
}
}
/**中序遍历二叉排序树**/
void InOrder() {
if (root != nullptr) {
root->midShow(root);
}
}
/**在二叉排序树中查找**/
Node* search(int value) {
if (root == nullptr) {
return nullptr;
} else {
return root->searchNode(value);
}
}
/**在二叉排序树中查找该值的父亲结点,并返回**/
Node* searchParent(int value) {
if (root == nullptr) {
return nullptr;
} else {
return root->searchParentsNode(value);
}
}
/**删除某个结点的右子树中值最小的结点,并返回该值**/
int deleteMin(Node* node){
Node* target = node;
while (target->left != nullptr) {//右子树中最小值必然是其最下层的左孩子
target = target->left;
}
// 该最小值结点可能是叶子结点,也可能有右孩子,但delete函数已经考虑了这两种情况了,
// 所以可以直接调用。(但不可能有左孩子,因为其是最小的)
deleteNode(target->value);
return target->value;
}
/**删除结点**/
void deleteNode(int value){
if(root==nullptr){
return;
}else{
//查找要删除的结点
Node* target=search(value);
if(target == nullptr){
return;
}
//查找父亲结点
Node* parent=searchParent(value);
//如果目标结点没有孩子,可直接将该结点删除
if(target->left==nullptr&&target->right==nullptr){
//如果目标结点没有孩子,可直接将该结点删除
if(parent->left->value==value){
parent->left=nullptr;
}else{
parent->right=nullptr;
}
// 如果目标结点既有左孩子,又有右孩子,需要在目标结点的右孩子中找到一个最小值,
// 将目标结点删除后,替代目标结点的位置。
}else if(target->left!=nullptr&&target->right!=nullptr){
//删除右子树中的最小值,同时获得该值
int min=deleteMin(target->right);
// 将要删除的结点的值改为最小值
target->value = min;
//如果目标结点只有一个孩子,只需让目标结点的该孩子顶替目标结点
}else{
//如果目标结点有的只是左孩子
if(target->left!=nullptr){
//判断目标结点是其父亲结点的左孩子还是右孩子
if (parent->left->value == value) {
parent->left = target->left;
} else {
parent->right = target->left;
}
}else{
if (parent->left->value == value) {
//直接覆盖旧结点,那么该新结点后面左右子树其实也会跟过来
parent->left = target->right;
} else {
//直接覆盖旧结点,那么该新结点后面左右子树其实也会跟过来
//所以不用担心target结点的左、右结点是否还带其他结点
parent->right = target->right;
}
}
}
}
}
};
int main(){
int t;
cin>>t;
while(t--){
BST* bst=new BST();
int n;
cin>>n;
//构建二叉排序树
while(n--){
int val;
cin>>val;
bst->add(new Node(val));
}
bst->InOrder();
cout<<endl;
//删除多少个结点
cin>>n;
while(n--){
int val;
cin>>val;
bst->deleteNode(val);
bst->InOrder();
cout<<endl;
}
}
return 0;
}
看删除的函数,以及搜索对应删除结点及其父结点的方法,输入输出不用过多理会。
我是花花,祝自己也祝您变强了~