C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++二叉搜索树实现

C++二叉搜索树及其实现方法实例代码

作者:zzh_zao

这篇文章主要介绍了C++二叉搜索树及其实现方法的相关资料,搜索二叉树是一种左小右大的二叉树结构,支持高效查找、插入和删除操作,需要的朋友可以参考下

前言

搜索二叉树(Binary Search Tree,简称BST)是一种基础且重要的数据结构,它在查找、插入和删除操作上具有高效性。本文将围绕搜索二叉树的原理,结合C++代码实现,深入探讨这一数据结构的核心特性与具体实现。

一.二叉搜索树的基本概念

二叉搜索树(Binary Search Tree,简称 BST)是一种特殊的二叉树,它满足以下性质:

对于树中的每个节点,其左子树中所有节点的值都小于该节点的值

对于树中的每个节点,其右子树中所有节点的值都大于该节点的值

左右子树也分别是二叉搜索树

这种特性使得二叉搜索树在查找、插入和删除操作上具有较高的效率,平均时间复杂度为 O (log n)。

二.二叉搜索树的性能分析

最优情况下,⼆叉搜索树为完全⼆叉树(或者接近完全⼆叉树),其⾼度为:log2 N

最差情况下,⼆叉搜索树退化为单⽀树(或者类似单⽀),其⾼度为:N

所以综合⽽⾔⼆叉搜索树增删查改时间复杂度为:O(N)

⼆分查找也可以实现O(log2N) 级别的查找效率,但是⼆分查找有两⼤缺陷:

这⾥也就体现出了平衡⼆叉搜索树的价值。

三.二叉搜索树的实现

搜索二叉树的基本概念与特性

搜索二叉树是一种特殊的二叉树,它满足以下性质:

这些性质使得搜索二叉树在进行查找操作时具有天然的优势,我们可以利用节点值的大小关系快速缩小查找范围,类似于有序数组的二分查找。

搜索二叉树的节点结构设计

首先来看搜索二叉树的节点结构实现:

template<class K>
struct BSTreeNode
{
	K _key;
	BSTNode<K>* _left;
	BSTNode<K>* _right;
	BSTNode(const K& key)
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{
	}
};

节点采用模板设计,使得该结构可以存储任意类型的数据,只要该类型支持比较运算。

搜索二叉树的类结构与核心操作

类的基本结构

template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	// 构造、拷贝构造、赋值运算符、析构函数
	BSTree() = default;
	BSTree(const BSTree<K>& t);
	BSTree<K>& operator=(BSTree<K> t);
	~BSTree();
	
	// 核心操作
	bool Insert(const K& key);
	bool Find(const K& key);
	bool Erase(const K& key);
	
	// 中序遍历
	void InOrder();
private:
	// 中序遍历的递归辅助函数
	void _InOrder(Node* root);
	// 拷贝构造的递归辅助函数
	Node* Copy(Node* root);
	// 析构函数的递归辅助函数
	void Destory(Node* root);
private:
	Node* _root = nullptr;
};

构造与析构函数

插入操作(Insert)

插入操作是构建搜索二叉树的基础,其实现逻辑如下:

bool Insert(const K& key)
{
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else {
			return false; // 键值已存在,插入失败
		}
	}
	// 找到插入位置,创建新节点并连接到树中
	cur = new Node(key);
	if (parent->_key > key)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	return true;
}

插入操作的步骤:

查找操作(Find)

查找是搜索二叉树的核心功能,利用树的特性可以高效地定位目标节点:

bool Find(const K& key)
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key < key)
		{
			cur = cur->_right;
		}
		else if (cur->_key > key)
		{
			cur = cur->_left;
		}
		else
		{
			return true; // 找到目标节点
		}
	}
	return false; // 未找到目标节点
}

查找操作的逻辑非常直观,与插入操作类似:

删除操作(Erase)

删除操作是搜索二叉树中最复杂的操作,需要考虑多种情况:

