DS二叉排序树之删除(带图示)

题目描述

给出一个数据序列,建立二叉排序树,并实现删除功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

输入

第一行输入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;
		}
	}
}

 

  • 18
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值