题目描述
给出一个数据序列,建立二叉排序树,并实现删除功能
对二叉排序树进行中序遍历,可以得到有序的数据序列
输入
第一行输入t,表示有t个数据序列
第二行输入n,表示首个序列包含n个数据
第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开
第四行输入m,表示要删除m个数据
从第五行起,输入m行,每行一个要删除的数据,都是自然数
以此类推输入下一个示例
输出
第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到
从第二行起,输出删除第m个数据后的有序序列,输出m行
以此类推输出下一个示例的结果
样例输入
1
6
22 33 55 66 11 44
3
66
22
77
样例输出
11 22 33 44 55 66
11 22 33 44 55
11 33 44 55
11 33 44 55
删除实现:
先找到要删除的结点
如果没找到,则不删除
如果找到,分为以下3种情况
case1:找到的结点的左右孩子都为空,那么直接删除此结点即可
case2:找到的结点的左右孩子有一个为空,那么将不空的那个孩子代替要删的结点即可
case3:找到的结点的左右孩子都不为空,那么找到这个结点的右子树中的最小结点(此结点的左孩子一定为空),将最小结点的值赋给要删除的结点,然后删除最小结点(因为最小结点属于case1或case2的一种,所以删除实现非常简单)
辅助指针:
由于本方法采用的是指针实现而非引用实现,在删除的时候无法直接修改要删除的结点的父亲的左右孩子指针,所以需要设定一个父节点指针previous,每次都指向删除的结点的父亲,这样在删除的时候才方便修改
用指针实现的话只需要一个函数即可
用引用实现的话则需要2个函数,且需要递归实现
图示:
如上图,比如说要删50,那么找到50的右子树的最小结点60,将50替换为60,然后右边的最小结点
删除后结果:
代码:
#include <iostream>
using namespace std;
class BSTNode{
public:
int data;
BSTNode *LeftChild;
BSTNode *RightChild;
public:
BSTNode() :LeftChild(NULL), RightChild(NULL){};
~BSTNode(){};
};
class BST{
public:
BSTNode *Root;
public:
BST(){};
~BST(){};
void Create();
void Inorder(BSTNode *t);
void Insert();
int Search();
void Delete();
};
void BST::Create()
{
int n, temp_num;
cin >> n;
Root = new BSTNode();
cin >> Root->data;
BSTNode *temp;
for (int i = 0; i<n - 1; i++)
{
cin >> temp_num;
temp = Root;
while (1)
{
if (temp->data > temp_num)
{
if (temp->LeftChild != NULL)
temp = temp->LeftChild;
else
{
BSTNode *lc = new BSTNode();
temp->LeftChild = lc;
lc->data = temp_num;
break;
}
}
else
{
if (temp->RightChild != NULL)
temp = temp->RightChild;
else
{
BSTNode *lc = new BSTNode();
temp->RightChild = lc;
lc->data = temp_num;
break;
}
}
}
}
}
void BST::Inorder(BSTNode *t)
{
if (t != NULL)
{
Inorder(t->LeftChild);
cout << t->data << ' ';
Inorder(t->RightChild);
}
}
void BST::Insert()
{
int temp_num;
cin >> temp_num;
BSTNode *temp;
temp = Root;
while (1)
{
if (temp->data > temp_num)
{
if (temp->LeftChild != NULL)
temp = temp->LeftChild;
else
{
BSTNode *lc = new BSTNode();
temp->LeftChild = lc;
lc->data = temp_num;
break;
}
}
else
{
if (temp->RightChild != NULL)
temp = temp->RightChild;
else
{
BSTNode *lc = new BSTNode();
temp->RightChild = lc;
lc->data = temp_num;
break;
}
}
}
}
int BST::Search()
{
int num;
cin >> num;
BSTNode *temp;
temp = Root;
int time = 0;
while (1)
{
if (temp == NULL)
return -1;
time++;
if (temp->data == num)
return time;
else if (temp->data > num)
temp = temp->LeftChild;
else
temp = temp->RightChild;
}
}
void BST::Delete()
{
int num;
cin >> num; //输入要删除的结点的值
BSTNode *temp, *previous;
temp = Root;
previous = Root;
while (temp != NULL)
{
if (temp->data == num)
break;
else if (temp->data > num)
{
previous = temp;
temp = temp->LeftChild;
}
else
{
previous = temp;
temp = temp->RightChild;
}
}
if (temp != NULL)
{
if (temp->LeftChild == NULL) //要删的结点的左孩子为空的情况
{
if (temp==Root && temp->RightChild==NULL)
{
delete temp;
temp=NULL;
}
else
{
previous->LeftChild==temp ? previous->LeftChild=temp->RightChild :previous->RightChild=temp->RightChild;
delete temp;
}
}
else if (temp->RightChild == NULL) //要删的结点的右孩子为空的情况
{
previous->LeftChild == temp ? previous->LeftChild=temp->LeftChild :previous->RightChild=temp->LeftChild;
delete temp;
}
else //要删的结点的左、右孩子都不为空的情况
{
BSTNode *right_min = temp->RightChild;
previous = right_min;
while (right_min->LeftChild != NULL) //找到右子树最小结点
{
previous = right_min;
right_min = right_min->LeftChild;
}
temp->data = right_min->data; //最小结点的值赋给要删除的结点
if(right_min == previous)
{
temp->RightChild=right_min->RightChild;
}
else
{
previous->LeftChild = right_min->RightChild;
}
delete right_min; //删除右子树的最小结点
}
}
}
int main()
{
int t, delete_num;
cin >> t;
while (t--)
{
BST t;
t.Create();
t.Inorder(t.Root);
cout << endl;
cin >> delete_num;
while (delete_num--)
{
t.Delete();
t.Inorder(t.Root);
cout << endl;
}
}
}