栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

二叉搜索树(C++)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉搜索树(C++)

目录

二叉搜索树的概念

 二叉搜索树操作

二叉搜索树的查找

二叉搜索树的插入

 二叉搜索树的删除

要删除的结点无孩子结点

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

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

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

代码实现


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

 二叉搜索树操作

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

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

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

要删除的结点无孩子结点 找到该节点,直接删除

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

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

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

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

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

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

template
class BSTree{
	typedef BTNode Node;//重命名BTNode,方便使用
public:
	BSTree()//构造函数,初始化root为空
		:_root(nullptr)
	{
	}
	Node* Find(const T& val){//查找元素
		Node* cur = _root;
		while (cur){
			if (cur->_val_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_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_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的指向。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/947649.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号