二叉搜索树的基本特征和模拟实现

一、二叉搜索树的定义
二叉搜索树又称二叉排序树,它或者是一颗空树,或者是一棵排序树,它具有如下性质:
1、若它的左子树不为空,则它的左子树的所有节点的值都小于根节点的值
2、若它的右子树不为空,则它的右子树的所有节点的值都大于根节点的值
3、它的左右子树也都是二叉搜索树
二、二叉树的主要操作分析
1、二叉树的插入
a.若二叉树为空,则直接插入,然后返回true
b.若二叉树不为空,按照二叉搜索树的性质查找插入位置,插入新节点
举个例子:插入节点12
在这里插入图片描述
2、二叉树的查找
若根节点不为空
a.如果root->_key=Find(key),返回true;
b.如果root->_key>Find(key),在其左树查找
c.如果root->_key<Find(key),在其右树查找
否则,返回false。
举个例子:查找2
在这里插入图片描述
3、二叉树的删除
首先查找要删除的元素是否在二叉树中,如果不存在,则返回,否则要删除的节点可能存在以下几种情况:
a.要删除的节点左为空,则让父亲指向节点的右,删除节点
b.要删除的节点右为空,则让父亲指向节点的左,删除节点
c.要删除的节点左右都不为空,找右树的最左节点或左树的最右节点替换要删除的节点
举例说明
1)要删除的节点左为空,删除8
在这里插入图片描述
2)要删除的节点右为空,删除7
在这里插入图片描述
3)要删除的节点左右都不是空,删除7
这里需要注意的是:
若找的是右树的最左节点,则最左节点的右树不一定为空;
若找的是左树的最右节点,则最右节点的左树不一定为空;

在这里插入图片描述
附上二叉搜索树的模拟实现代码:

#pragma once
#include <iostream>
#include <set>
using namespace std;
template <class K>
struct BSTNode
{
	BSTNode(const K& key = K())
		:_left(nullptr)
		,_right(nullptr)
		, _key(key)
	{}
	BSTNode* _left;
	BSTNode* _right;
	K _key;
};
template <class K>
class BSTree
{
	typedef BSTNode<K> Node;
public:
	BSTree()
		:_root(nullptr)
	{}
	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;
	}
	//copy(t)
	BSTree(const BSTree<K>& tree)
	{
		_root = Copy(tree._root);
	}
	//t1=t2
	BSTree<K>& operator=(const BSTree<K>& tree)
	{
		if (this != &tree)
		{
			//首先销毁t1,再赋值
			_Destory(this->_root);
			this->_root = Copy(tree._root);
		}
		return *this;
	}
	~BSTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}
	//插入元素
	bool Insert(const K& key)
	{
		//如果树为空,直接插入
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}
		Node* cur = _root;
		Node* parents = nullptr;
		//找插入新节点的位置
		while (cur)
		{
			parents = cur;
			if (key > cur->_key)
			{
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else
			{
				//set有重复的不插入
				return false;
			}
		}
		cur = new Node(key);
		//插入节点
		if (key > parents->_key)
		{
			parents->_right = cur;
		}
		else
			parents->_left = cur;
		return true;
	}
	//查找值为data的节点
	bool Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key == key)
			{
				return true;
			}
			else if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else if (key > cur->_key)
			{
				cur = cur->_right;
			}
		}
		return false;
	}
	bool Erase(const K& key)
	{
		if (_root == nullptr)
			return false;
		Node* cur = _root;
		Node* parents = nullptr;
		if (Find(key))
		{
			//找data在树中的位置
			while (cur)
			{
				if (key == cur->_key)
				{
					break;
				}
				else if (key > cur->_key)
				{
					parents = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parents = cur;
					cur = cur->_left;
				}
			}
			Node* del = cur;
			//cur的左树为空
			if (cur->_left == nullptr)
			{
				//key是根节点
				if (parents == nullptr)
				{
					_root = cur->_right;
				}
				else
				{
					//删除cur,再把parents和cur的子树链起来
					if (parents->_left == cur)
					{
						parents->_left = cur->_right;
					}
					else
						parents->_right = cur->_right;
				}
			}
			//cur的右树为空
			else if (cur->_right == nullptr)
			{
				//data是根节点
				if (parents == nullptr)
				{
					_root = cur->_left;
				}
				else
				{
					if (parents->_left == cur)
					{
						parents->_left = cur->_left;
					}
					else
						parents->_right = cur->_left;
				}
			}
			//替代法删除:用左树的最右节点或右树的最左节点覆盖cur
			//cur的左右都不为空,找左树的最右节点(该节点的右一定为空)和右树的最左节点(该节点的左一定为空)
			else
			{
				//1、找cur的替代节点,假定替代节点replace指向cur的右
				Node* replace = cur->_right;
				//p_replace作为replaced父亲节点
				Node* p_replace = cur;
				//2、找替代节点replace的最左节点
				while (replace->_left)
				{
					p_replace = replace;
					replace = replace->_left;
				}
				//3、用replace的值去覆盖cur的值
				cur->_key = replace->_key;
				//4、删除replace节点
				if (p_replace->_left == replace)
				{
					p_replace->_left = replace->_right;
				}
				else
				{
					p_replace->_right = replace->_right;
				}
				del = replace;
			}

			delete del;
			return true;
		}
		else
			return false;
	}
	//_root节点是私有的,在类外面无法访问,所以要套一个_InOrder
	void InOrder()
	{
		_InOrder(_root);
	}
private:
	void _InOrder(Node* root)
	{
		if (root)
		{
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
	}
	void _Destory(Node* root)
	{
		//后序销毁
		if (root == nullptr)
		{
			return;
		}
		_Destory(root->_left);
		_Destory(root->_right);
		delete	root;
	}
private:
	Node* _root;
};

需要注意的是:
中序遍历:要套_InOrder,因为_root是私有的,无法在类外面访问
析构:递归实现后序销毁
拷贝构造:前序拷贝
赋值:要先销毁原来的树,再进行递归赋值

测试代码:

void test()
{
	/*BSTree<int> BT;
	BT.Insert(5);
	BT.Insert(3);
	BT.Insert(7);
	BT.Insert(1);
	BT.Insert(4);
	BT.Insert(6);
	BT.Insert(8);
	BT.InOrder();
	cout << endl;*/
	/*cout <<"查找:"<< BT.Find(3) << endl;
	cout << endl;
	cout << "删除:" << BT.Erase(7) << endl;*/
	BSTree<int> t;
	int a[] = { 5, 3, 7, 1, 4, 6, 8, 9, 0, 2 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();
	cout << endl;
	BSTree<int> copy(t);
	copy.InOrder();
	cout << endl;
	t = copy;
	t.InOrder();
	/*t.Erase(5);
	t.Erase(1);
	t.Erase(8);
	t.InOrder();
	t.~BSTree();*/
}
int main()
{
	test();
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yam_sunshine/article/details/89500485
今日推荐