数据结构——排序二叉树

前言

下图代码是排序二叉树的相关操作的实现。众所周知,排序二叉树的优点就是插入高效,查找高效(除顺序序列插入,否则查找数据的时间复杂度都为O(logn),并且中序遍历二叉树的输出结果都是顺序序列。但在删除结点时比较复杂,接下来会对排序二叉树结点的删除做具体分析!

#include<iostream>
#include<time.h>
#include<Windows.h>
using namespace std;
#define NUM 100
#pragma warning(disable:4996)
typedef struct node
{
	char data;
	struct node* lchild;
	struct node* rchild;
}*TNode, Tnode;
void createordtree(TNode &T, char key); //建立排序二叉树
void printtree(TNode T);//中序遍历输出排序二叉树
void findtree(TNode T, char key);//查询排序二叉树
void Findtree(TNode T, char key);//非递归查询排序二叉树
void temp(TNode T, TNode &parent, TNode &child, char key);//寻找排序二叉树删除位置的地址
void deletenode(TNode &T,TNode parent, TNode child);//删除排序二叉树的对应节点
int main()
{
	TNode deletep, deletec;
	char a, x,find,deletedata;
	TNode Tree=NULL;
	while (1)
	{
		cout << "请输入录入的字母信息:";
		cin >> a;
		createordtree(Tree, a);
		cout << "是否继续录入(Y/N)";
		cin >> x;
		if (x == 'N')break;
	}
	cout << "中序遍历的结果为:";
	printtree(Tree);
	cout << endl;
	while(1)
	{ 
	cout << "请输入需要在排序二叉树中查找的元素:" ;
	cin >> find;
	cout << "递归查询结果:";
    findtree(Tree, find);
	cout << "非递归查询结果:";
	Findtree(Tree, find);
	cout << "是否继续查找(Y/N)";
	cin >> x;
	if (x == 'N')break;
	}
	while(1)
	{
	cout << "请输入需要删除的数据:";
	cin >> deletedata;
	deletec = Tree;
	temp(Tree, deletep, deletec, deletedata);
	deletenode(Tree,deletep, deletec);
	cout << "删除后重新中序遍历后的结果为:";
	printtree(Tree);
	cout <<endl<< "是否继续删除(Y/N)";
	cin >> x;
	if (x == 'N')break;
	}
	return 0;
}
void createordtree(TNode &T, char key) //建立排序二叉树
{
	if (T==NULL)
	{
		T = new Tnode;
		T->data = key;
		T->lchild = NULL;
		T->rchild = NULL;
	}
	else if (T->data > key)createordtree(T->lchild, key);
	else if (T->data <= key)createordtree(T->rchild, key);
}
void printtree(TNode T)//中序遍历输出排序二叉树
{
	if (T)
	{
		printtree(T->lchild);
		cout << T->data;
		printtree(T->rchild);
	}
}
void findtree(TNode T, char key)//查询排序二叉树
{
	if (T == NULL)
	{
		cout << "NO EXIST!" << endl;
		return;
	}
	else if (T->data == key)
	{
		cout << "EXIST!" << endl;
		return;
	}
	else if (T->data > key)findtree(T->lchild, key);
	else if (T->data < key)findtree(T->rchild, key);
}
void Findtree(TNode T, char key)//非递归查询排序二叉树
{
	TNode p = T;
	while (p)
	{
		if (p->data == key)
		{
			cout << "EXIST!" << endl;
			break;
		}
		else if(p->data > key)p = p->lchild;
		else p = p->rchild;
	}
	if(!p)cout<< "NO EXIST!" << endl;
}
void temp(TNode T,TNode &parent,TNode &child,char key)//寻找排序二叉树删除位置的地址
{
	if (T->data == key)
	{
		parent=T;
		child = T;
		return;
	}
	if (child == NULL)
	{
		cout << "ERROR" << endl;
		return;
	}
	else if(child->data == key) 
	{
		return;
	}
	else if (child->data > key)
	{
		parent = child;
		child = child->lchild;
		temp(T, parent, child, key);
	}
	else if (child->data < key)
	{
		parent = child;
		child = child->rchild;
		temp(T, parent, child, key);
	}
}
void deletenode(TNode &T,TNode parent, TNode child)//删除排序二叉树的对应节点
{
	TNode p, s;
	if (T == child)
	{
		if (T->lchild == NULL && T->rchild != NULL)
		{
			T = child->rchild;
			delete child;
			return;
		}
		else if (T->rchild == NULL && T->lchild != NULL)
		{
			T = child->lchild;
			delete child;
			return;
		}
	}
	if (child->lchild == NULL)
	{
		if (parent->lchild == child)
		{
			parent->lchild = child->rchild;
			delete child;
		}
		else
		{
			parent->rchild = child->rchild;
			delete child;
		}
	}
	else if (child->rchild == NULL )
	{
		if (parent->lchild == child)
		{
			parent->lchild = child->lchild;
			delete child;
		}
		else
		{
			parent->rchild = child->lchild;
			delete child;
		}
	}
	else if (child->lchild != NULL && child->rchild != NULL)
	{
		p = child; s = child->lchild;
		while (s->rchild != NULL)
		{
			p = s;
			s = s->rchild;
		}
		child->data = s->data;
		if (p != child)
		{
			p->rchild = s->lchild;
			delete s;
		}
		else
		{
			p->lchild = s->lchild;
			delete s;
		}
	}
}

结点删除情况总结
一.待删除结点为根结点,且根结点的左子树或右子树为空
解决方案:直接将根结点顺位继承,即根结点=根结点->右孩子/左孩子(如下图情况Ⅵ
二.待删除结点为子结点,且子结点的左子树/右子树为空
解决方案:寻找删除结点及删除结点的父结点,让父结点指向删除结点的剩余结点(如下图情况Ⅲ
三.待删除结点的的左子树和右子树都不为空
解决方案:将待删除结点左子树中的最大结点找到,并将其赋值给待删除结点
此时会衍生出两种情况
待删除结点的左孩子就是最大结点:此时在赋值完成后,直接让待删除结点->左孩子=待删除结点->左孩子->左孩子(如下图情况Ⅴ)
待删除结点的左孩子不是最大结点:定义两个指针,一个指向最大结点,一个指向最大结点的父结点,在赋值完成后,让最大结点的父结点->右孩子=最大结点->左孩子(如下图情况Ⅱ
四.待删除的结点为叶子结点
解决方案:直接将此结点删除即可(如下图情况Ⅳ
在这里插入图片描述
图Ⅰ是演示示例的逻辑结构图,其他图是对应结点的删除后的逻辑结构图
所以编译器中的输入应为ADBHCFIEG
结点的删除顺序应为HBFEIDA
下图是对应代码的运行结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值