二叉搜索树

二叉搜索树

一、二叉搜索树的概念

又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
1、若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2、若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3、它的左右子树也分别为二叉搜索树

二、对二叉搜索树的操作

1、搜索
规则:
从根节点开始, 若根节点不为空
如果根节点key等于查找节点key 返回true
如果根节点key大于查找节点key 在其左子树查找
如果根节点key小于查找节点key 在其右子树查找
否则,返回false
递归代码:
bool _SearchP(pNode pRoot, K key)//查找递归
	{
		if (pRoot)
		{
			if (pRoot->_key == key)
				return true;
			else if (pRoot->_key > key)
				_SearchP(pRoot->_left, key);
			else
				_SearchP(pRoot->_right, key);
		}
		else
			return false;
	}
非递归代码:
bool _Search(pNode pRoot, K key)//查找非递归
	{
		while (pRoot)
		{
			if (pRoot->_key > key)
				pRoot = pRoot->_left;
			else if (pRoot->_key < key)
				pRoot = pRoot->_right;
			else
				return true;
		}
		return false;
	}
2、插入
在向二叉搜索树中插入新元素时,必须先检测这个元素是否在树中已经存在。如果搜索成功,说明该元素已经存在,
则不进行插入; 否则将新元素加入到搜索停止的地方
规则:
如果是空树,直接插入,然后返回true
搜索需要插入的位置 --比较当前节点与要插入节点的key值大小
    -- 如果要插入节点的key值小于当前节点key值,则与当前节点的左子树的key值比较
    --如果要插入节点的key值大于当前节点key值,则与当前节点的右子树的key值比较
    --如果要插入节点的key值等于当前节点key值,返回false
    --如此循环,直至当前节点为空
插入新节点


递归代码:
bool _InsertP(pNode &pRoot,pNode Pre, K key, V value)//插入递归
	{
		if (pRoot == NULL)
		{
			pRoot = new Node(key, value);
			pRoot->_Parent = Pre;
			pRoot->_left = NULL;
			pRoot->_right = NULL;
			return true;
		}
		if (!Search(key))
		{
			if (pRoot->_key > key)
			{
				Pre = pRoot;
				_InsertP(pRoot->_left,Pre, key, value);
			}
			else
			{
				Pre = pRoot;
				_InsertP(pRoot->_right,Pre, key, value);
			}
		}
		return false;
	}
非递归代码:
bool _Insert(pNode &pRoot,pNode Pre, K key, V value)//插入非递归
	{
		if (Search(key))
			return false;
		pNode pCur = pRoot;
		pNode temp = new Node(key, value);
		if (pCur == NULL)
		{
			pRoot = temp;
			pRoot->_left = NULL;
			pRoot->_right = NULL;
			return true;
		}
		while (pCur)
		{
			Pre = pCur;
			if (pCur->_key > key)
				pCur = pCur->_left;
			else
				pCur = pCur->_right;
		}
	
		pNode parent = Pre;
		if (parent->_key > key)
			parent->_left = temp;
		else
			parent->_right = temp;
		temp->_Parent = parent;
		return true;
	}

3、删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回;否则要删除的结点可能分下面四种
情况:
1、要删除的结点无孩子结点;
2、要删除的结点只有左孩子结点;
3、要删除的结点只有右孩子结点;
4、要删除的结点有左、右孩子结点;
情况1可以归类到2或者3
对于上述情况,相应的删除方法如下:
a、直接删除该结点
b、删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点;
c、删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点;
d、在它的右子树中寻找中序下的第一个结点(key值最小),用它的值填补到被删除节点中,再来处理该结点的删除问题
代码如下:
 
	bool _Delete(pNode &pRoot, K key)//删除非递归
	{
		if (!Search(key))//查找不到
			return false;
		pNode pCur = pRoot;
		//查询删除节点所在位置
		while (pCur->_key != key)
		{
			if (pCur->_key > key)
				pCur = pCur->_left;
			else
				pCur = pCur->_right;
		}
		if (pCur->_left == NULL && pCur->_right != NULL)//要删除节点只有右孩子节点
		{
			pNode parent = pCur->_Parent;
			if (parent->_left == pCur)
				parent->_left = pCur->_right;
			else
				parent->_right = pCur->_right;
			delete pCur;
			pCur = NULL;
			return true;
		}
		else if (pCur->_right != NULL && pCur->_left != NULL)//要删除节点有左、右孩子节点
		{
			pNode pCurR = pCur->_right;
			//在要删除节点的右子树中寻找中序下的第一个节点,用它的值替补到被删除节点中
			while (pCurR)
			{
				if (pCurR->_left == NULL && pCurR->_right == NULL)//要删除节点的右节点没有左右孩子
				{
					pNode parent = pCurR->_Parent;
					pCur->_value = pCurR->_value;
					pCur->_key = pCurR->_key;
					if (pCurR == parent->_left)
						parent->_left = NULL;
					else
						parent->_right = NULL;
					delete pCurR;
					pCurR = NULL;
					return true;
				}
				else if (pCurR->_left == NULL && pCurR->_right != NULL)//要删除节点只有右孩子
				{
					pNode parent = pCurR->_Parent;
					pCur->_value = pCurR->_value;
					pCur->_key = pCurR->_key;
					if (parent->_left == pCurR)
						parent->_left = pCurR->_right;
					else
						parent->_right = pCurR->_right;
					delete pCurR;
					pCurR = NULL;
					return true;
				}
				else
					pCurR = pCurR->_left;
			}
		}
		else
		{
			pNode parent = pCur->_Parent;
			if (parent->_left == pCur)
				parent->_left = pCur->_left;
			else
				parent->_right = pCur->_left;
			delete pCur;
			pCur = NULL;
			return true;
		}
		return false;
	}
