【c++】二叉搜索树---基本操作

9 篇文章 0 订阅

二叉搜索树

  前面我们写过二叉树, 两种树基本是相同的结构, 但是二叉搜索树又有固定的一些条件, 下来我们一起看.

一.定义 : 

  二叉搜索树又称二叉排序树, 它有两种可能

1. 空树

2. 非空树, 满足 : 

    a. 若左子树不为空, 则左子树上所有的点都小与根节点

    b. 若右子树不为空, 则右子树上所有的点都大于根节点

    c. 它的左右子树也分别为二叉搜索树

例如 : 

二. 操作

1. 查找 Find

a. 若根节点不为空

    若根节点的data <  查找的data, 去右子树找

    若根节点的data >  查找的data, 去左子树找

    若根节点的data =  查找的data, 返回true

    都没有就返回false

  b. 根节点为空, 直接返回false

2. 插入 Insert

a. 如果是空树, 直接插入

b. 不是空树, 先找到合适的位置, 然后再进行插入

3. 删除 Erase

a. 要删除的节点没有孩子节点, 直接删除.

b. 要删除的节点只有右孩子, 让该节点的双亲节点指向它的右孩子, 然后再进行删除.

c. 要删除的节点只有左孩子, 同上.

d. 要删除的节点有左右孩子, 比较复杂,两种思路

    i : 找到中序下的前一个节点, 即左孩子的最右孩子, 交换该节点与要删除节点的值, 再删除找到的节点.

    ii : 找到中序下的后一个节点, 即右孩子的最左孩子, 同上.

举例说明d :

三. 二叉搜索树的实现

#include <iostream>
using namespace std;

template <class T>
struct BSTNode
{
	BSTNode<T>* _left;
	BSTNode<T>* _right;
	T _data;
	BSTNode(const T& data = T())
		:_left(nullptr)
		, _right(nullptr)
		, _data(data)
	{}
};

template <class T>
class BSTree
{
public:
	typedef BSTNode<T> Node;
	typedef Node* pNode;

	BSTree()
		: _root(nullptr)
	{}

	~BSTree()
	{
		_Destroy(_root);
	}

	BSTree(const BSTree<T>& bst)
	{
		_root = _Copy(bst._root);
	}

	pNode _Copy(const pNode root)
	{
		if (root == nullptr)
			return root;
		pNode newRoot = new Node(root->_data);
		newRoot->_left = _Copy(root->_left);
		newRoot->_right = _Copy(root->_right);
		return newRoot;
	}
	
	BSTree& operator=(const BSTree<T>& bst)
	{
		if (this != &bst)
		{
			if (_root)
				_Destroy(_root);
			_root = _Copy(bst._root);
		}
		return *this;
	}

	bool Find(const T& data)
	{
		//先判断是否为空
		if (_root == nullptr)
		{
			return false;
		}
		//定义变量, 不要直接用_root
		pNode cur = _root;
		while (cur)
		{
			if (cur->_data == data)
			{
				return true;
			}
			else if (cur->_data > data)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}
		return false;
	}

	bool Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			return true;
		}
		//有关系, 所以要用两个指针
		pNode parent = nullptr;
		pNode cur = _root;
		//一直找到合适的位置
		while (cur)
		{
			parent = cur;

			if (cur->_data == data)
			{
				return false;
			}
			else if (cur->_data > data)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}

		//插入新的节点
		cur = new Node(data);
		if (parent->_data > data)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		return true;
	}

	bool Erase(const T& data)
	{
		// 如果树为空,删除失败
		if (_root == nullptr)
		{
			return false;
		}
		// 查找在data在树中的位置
		pNode cur = _root;
		pNode parent = nullptr;
		while (cur)
		{
			if (cur->_data == data)
			{
				break;
			}
			parent = cur;
			if (cur->_data > data)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}
		// data不在二叉搜索树中,无法删除
		if (cur == nullptr)
		{
			return false;
		}
		//data在树中,分情况讨论
		if (cur->_left == nullptr && cur->_right == nullptr)
		{
			//两个子树都为空
			if (cur != _root)
			{
				if (parent->_left == cur)
					parent->_left = nullptr;
				else
					parent->_right = nullptr;
			}
			else
			{
				_root = nullptr;
			}
			delete cur;
			cur = nullptr;
		}
		else if (cur->_right == nullptr)
		{
			//右子树为空
			if (cur != _root)
			{
				if (parent->_left == cur)
				{
					parent->_left = cur->_left;
				}
				else
					parent->_right = cur->_left;
			}
			else
			{
				_root = cur->_left;
			}
			delete cur;
			cur = nullptr;
		}
		else if (cur->_left == nullptr)
		{
			//左子树为空
			if (cur != _root)
			{
				if (parent->_left == cur)
				{
					parent->_left = cur->_right;
				}
				else
					parent->_right = cur->_right;
			}
			else
				_root = cur->_right;

			delete cur;
			cur = nullptr;
		}
		else
		{
			//左右都不为空
			pNode next = cur->_left;
			parent = cur;
			//找到左子树的最右节点
			while (next->_right)
			{
				parent = next;
				next = next->_right;
			}
			//交换值
			cur->_data = next->_data;
			//链接
			if (parent->_left == next)
				parent->_left = next->_left;
			else
				parent->_right = next->_left;
			//删除cur
			delete next;
			next = nullptr;
		}
		return true;
	}

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

	void _InOrder(pNode root)
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_data << " ";
		_InOrder(root->_right);
	}

	void _Destroy(pNode& root)
	{
		if (root == nullptr)
			return;
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
		root = nullptr;
	}
private:
	pNode _root = nullptr;
};

void test()
{
	BSTree<int> bst;
	bst.Insert(5);
	bst.Insert(7);
	bst.Insert(1);
	bst.Insert(3);
	bst.Insert(4);
	bst.Insert(6);
	bst.Insert(9);
	bst.Insert(8);
	bst.Insert(2);
	bst.Insert(0);
	bst.InOrder();
	BSTree<int> bst2 = bst;
	bst2.InOrder();
	bst.Erase(3);
	bst.Erase(4);
	bst.InOrder();
	cout << bst.Find(0) << endl;
	cout << bst.Find(1) << endl;
	cout << bst.Find(10) << endl;
}

int main()
{
	test();
	system("pause");
	return 0;	
}

以上就是二叉搜索树以及一些基本的操作, 谢谢观看^_^

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值