DS:二叉搜索树

一、二叉搜索数的定义

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

  1. 每个节点都有一个唯一的键值。
  2. 左子树上所有节点的键值小于它的根节点的键值。
  3. 右子树上所有节点的键值大于它的根节点的键值。
  4. 左、右子树也分别是二叉搜索树。

这种结构使得二叉搜索树在进行查找、插入和删除操作时,平均时间复杂度达到O(log n),是一种高效的查找树。

按照这样存储数据,将二叉搜索树进行中序遍历后,结果是升序的。

二、二叉搜索树的实现

2.1二叉搜索树的结点

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


    K _key;

    BSTreeNode<K,V>* _right;
    BSTreeNode<K,V>* _left;
};

2.2二叉搜索树的框架

template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	bool Insert(const K& key);
	Node* Find(const K& key);
	bool Erase(const K& key);
	void InOrder();
private:
void _InOrder(Node* root);
	Node* _root = nullptr;
};

2.3二叉搜索树的插入

//实现节点的插入
bool Insert(const K& key)
{
	//若是空树,就让其成为根节点
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}
	//若不是空树寻找该节点所在位置,并记录父节点
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (key < cur->_key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (key > cur->_key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;//已有结点,插入失败
		}
	}
	//如果key较小,成为左子树,较大,则成为右子树
    if (key < parent->_key) parent->_left = new Node(key);
	else    parent->_right = new Node(key);
	return true;
}

2.4二叉搜索树的查找

Node* Find(const K& key)
{
	Node* cur = _root;
	while (cur)
	{
        if(key==cur->_key)
        return cur;
		if (key < cur->_key)  cur = cur->_left;
		else(key > cur->_key) cur = cur->_right;
	}
	return nullptr;
}

2.4二叉搜索树的删除

分为四种情况 
a. 要删除的结点无孩子
b. 要删除的结点只有左孩子
c. 要删除的结点只有右孩子
d. 要删除的结点有左、右孩子

bool Erase(const K& key)
{
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key == key)//找到了,进行删除操作
		{
			if (parent == nullptr)//查找到的结点为根节点
			{
				delete cur;
				_root = cur = nullptr;
			}
			else
			{
				if (cur->_right == nullptr && cur->_left == nullptr)//没有孩子
				{
					if (parent->_key < cur->_key)
						parent->_right = nullptr;
					else
						parent->_left = nullptr;
                delete cur;
				cur = nullptr;
				}
				else if (cur ->_right == nullptr && cur->_left != nullptr)//只有左孩子
				{
					if (parent->_key < cur->_key)
						parent->_right = cur->_left;
					else
						parent->_left = cur->_left;
					delete cur;
					cur = nullptr;
				}
				else if (cur ->_right != nullptr && cur->_left == nullptr)//只有右孩子
				{
					if (parent->_key < cur->_key)
						parent->_right = cur->_right;
					else
						parent->_left = cur->_right;
					delete cur;
					cur = nullptr;
				}
				else {//两个孩子,找右子树最小结点
					Node* obj = cur->_right;
					Node* objparent = cur;
					while (obj->_left)
					{
						objparent = obj;
						obj = obj->_left;
					}
					cur -> _key = obj -> _key;

					if (objparent == cur)
						cur->_right = obj->_right;
					else
						objparent->_left = obj->_right;
					delete obj;
					obj = nullptr;
				}

			}
			return true;
		}

		parent = cur;//继续查找
		if (cur->_key < key)
			cur = cur->_right;
		else
			cur = cur->_left;
	}
	return false;
}

2.5二叉树的前序遍历

由于会使用到成员变量_root,所以可以制造接口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);
	}

2.6二叉树的拷贝

BSTree() = default; // 强制生成默认构造

Node* Copy(Node* root)
{
	if (root == nullptr) return nullptr;
	Node* newroot = new Node(root->_key);
	newroot->_left = Copy(root->_left);
	newroot->_right = Copy(root->_right);
	return newroot;
}
BSTree(const BSTree<K>& t)
{
	_root = Copy(t._root);
}

2.7二叉树赋值的现代写法

	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		return *this;
	}

2.8二叉树的销毁

//销毁
void Destroy(Node*& root)
{
	if (root == nullptr)
		return;
	//后续遍历,删左 删右 再删中间
	Destroy(root->_left);
	Destroy(root->_right);
	delete root;
	root = nullptr;
}
~BSTree()
{
	Destroy(_root);
}

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值