C++从入门到入土第十九篇:二叉搜索树

Posted 李憨憨_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++从入门到入土第十九篇:二叉搜索树相关的知识,希望对你有一定的参考价值。

二叉搜索树


文章目录


二叉搜索树概念

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

原理

二叉搜索树(BST)又称二叉查找树或二叉排序树。一棵二叉搜索树是以二叉树来组织的,可以使用一个链表数据结构来表示,其中每一个结点就是一个对象。一般地,除了key和位置数据之外,每个结点还包含属性lchild、rchild和parent,分别指向结点的左孩子、右孩子和双亲(父结点)。如果某个孩子结点或父结点不存在,则相应属性的值为空(NIL)。根结点是树中唯一父指针为NULL的结点,而叶子结点的孩子结点指针也为NULL。

性质

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树

复杂度

不论哪一种操作,所花的时间都和树的高度成正比。因此,如果共有n个元素,那么平均每次操作需要O(logn)的时间。

二叉搜索树操作

1.结构

template <class T>
struct BNode

	T _data;
	typedef BNode<T> Node;
	Node* _left;
	Node* _right;
	BNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
	
;

template <class T>
class BTree

public:
	typedef BNode<T> Node;
private:
	Node* _root;
;

2.查找

	Node* find(const T& val)
	
		Node* cur = _root;
		while (cur)
		
			if (cur->_data == val)
				return cur;
			else if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		
	

3.插入

	//插入节点
	//不插入重复的值
	bool insert(const T& val)
	
		//向空树中插入
		if (_root == nullptr)
		
			_root = new Node(val);
			return true;
		
		//搜索,找到合适的插入位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		
			parent = cur;
			if (cur->_data == val)
				return false;
			else if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		
		//插入
		cur = new Node(val);
		if (parent->_data > val)
			parent->_left = cur;
		else
			parent->_right = cur;
		return true;
	

4.中序遍历

	//搜索树的中序遍历有序
	void _inorder(Node* root)
	
		if (root)
		
			_inorder(root->_left);
			cout << root->_data << " ";
			_inorder(root->_right);
		
	

5.拷贝

	Node* copy(Node* root)
	
		if (root == nullptr)
			return nullptr;
		Node* newnode = new Node(root->_data);
		newnode->_left = copy(root->_left);
		newnode->_right = copy(root->_right);
		return newnode;
	

6.销毁

	void destroy(Node* root)
	
		if (root)
		
			cout << "destroy: " << root->_data << endl;
			destroy(root->_left);
			destroy(root->_right);
			delete root;
		
	

7.删除

	bool erase(const T& val)
	
		//查找
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		
			if (cur->_data == val)
				break;
			parent = cur;
			if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		
		//判断是否找到了需要删除的节点
		if (cur == nullptr)
			return false;

		//删除
		//1.删除的为叶子节点
		if (cur->_left == nullptr && cur->_right == nullptr)
		
			//判断是否为根节点
			if (cur == _root)
			
				_root = nullptr;
			
			else
			
				//判断需要删除的节点在父节点的哪一边
				if (parent->_left == cur)
					parent->_left = nullptr;
				else
					parent->_right = nullptr;
			
			//删除节点
			delete cur;
		
		else if (cur->_left == nullptr)  //非叶子节点
		
			//判断删除的是否为根节点
			if (cur == _root)
			
				//更新根节点
				_root = cur->_right;
			
			else
			
				if (parent->_left == cur)
					parent->_left = cur->_right;
				else
					parent->_right = cur->_right;
			

			//删除节点
			delete cur;
		
		else if (cur->_right == nullptr)
		
			if (cur == _root)
			
				_root = cur->_left;
			
			else
			
				if (parent->_right == cur)
					parent->_right = cur->_left;
				else
					parent->_left = cur->_left;
			
			delete cur;
		
		else
		
			//左右子树都存在
			//1.假设找左子树的最右节点
			Node* leftRightMost = cur->_left;
			parent = cur;
			while (leftRightMost->_right)
			
				parent = leftRightMost;
				leftRightMost = leftRightMost->_right;
			
			//2.交换
			swap(cur->_data, leftRightMost->_data);

			//3.删除最右节点
			if (parent->_left == leftRightMost)
				parent->_left = leftRightMost->_left;
			else
				parent->_right = leftRightMost->_left;
			delete leftRightMost;
		
		return true;

	

以上是关于C++从入门到入土第十九篇:二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章

C++从青铜到王者第十九篇:C++二叉树进化之二叉搜索树

C++从入门到入土第二十一篇:二叉搜索树之AVL树

C++从入门到入土第二十一篇:二叉搜索树之AVL树

C++从入门到入土第二十一篇:二叉搜索树之AVL树

C++进阶第十九篇——红黑树(概念+代码实现)

C++从入门到入土第九篇:string相关OJ练习