【C++】二叉排序树
(写在前面:这是数据结构课程作业,仅供学习参考)
(1)二叉排序树的定义
二叉排序树或是空树,或是具有下述性质的二叉树:其左子树上所有结点的数据均小于根结点的数据值;右子树上所有结点的数据值均大于或等于根结点的数据值。左子树和右子树又各是一棵二叉排序树。
在二叉排序树中,若按中序遍历就可以得到由小到大的有序序列,如图2.41中的二叉排序树,中序遍历可得到有序序列{2,3,4,8,9,9,10,13,15,18,21}。
(2)二叉排序树的生成
二叉排序树是一种动态表结构,即二叉排序树的生成过程是不断地向二叉排序树中插入新的结点。
对任意的一组数据元素序列{R1,R2,…,Rn},要生成一棵二叉排序树的过程为:
<1>令R1为二叉排序树的根结点。
<2>若R2<R1,令R2为R1的左子树的根结点;否则R2为R1的右子树的根结点。
<3>R3,…,Rn结点的插入方法同上。
(3)删除二叉排序树上的结点
删除二叉排序树上的一个结点,也就是要在已排好序的序列中删除一个元素,因此要求删除一个结点后二叉树仍然是一棵二叉排序树。
删除二叉排序树上结点过程较插入过程复杂,按照被删除结点在二叉排序树中的位置,可以有以下几种情况:
<1>被删除结点是叶子结点,则删除后不会影响整个二叉排序树的结构,因此只需修改它双亲结点的指针即可。
<2>被删除结点P只有左子树PL或右子树PR,此时只要将左子树或右子树直接成为其双亲结点F的左或右子树即可,见图2.43(a)所示。
<3>若被删除结点P的左右子树均为非空。这是要循着P的左子树的根结点C,向右一直找到结点S,要求S的右子树为空。然后将S 的左子树改为结点Q的右子树,将S结点的数据域值取代P结点的数据域值,删除前后如图2.43(b)©所示。
<4>若被删除的结点为二叉排序树的根结点,则删除后应修改根结点指针。
下面是代码实现:
#include <iostream>
using namespace std;
struct tree {
int value;
tree* lnext;
tree* rnext;
};
tree* insert(tree*&, int);
void del(tree*&, int);
void inorder(tree*); //中序遍历
void freeTree(tree*); //回收内存
tree* find(tree*, tree*&, int, bool = 0); //查找某个值对应的节点,返回它的指针
int main()
{
tree* root = NULL;
int n, num;
char ch;
cout << "请输入初始的元素个数:" << endl;
cin >> n;
int* list = new int[n];
cout << "请依次输入这" << n << "个数:" << endl;
for (int i = 0; i < n; i++) {
cin >> list[i];
}
//生成
for (int i = 0; i < n; i++) {
insert(root, list[i]);
}
cout << "已生成二叉排序树,排序结果为:" << endl;
inorder(root);
//添加
cout << "\n当前:添加" << endl;
while (1) {
cout << "请输入要添加的数:";
cin >> num;
insert(root, num);
cout << "已添加,排序结果为:" << endl;
inorder(root);
cout << "\n继续添加?(y / n)" << endl;
cin >> ch;
if (ch == 'n') {
cout << "添加结束" << endl;
break;
}
}
//删除
cout << "\n当前:删除\n";
while (1) {
cout << "请输入要删的数:";
cin >> num;
del(root, num);
cout << "已删除,排序结果为:" << endl;
inorder(root);
cout << "\n继续删除?(y / n)" << endl;
cin >> ch;
if (ch == 'n') {
cout << "删除结束" << endl;
break;
}
}
freeTree(root);
return 0;
}
tree* insert(tree*& t, int b)
{
if (t == NULL) {
t = new tree;
t->value = b;
t->lnext = NULL;
t->rnext = NULL;
}
else {
if (b < t->value)t->lnext = insert(t->lnext, b); //插入左子树
else t->rnext = insert(t->rnext, b); //插入右子树
}
return t;
}
void del(tree*& root, int b)
{
tree* parent = NULL;
tree* target = find(root, parent, b, 1);
tree* s; //辅助结点指针
if (target != NULL) {
bool flag = true; //指示是否需要修改父节点指针
if (target->lnext == NULL)s = target->rnext; //目标是叶子或者左子树为空
else if (target->rnext == NULL)s = target->lnext; //目标结点的右子树为空
else { //目标的左右子树均非空
tree* q = target;
s = target->lnext;
while (s->rnext != NULL) { //从目标的左子树开始,一直找到最右的节点s
q = s;
s = s->rnext;
}
if (q == target)
q->lnext = s->lnext; //若一开始就是最右,直接删除即可
else
q->rnext = s->lnext; //将s节点的左子树改为q的右子树
target->value = s->value; //用s值替代目标节点的值
delete s;
flag = false;
}
if (flag) { //需要修改父节点指针
if (parent == NULL)root = s; //目标是根节点
else if (parent->lnext == target)parent->lnext = s;
else parent->rnext = s;
delete target;
}
}
else cout << "无此数" << endl;
}
void inorder(tree* root)
{
if (root != NULL) {
inorder(root->lnext);
cout << root->value << ' ';
inorder(root->rnext);
}
}
void freeTree(tree* root)
{
if (root == NULL)return;
else {
freeTree(root->lnext);
freeTree(root->rnext);
delete root;
}
}
tree* find(tree* pnow, tree*& par, int b, bool isroot)
{
if (isroot) {
if (pnow->value == b)
{
par = NULL;
return pnow;
}
}
if (pnow == NULL)return NULL;
else {
if (pnow->lnext != NULL && pnow->lnext->value == b) {
par = pnow;
return pnow->lnext;
}
else if (pnow->rnext != NULL && pnow->rnext->value == b) {
par = pnow;
return pnow->rnext;
}
else {
if (find(pnow->lnext, par, b) == NULL && find(pnow->rnext, par, b) == NULL)
return NULL;
}
}
}
测试用例
参考资料:《计算机软件技术基础》(第三版)-清华大学出版社