二叉搜索树(C++)

目录

二叉搜索树的概念

 二叉搜索树操作

二叉搜索树的查找

二叉搜索树的插入

 二叉搜索树的删除

要删除的结点无孩子结点

要删除的结点只有右孩子结点

要删除的结点只有左孩子结点

要删除的结点有左、右孩子结点都存在

代码实现


二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树,如下图所示:

 二叉搜索树操作

二叉搜索树的查找

二叉搜索树的查找操作其实很简单,若根节点不空,只要比较要查找的值与当前根节点值的大小,根据比较结果去根节点的左子树或右子树中查找就可以了,然后重复上述过程。

二叉搜索树的插入

根据二叉搜索树的性质,找到要插入的位置,将新节点插入即可(如果树为空,直接插入后返回)

 二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

要删除的结点无孩子结点

找到该节点,直接删除

要删除的结点只有右孩子结点

找到该节点,同时在寻找的过程中记录其双亲,让其双亲指向待删除的节点的右孩子节点即可。如下图:

要删除的结点只有左孩子结点

找到该节点,同时在寻找的过程中记录其双亲,让其双亲指向待删除的节点的左孩子节点即可。
过程和只存在右孩子节点类似

要删除的结点有左、右孩子结点都存在

不能直接删除该节点,需要分几步完成:
1.找替代节点:在待删除节点的右子树中找最左侧节点,或者在待删除节点左子树中找最右侧节点。
2.将替代节点中的值域赋值给待删除节点。
3.将替代节点删除(注意该替代节点可能还存在左子树或者右子树,在删除时需要考虑其左右子树)
如下图,删除值为5的节点,去其右子树中找最左侧节点,过程如下:

代码实现

首先,节点的结构得有,所以定义如下模板类:
template<class T>
class BTNode{
public:
	BTNode<T>* _left;//左指针阈
	BTNode<T>* _right;//右指针阈
	T _val;//值域
	BTNode(T val=T())//使用默认的_val
		:_left(nullptr)
	    ,_right(nullptr)
	    ,_val(val)
	{
		
	}
};

使用模板类,可以存放任意类型的元素。

然后就可以定义二叉搜索树了,代码如下:

template<class T>
class BSTree{
	typedef BTNode<T> Node;//重命名BTNode<T>,方便使用
public:
	BSTree()//构造函数,初始化root为空
		:_root(nullptr)
	{
	}
	Node* Find(const T& val){//查找元素
		Node* cur = _root;
		while (cur){
			if (cur->_val<val){
				cur = cur->_right;
			}
			else if (cur->_val>val){
				cur = cur->_left;
			}
			else{
				return cur;
			}
		}
		return nullptr;
	}
	Node* insert(T val){//插入元素
		if (_root==nullptr){//当前树为空,插入一个元素后直接返回
			_root = new Node(val);
			return _root;
		}
		//当前树不空,如下:
		Node* parent=nullptr;
		Node* child = _root;
		while (child){//循环结束后,要插入的节点就是parent的左或者右孩子
			parent = child;
			if (val<child->_val){
				child = child->_left;
			}
			else{
				child = child->_right;
			}
		}
		if (parent->_val>val){//判断要把新节点插入到parent的左还是右
			parent->_left = new Node(val);
		}
		else{
			parent->_right = new Node(val);
		}
		return _root;
	}
	bool Erase(T val){//删除元素
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur){//寻找待删除节点,注意parent = cur;必须放在if与else if中
			if (val<cur->_val){
				parent = cur;
				cur = cur->_left;
			}
			else if (val>cur->_val){
				parent = cur;
				cur = cur->_right;
			}
			else{
				break;
			}
		}
		if (cur==nullptr){//表示没找到,直接返回
			return false;
		}
		//找到了待删除节点,如下:
		if (cur->_left == nullptr){//待删除节点只有右孩子,或者待删除节点没有孩子
			if (parent == nullptr){//待删除节点是根节点
				_root = cur->_right;
				delete cur;
			}
			else{//待删除节点不是根节点
				if (parent->_left == cur){
					parent->_left = cur->_right;
				}
				else{
					parent->_right = cur->_right;
				}
				delete cur;
			}
		}
		else if (cur->_right==nullptr){//待删除节点只有左孩子
			if (parent==nullptr){//待删除节点是根节点
				_root = cur->_left;
				delete cur;
			}
			else{//待删除节点不是根节点
				if (parent->_left == cur){
					parent->_left = cur->_left;
				}
				else{
					parent->_right = cur->_left;
				}
				delete cur;
			}
		}
		else{//待删除节点左右孩子都有
			parent = cur;
			Node* rec = cur->_right;
			while (rec->_left){//找到其右子树中最左侧节点
				parent = rec;
				rec = rec->_left;
			}
			cur->_val = rec->_val;//覆盖待删除节点的值
			if (parent->_left==rec){//连接右子树中最左侧节点的右子树
				parent->_left = rec->_right;
			}
			else{
				parent->_right = rec->_right;
			}
			delete rec;//删除掉右子树中最左侧节点
		}
		return true;
	}
	
	~BSTree(){//析构
		Destroy(_root);
	}
	void InOrder(){//暴露给外部,中序遍历
		InOrder(_root);
		cout << endl;
	}
private:
	void Destroy(Node*& root){//利用递归销毁二叉树
		if (root==nullptr){
			return;
		}
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
		root = nullptr;
	}
	void InOrder(Node*& root){//中序遍历
		if (root==nullptr){
			return;
		}
		InOrder(root->_left);
		cout << root->_val << ' ';
		InOrder(root->_right);
	}
private:
	 Node* _root;//底层维护的指针,指向根节点
};

代码中要注意的点就是当树为空时要插入元素,直接插入返回。当待删除节点是根节点时,需要改变底层维护的指针_root的指向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值