三、二叉搜索树性能分析

插入和删除操作的主体部分是查找,查找效率代表了二叉排序中上各个操作的性能。对有n个结点的
二叉排序树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数
即结点越深,则比较次数越多
最坏情况下,二叉排序树的平均查找长度为O(n),一般情况下平均查找长度为O(lbn)


全部代码:
#include<iostream>
using namespace std;

template<class K, class V>
struct SearchBinTreeNode
{
	SearchBinTreeNode(K key,V value)
	: _left(NULL)
	, _right(NULL)
	, _Parent(NULL)
	, _key(key)
	, _value(value)
	{}
	struct SearchBinTreeNode<K,V>* _Parent;
	struct SearchBinTreeNode<K,V>* _left;
	struct SearchBinTreeNode<K,V>* _right;
	K _key;
	V _value;
};
//迭代器
template<class K, class V>
struct BSTIterator
{
	typedef SearchBinTreeNode<K, V>* PNode;
	typedef BSTIterator<K,V> Self;
public:
	BSTIterator()
		: _pNode(NULL)
		, _pHead(NULL)
	{}

	BSTIterator(PNode pHead, PNode pNode)
		: _pNode(pNode)
		, _pHead(pHead)
	{}

	BSTIterator(Self& s)
		: _pNode(s._pNode)
	{}

	Self &operator++()
	{
		Increase();
		return *this;
	}

	Self operator++(int)
	{
		Self temp(*this);
		Increase();
		return temp;
	}

	Self &operator--()
	{
		Decrease();
		return *this;
	}

	Self operator--(int)
	{
		Self temp(*this);
		Decrease();
		return temp;
	}

	bool operator==(const Self& s)
	{
		return _pNode == s._pNode;
	}

	bool operator!=(const Self& s)
	{
		return _pNode != s._pNode;
	}

	K operator*()
	{
		return _pNode->_key;
	}

	PNode operator->()
	{
		return _pNode;
	}

	void Increase()
	{
		if (_pNode->_right)
		{
			_pNode = _pNode->_right;
			while (_pNode->_left)
				_pNode = _pNode->_left;
		}
		else
		{
			PNode parent = _pNode->_Parent;
			while (_pNode == parent->_right)
			{
				_pNode = _pNode->_Parent;
				parent = _pNode->_Parent;
			}
			if (_pNode->_right != parent)
				_pNode = parent;
		}
	}
	void Decrease()
	{
		if (_pNode == _pHead)
			_pNode = _pNode->_right;
		else if (_pNode->_left)
		{
			_pNode = _pNode->_left;
			while (_pNode->_right)
				_pNode = _pNode->_right;
		}
		else
		{
			PNode parent = _pNode->_Parent;
			while (_pNode != parent->_left)
			{
				_pNode = _pNode->_Parent;
				parent = _pNode->_Parent;
			}
			_pNode = parent;
		}
	}
private:
	PNode _pNode;
	PNode _pHead;
};



template<class K, class V>
class SearchBinTree
{
	typedef SearchBinTreeNode<K, V> Node;
	typedef Node* pNode;
public:
	typedef BSTIterator<K,V> Iterator;
	SearchBinTree()
		:_pRoot(NULL)
	{}