bool Erase(const K& key)
{
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else {
			// 找到要删除的节点,处理不同情况
			if (cur->_left == nullptr)
			{
				// 情况1:左子树为空
				if (cur == _root)
				{
					_root = _root->_right;
				}
				if (parent->_right == cur)
				{
					parent->_right = cur->_right;
				}
				else
				{
					parent->_left = cur->_right;
				}
				delete cur;
			}
			else if(cur->_right == nullptr)
			{
				// 情况2:右子树为空
				if (cur == _root)
				{
					_root = _root->_left;
				}
				if (parent->_right == cur)
				{
					parent->_right = cur->_left;
				}
				else
				{
					parent->_left = cur->_left;
				}
				delete cur;
			}
			else
			{
				// 情况3:左右子树都不为空
				Node* pMinRight = cur;
				Node* minRight = cur->_right;
				while (minRight->_left)
				{
					pMinRight = minRight;
					minRight = minRight->_left;
				}
				// 找到右子树中的最小节点(最左节点)
				swap(minRight->_key, cur->_key);
				// 删除右子树中的最小节点
				if (pMinRight->_left == minRight)
				{
					pMinRight->_left = minRight->_right;
				}
				else
				{
					pMinRight->_right = minRight->_right;
				}
				delete minRight;
			}
			return true;
		}
	}
	return false; // 未找到要删除的节点
}

删除操作需要处理三种情况:

这种处理方式确保了删除节点后,搜索二叉树的性质仍然保持。

中序遍历(InOrder)

中序遍历可以将搜索二叉树中的节点按从小到大的顺序输出,这是搜索二叉树的一个重要特性:

void InOrder()
{
	_InOrder(_root);
	cout << endl;
}

private:
void _InOrder(Node* root)
{
	if (root == nullptr)
	{
		return;
	}
	_InOrder(root->_left);
	cout << root->_key << ' ';
	_InOrder(root->_right);
}

中序遍历的顺序是:左子树 → 根节点 → 右子树,对于搜索二叉树来说,中序遍历的结果正好是有序的。

搜索二叉树的性能分析

时间复杂度

空间复杂度

最坏情况

搜索二叉树的性能依赖于树的高度,在最坏情况下(如插入的节点是有序的),搜索二叉树会退化为链表,此时所有操作的时间复杂度都会退化为O(n)。为了避免这种情况,可以使用平衡二叉树(如AVL树、红黑树等)来保证树的高度始终保持在O(log n)。

搜索二叉树的应用场景

搜索二叉树在实际应用中非常广泛,以下是一些常见的应用场景:

总体代码实现

using namespace std;
template<class K>

struct BSTreeNode

{
	K _key;
	BSTNode<K>* _left;
	BSTNode<K>* _right;
	BSTNode(const K& key)
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{
	}
};


template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	BSTree() = default;
	BSTree(const BSTree<K>& t)
	{
		_root = Copy(t._root);
	}
	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		return *this;
	}
	~BSTree()
	{
		Destory(_root);
		_root = nullptr;
	}
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else {
				return false;
			}
			cur = new Node(key);
			if (parent->_key > key)
			{
				parent->_left = cur;
			}
			else
			{
				parent->_right = cur;
			}
			return true;
		}
	}
	bool Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{

				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else
			{
				return true;
			}
		}

		return false;
	}
	bool Erase(const K& key)
	{
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else {
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{
						_root = _root->_right;
					}
					if (parent->_right == cur)
					{
						parent->_right = cur->_right;
					}
					else
					{
						parent->_left = cur->_right;
					}
					delete cur;
				}
				else if(cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = _root->_left;
					}
					if (parent->_right == cur)
					{
						parent->_right = cur->_left;
					}
					else
					{
						parent->_left = cur->_left;
					}
					delete cur;
				}
				else
				{
					Node* pMinRight = cur;
					Node* minRight = cur->_right;
					while (minRight->_left)
					{
						pMinRight = minRight;
						minRight = minRight->_left;
					}
					swap(minRight->_key, cur->_key);
					if (pMinRight->_left == minRight)
					{
						pMinRight->_left = minRight->_right;
					}
					else
					{
						pMinRight->_right = minRight->_right;
					}
					delete minRight;
				}
				return true;
			}
		}
		return false;
	}	

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << ' ';
		_InOrder(root->_right);
	}
	Node* Copy(Node* root)
	{
		if (root == nullptr)
			return;
		Node* copy = new Node(root->_key);
		copy->_left = Copy(root->_left);
		copy->_right = Copy(root->_right);
		return copy;
	}
	void Destory(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		Destory(root->_left);
		Destory(root->_right);
		delete root;
	}
private:
	Node* _root = nullptr;
};

总结 

到此这篇关于C++二叉搜索树及其实现方法的文章就介绍到这了,更多相关C++二叉搜索树实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文