[C++]搜索树 查找/插入/删除

搜索树:一种二叉树,满足任何节点的关键字大于都其左子树所有节点的关键字,小于其右子树所有节点的关键字(默认所有节点关键字不重复)。
查找:输入需要查找的关键字,从根节点开始,通过比较关键字的大小来搜索,若查找关键字小于根节点,则考察左子树;若查找关键字大于根节点,则考察右子树。最终若指针指向空节点,说明查找元素不存在。
插入:方法类似于查找,最终当指针指向的空节点即为插入元素的位置。
删除:先找到需要删除的节点的位置,若不存在则返回。若删除节点有两个子树,则需要先将需要删除的节点的左子树最大值(或右子树的最小值)节点复制到删除节点上,然后需要删除的节点变为原来左子树最大值(或右子树的最小值)节点。删除节点至多有一个子树时,只需要将子树的根节点替换到删除节点的位置上。

代码

#include<iostream>
using namespace std;
template<class T,class E>
struct bsNode//定义二叉搜索树节点
{
	pair<T, E> element;//元素为数对,前项表示关键字,后项表示数值
	bsNode<T,E>* leftChild;//左子节点指针
	bsNode<T,E>* rightChild;//右子节点指针
	bsNode(const pair<T,E>& theElement)
	{
		element = theElement;
		leftChild = NULL;
		rightChild = NULL;
	}
	bsNode(const pair<T, E>& theElement, bsNode<T,E>* LEFT, bsNode<T,E>* RIGHT)
	{
		element = theElement;
		leftChild = LEFT;
		rightChild = RIGHT;
	}
};
template<class T, class E>
int height(bsNode<T,E>* node)//获得某一节点下二叉树的高度
{
	if (node == nullptr)
		return 0;
	int leftHeight = height(node->leftChild);
	int rightHeight = height(node->rightChild);
	if (leftHeight > rightHeight)
		return ++leftHeight;
	else
		return ++rightHeight;
}
template<class T, class E>
int countNode(bsNode<T,E>* node)//获取某一节点下二叉树的节点个数
{
	if (node == nullptr)
		return 0;
	int leftCount = countNode(node->leftChild);
	int rightCount = countNode(node->rightChild);
	return leftCount + rightCount + 1;
}

template<class T, class E>
class bsTree
{
public:
	bsTree() 
	{
		size = 0;
		root = NULL;
	}
	void ascend() { inOrder(root); }//按关键字顺序输出元素数值
	void find(const T& theKey)//按关键字查找对应元素的数值
	{
		bsNode<T, E>* p = root;
		while (p != NULL)
		{
			if (theKey < p->element.first)
				p = p->leftChild;
			else if (theKey > p->element.first)
				p = p->rightChild;
			else
			{
				cout << p->element.second << endl;
				return;
			}

		}
		cout << "Not find" << endl;
	}
	void insert(const pair<T, E>& theElement)//插入元素(若关键字上已经存在元素,则覆盖其数值)
	{
		bsNode<T, E>* p = root;//用于寻找安放空位
		bsNode<T, E>* pp = NULL;//p节点的父节点
		while (p != NULL)//寻找
		{
			pp = p;
			if (theElement.first < p->element.first)
				p = p->leftChild;
			else if (theElement.first > p->element.first)
				p = p->rightChild;
			else
			{
				p->element.second = theElement.second;//覆盖
				return;
			}
		}
		bsNode<T, E>* newNode = new bsNode<T, E>(theElement);
		if (root != NULL)//树非空
		{
			if (theElement.first < pp->element.first)
				pp->leftChild = newNode;
			else
				pp->rightChild = newNode;
		}
		else//树空
			root = newNode;
		size++;
	}
	void erase(const T& theKey)//删除元素
	{
		bsNode<T, E>* p = root;//用于寻找需要删除的节点
		bsNode<T, E>* pp = NULL;//p节点的父节点
		while (p != NULL && p->element.first != theKey)//把p定位到删除节点上
		{
			pp = p;
			if (theKey < p->element.first)
				p = p->leftChild;
			else
				p = p->rightChild;
		}
		if (p == NULL)//若p为空,则说明删除节点不存在,退出函数
		{
			cout << "Not find" << endl;
			return;
		}
		//当删除节点至多只有一个子树时,只需要将删除节点替换成其子树的根节点;
		//当删除节点存在两个子树时,需要先重新组织树结构:
		//把删除节点的左子树的关键字最大值(或右子树的关键字最小值)元素复制到删除位置上,
		//然后把删除指针指向左子树的关键字最大值(或右子树的关键字最小值)节点,此时转化为删除只有一个子树的节点。
		//(↑因为左子树的关键字最大值和右子树的关键字最小值节点至多只有一个子树)
		if (p->leftChild != NULL && p->rightChild != NULL)
		{
			bsNode<T, E>* s = p->leftChild;//寻找p左子树的最大值
			bsNode<T, E>* ps = p;//s节点的父节点
			while (s->rightChild != NULL)//循环结束后,s指向p的左子树的最大值
			{
				ps = s;
				s = s->rightChild;
			}
			p->element = s->element;
			bsNode<T, E>* q = new bsNode<T, E>(s->element, p->leftChild, p->rightChild);//q节点的元素是p节点左子树的最大值,q节点的位置是p
			if (pp == NULL)//以q节点替换p节点
				root = q;
			else if (p == pp->leftChild)
				pp->leftChild = q;
			else
				pp->rightChild = q;

			if (ps == p)//把pp移动到s节点的父节点
				pp = q;
			else
				pp = ps;
			delete p;
			p = s;//把p移动到s节点
		}
		//之后删除节点至多只有一个子树
		bsNode<T, E>* c;
		if (p->leftChild != NULL)
			c = p->leftChild;
		else
			c = p->rightChild;
		if (p == root)
			root = c;
		else
		{
			if (p == pp->leftChild)
				pp->leftChild = c;
			else
				pp->rightChild = c;
		}
		size--;
		delete p;
	}
private:
	bsNode<T, E>* root;
	int size;
	void inOrder(bsNode<T,E>* node)//中序遍历
	{
		if (node != nullptr)
		{
			inOrder(node->leftChild);
			cout << node->element.second << " ";
			inOrder(node->rightChild);
		}
	}
};
int main()//简单测试
{
	bsTree<int, int> tree;
	for (int i = 0; i < 10; i++)
	{
		pair<int, int> p(i, i*2);
		tree.insert(p);
	}
	tree.ascend();
	cout << endl;
	tree.erase(8);
	tree.erase(8);
	tree.find(8);
	tree.find(7);
	tree.ascend();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值