二叉搜索树

               二叉查找树(Binary Search Tree)(二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 

     

          1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不同。

          2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。

          3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。

          4. 左右子树都是二叉搜索树。

            对于二叉搜索树,在实现它的结点的插入、删除、查找时,插入结点不是很复杂,但是对于其删除有一定的难度。在实现删除时,要考虑的情况较多。

      一、对二叉树的定义:

template<class K,class V>
struct BSTNode
{
	K _key;
	V _value;
	BSTNode<K, V>* _Left;
	BSTNode<K, V>* _Right;
	BSTNode(K key,V value)
		:_key(key)
		,_value(value)
		,_Left(NULL)
		,_Right(NULL)
	{}

};
template<class K, class V>
class BSTree
{
	typedef BSTNode<K, V>  Node;
public:
	BSTree()
		:_root(NULL)
	{}
}
对于定义,应该没什么问题。那就来说说它的插入、删除、查找的实现。


二、插入的实现

   对于插入,在此我用两种方法来实现(递归和非递归)

  首先,非递归的方法:(在插入时,都要按照二叉树的性质来实现即要在合适位置)

  思想:1、先考虑根结点为空。

             2、保存上一个节点,插入时要找上一个结点。

             3、找到合适的位置(要插入的key小于当前key就往左子树找反之往右子树找)

             4、找到合适位置后,插入结点

bool Insert(const K& key, const V& value)
	{
		if (_root == NULL)
		{
                    _root = new Node(key, value);
		    return true;
		}

		Node* cur = _root;
		Node* parent = NULL;

		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_Left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_Right;
			}
			else
			{
				return false;
			}
		}

		if (parent->_key > key)
		{
			parent->_Left = new Node(key, value);
		}
		else
		{
			parent->_Right = new Node(key, value);
		}
		return true;
	}
      非递归完成后,我们来看一下Insert的递归的形式

bool  _Insert_R(Node* &root, const K& key, const V& value)
	{
		if (root == NULL)
		{
			root = new Node(key, value);
			return true;
		}
		if (root->_key > key)
		{
			return _Insert_R(root->_Left,key,value);
		}
		else if (root->_key < key)
		{
			return _Insert_R(root->_Right,key,value);
		}
		return false;
	}
接下来就是的查找和删除,先看一下查找:

 三、查找的实现(非递归形式)

Node* _Find(Node* root, const K& key)
	{
		if (root == NULL)
			return NULL;
		Node* cur = root;
		while (cur)
		{
			if (cur->_key > key)
			{
				cur = cur->_Left;
			}
			else if (cur->_key < key)
			{
				cur = cur->_Right;
			}
			else 
			{
				return cur;
			}
		}
			return NULL;
	}
查找的递归形式

Node* _Find_R(Node* &root, const K& key)
	{
		if (root == NULL) //没有结点
			return root;
		if (root->_key == key)
			return root;
		if (root->_key < key)
		{
			return _Find_R(root->_Right, key);
		}
		else
		{
			return _Find_R(root->_Left, key);
		}
	}
四、删除的实现:(非递归)对于删除,在此需要考虑的情况非常多。

下面是删除的思想:

(在删除时,也要和查找一样,先查找到要删除的结点,然后删除)



   1、考虑根结点为空情况和一个结点情况

   2、当有多个结点时,根据上图中的情形考虑到不同情况

     (1)要删除的左结点的左子树或右子数为空。

     (2)要删除的结点是根结点。

     (3)要删除的结点的左右结点都不为空。

	bool _Remove(Node* root, const K& key)
	{
		if (root == NULL)    //没有结点
			return false;
		if (root->_Left == NULL&&root->_Right == NULL)   //一个结点
		{
			if (root->_key == key)
			{
				delete root;
				root = NULL;
				return true;
			}
			else
			{
				return false;
			}
		}
		Node* cur = root;        //多个节点
		Node* prev = NULL;
		while (cur)
		{
			if (cur->_key > key)
			{
				prev = cur;
				cur = cur->_Left;
			}
			else if (cur->_key < key)
			{
				prev = cur;
				cur = cur->_Right;
			}
			else   //找到了要删除的结点,判断左子树是否为空,若为空,把删除点的左子树设为删除点右子树的左子树
			{
				Node *del = cur;
				if (cur->_Left == NULL)
				{
					if (prev== NULL)
					{
						_root = cur->_Right;
					}
					else
					{
						if (prev->_Left == cur)
						{
							prev->_Left = cur->_Right;
						}
						else
						{
							prev->_Right = cur->_Right;
						}
					}
				}
				else if (cur->_Right == NULL)
				{
					if (prev == NULL){
						_root= cur->_Left;
					}
					else
					{
						if (prev->_Left == cur)
						{
							prev->_Left = cur->_Left;
						}
						else
						{
							prev->_Right = cur->_Left;
						}
					}
				}
				else  //左右都不为空
				{
					prev = cur;
					Node* fistleft = cur->_Right;
					while (fistleft->_Left)
					{
						prev = fistleft;
						fistleft = fistleft->_Left;
					}
					swap(cur->_key, fistleft->_key);
					swap(cur->_value, fistleft->_value);
					del = fistleft;
					if (prev->_Left == fistleft)
					{
						prev->_Left = fistleft->_Right;
					}
					else
					{
						prev->_Right = fistleft->_Right;
					}
				}
				delete del;
				return true;
			}
		}
		return false;
	}
删除的递归形式:
bool _Remove_R(Node* &root, const K& key)  //引用
	{
		if (root == NULL)
		{
			return false;
		}
		if (root->_key < key)
		{
			return _Remove_R(root->_Right,key);
		}
		else if (root->_key > key)
		{
			return _Remove_R(root->_Left,key);
		}
		else
		{
			if (root->_Left == NULL)
				{
					root = root->_Right;
				}
			else if (root->_Right==NULL)
			{
				root = root->_Left;
			}
			else
			{
				Node* firstleft = root->_Right;
				while (firstleft->_Left)
				{
					firstleft = firstleft->_Left;
				}
				swap(firstleft->_key, root->_key);
				swap(firstleft->_value, root->_value);
				_Remove_R(firstleft,key);
			}
			return true;
		}
	}
五、二叉查找树的时间复杂度


它和二分查找一样,插入和查找的时间复杂度均为lgN,但是在最坏的情况下仍然会有N的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值