	SearchBinTree(const K* arr,size_t size)
	{
		pNode Pre = NULL;
		for (size_t i = 0; i < size; i++)
		{
			_InsertP(_pRoot, Pre, arr[i], i);
		}
	}
	bool Search(K key)//搜索
	{
		return _Search(_pRoot, key);
	}
	bool Delete(K key)//删除
	{
		return _Delete(_pRoot, key);
	}
	void Inorder()
	{
		_Inorder(_pRoot);
	}
private:
	bool _InsertP(pNode &pRoot,pNode Pre, K key, V value)//插入递归
	{
		if (pRoot == NULL)
		{
			pRoot = new Node(key, value);
			pRoot->_Parent = Pre;
			pRoot->_left = NULL;
			pRoot->_right = NULL;
			return true;
		}
		if (!Search(key))
		{
			if (pRoot->_key > key)
			{
				Pre = pRoot;
				_InsertP(pRoot->_left,Pre, key, value);
			}
			else
			{
				Pre = pRoot;
				_InsertP(pRoot->_right,Pre, key, value);
			}
		}
		return false;
	}
	bool _Insert(pNode &pRoot,pNode Pre, K key, V value)//插入非递归
	{
		if (Search(key))
			return false;
		pNode pCur = pRoot;
		pNode temp = new Node(key, value);
		if (pCur == NULL)
		{
			pRoot = temp;
			pRoot->_left = NULL;
			pRoot->_right = NULL;
			return true;
		}
		while (pCur)
		{
			Pre = pCur;
			if (pCur->_key > key)
				pCur = pCur->_left;
			else
				pCur = pCur->_right;
		}
	
		pNode parent = Pre;
		if (parent->_key > key)
			parent->_left = temp;
		else
			parent->_right = temp;
		temp->_Parent = parent;
		return true;
	}
	bool _SearchP(pNode pRoot, K key)//查找递归
	{
		if (pRoot)
		{
			if (pRoot->_key == key)
				return true;
			else if (pRoot->_key > key)
				_SearchP(pRoot->_left, key);
			else
				_SearchP(pRoot->_right, key);
		}
		else
			return false;
	}
	bool _Search(pNode pRoot, K key)//查找非递归
	{
		while (pRoot)
		{
			if (pRoot->_key > key)
				pRoot = pRoot->_left;
			else if (pRoot->_key < key)
				pRoot = pRoot->_right;
			else
				return true;
		}
		return false;
	}
	bool _Delete(pNode &pRoot, K key)//删除非递归
	{
		if (!Search(key))//查找不到
			return false;
		pNode pCur = pRoot;
		//查询删除节点所在位置
		while (pCur->_key != key)
		{
			if (pCur->_key > key)
				pCur = pCur->_left;
			else
				pCur = pCur->_right;
		}
		if (pCur->_left == NULL && pCur->_right != NULL)//要删除节点只有右孩子节点
		{
			pNode parent = pCur->_Parent;
			if (parent->_left == pCur)
				parent->_left = pCur->_right;
			else
				parent->_right = pCur->_right;
			delete pCur;
			pCur = NULL;
			return true;
		}
		else if (pCur->_right != NULL && pCur->_left != NULL)//要删除节点有左、右孩子节点
		{
			pNode pCurR = pCur->_right;
			//在要删除节点的右子树中寻找中序下的第一个节点,用它的值替补到被删除节点中
			while (pCurR)
			{
				if (pCurR->_left == NULL && pCurR->_right == NULL)//要删除节点的右节点没有左右孩子
				{
					pNode parent = pCurR->_Parent;
					pCur->_value = pCurR->_value;
					pCur->_key = pCurR->_key;
					if (pCurR == parent->_left)
						parent->_left = NULL;
					else
						parent->_right = NULL;
					delete pCurR;
					pCurR = NULL;
					return true;
				}
				else if (pCurR->_left == NULL && pCurR->_right != NULL)//要删除节点只有右孩子
				{
					pNode parent = pCurR->_Parent;
					pCur->_value = pCurR->_value;
					pCur->_key = pCurR->_key;
					if (parent->_left == pCurR)
						parent->_left = pCurR->_right;
					else
						parent->_right = pCurR->_right;
					delete pCurR;
					pCurR = NULL;
					return true;
				}
				else
					pCurR = pCurR->_left;
			}
		}
		else
		{
			pNode parent = pCur->_Parent;
			if (parent->_left == pCur)
				parent->_left = pCur->_left;
			else
				parent->_right = pCur->_left;
			delete pCur;
			pCur = NULL;
			return true;
		}
		return false;
	}
	void _Inorder(pNode pRoot)//中序遍历
	{
		if (pRoot)
		{
			_Inorder(pRoot->_left);
			cout << pRoot->_key << "   " << pRoot->_value << endl;
			_Inorder(pRoot->_right);
		}
	}
	pNode _pRoot;
};
int main()
{
	int arr[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
	SearchBinTree<int, int> Tree(arr, 10);
	Tree.Inorder();
	cout << endl;
	Tree.Delete(0);
	Tree.Inorder();
	return 0;
}
运行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值