二叉搜索树

一、二叉搜索树的性质:
1、每个结点都有一个作为搜索依据的关键码,并且这个关键码是互不相同的
2、左子树上的所有结点的关键码都小于根节点的关键码
3、右子树上的所有结点的关键码都大于根节点的关键码
4、左右子树也是二叉搜索树
例:


二、二叉树搜索树所支持的操作

1、查找
  在二叉搜索树上进行查找,是从根节点出根据关键码的大小选择一条分支向下进行查找。一般情况下最多查找树的高度次就能得出结果,所以大多数情况下二叉搜索树的平均查找时间是O(logN)。但是如果删除多的话,二叉搜索树会逐渐向左倾斜,退化成链表,时间复杂度就是O(N).
例:

(1)、查找3

(2)、查找8


(3)、查找最小值
   在这棵树不为空的情况下,判断根节点有没有左子树。如果根节点没有左子树的话,则直接返回根节点。如果有左子树的话,则沿左分支查找最后一个数。
      
 Node* _FindMin(Node* cur)
       {
              assert(cur);
              while (cur->_left)
              {
                     cur = cur->_left;
              }
              return cur;
       }


(4)、查找最大值
   在这棵树不为空的情况下,判断根节点有没有右子树。如果根节点没有右子树的话,则直接返回根节点。如果有右子树的话,则沿右分支查找最后一个数。
   
    Node* _FindMax(Node* cur)
       {
              assert(cur);
              while (cur->_right)
                     cur = cur->_right;
              return cur;
       }


(5)、查找第k个数


       Node* _Find(Node* cur,int k)
       {
              int num =_Size(cur->_left);
              if (k == num + 1)
                     return cur;
              else if (k <= num)
              {
                     return _Find(cur->_left,k);
              }
              else
              {
                     return _Find(cur->_right,k-num-1);
              }
       }




2、插入
  插入一个数使得二叉树仍然是一颗二叉搜索树。从根节点出发搜索插入位置,然后把新节点作为叶子结点插入。这样的话不需要移动结点,只需要修改一个叶子结点的空指针就行。
   
    void _Insert(Node* &cur,const T& x)
       {
              if (cur == NULL)
              {
                     cur = new Node(x);
                     return;
              }
              if (x < cur->_data)
              {
                     _Insert(cur->_left, x);
              }
              else if (cur->_data < x)
              {
                     _Insert(cur->_right,x);
              }
       }

例:


3、删除
  删除比较复杂一点,但是可以分为两种情况。

 (1、假如要删除的结点有两个孩子,则应该将右子树上关键码最小的结点与要删除的结点交换,再删除右子树上关键码最小的那个结点。
例:


     (2、假如要删除的结点只有一个孩子
例:

假如只有右孩子或者没有孩子与只有左孩子是相同的道理。

       void _Remove(Node* &cur,const T& x)
       {
              if (cur == NULL)
                     return;
              if (x < cur->_data)
              {
                     _Remove(cur->_left,x);
              }
              else if (cur->_data < x)
              {
                     _Remove(cur->_right,x);
              }
              else
              {
                     if (cur->_left != NULL&&cur->_right != NULL) //如果要删除的结点有两个孩子
                     {
                           Node* del = cur;
                           cur->_data =_FindMin(cur->_right)->_data;
                           _Remove(cur->_right,cur->_data);
                     }
                     else                   //如果要删除的结点是叶子结点或只有一个孩子的结点
                     {
                           Node* del = cur;
                           cur = (cur->_left != NULL) ? cur->_left : cur->_right;
                           delete del;
                     }
              }
       }



#pragma once
#include<cassert>
#include<queue>
using namespace std;

template<typename T>
struct SearchTreeNode
{
	SearchTreeNode<T>* _left;
	SearchTreeNode<T>* _right;
	T _key;
	SearchTreeNode(const T& key)
		:_left(NULL)
		, _right(NULL)
		, _key(key)
	{}
};



template<typename T>
class BinarySearchTree
{
	typedef SearchTreeNode<T> Node;
public:
	BinarySearchTree()
		:_root(NULL)
	{}

	BinarySearchTree(T* a,size_t size)
	{
		_root = NULL;
		for (int i = 0; i < (int)size; i++)
		{
			Insert(a[i]);
		}
	}

	BinarySearchTree(const BinarySearchTree<T>& tree)     //拷贝构造
		:_root(NULL)
	{
		if (tree._root == NULL)
			return;
		queue<Node*> q;
		q.push(tree._root);
		while (!q.empty())
		{
			Node* cur = q.front();
			Insert(cur->_key);
			q.pop();
			if (cur->_left)
			{
				q.push(cur->_left);
			}
			if (cur->_right)
			{
				q.push(cur->_right);
			}
		}	
	}

	~BinarySearchTree()
	{
		_Destory(_root);
	}


	BinarySearchTree<T>& operator=(BinarySearchTree<T>& tree)  //赋值运算符重载
	{
		if (this!=&tree)
		{
			BinarySearchTree<T> tmp(tree);
			swap(_root,tmp._root);
		}
		return *this;
	}

	bool Insert(const T& x)
	{
		if (_root == NULL)
		{
			_root = new Node(x);
			return true;
		}
		Node* cur = _root;
		Node* parent =NULL;
		while (cur)                     //找到要插入的位置
		{
			parent = cur;
			if (x > cur->_key)      //如果要插入的值大于当前结点
			{
				cur = cur->_right;
			}
			else if (x<cur->_key)     //如果要插入的值小于当前结点
			{
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		//判断一下x要插入到parent的左边还是右边
		if (x>parent->_key)       //插入到右边
		{
			parent->_right = new Node(x);
		}
		else         //插入到左边
		{
			parent->_left = new Node(x);
		}
		return true;
	}

	bool Remove(const T& x)
	{
		Node* cur=_root;
		Node* parent = NULL;
		while (cur)
		{
			if (cur->_key < x)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key>x)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				if (cur->_left == NULL)     //如果cur的左孩子为空,或左右都为空
				{
					if (parent == NULL)
					{
						_root = cur->_right;
					}        
					else
					{
						if (parent->_left==cur)
						     parent->_left = cur->_right;
					    else
						     parent->_right = cur->_right;
					}
					delete cur;
				}
				else if (cur->_right == NULL)    //如果cur的右孩子为空
				{
					if (parent == NULL)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}
					delete cur;
				}
				else           //如果左右都不为空,寻找cur的右子树的最左结点,与之交换
				{
					Node* tmp = cur->_right;
					Node* prev = cur;
					while (tmp->_left)
					{
						prev= tmp;
						tmp =tmp->_left;
					}
					swap(cur->_key,tmp->_key);      //交换着两个结点的值
					if (prev->_left == tmp)
					{
						prev->_left = NULL;
					}
					else
					{
						prev->_right = NULL;
					}
					delete tmp;					
				}
				return true;
			}
		}
		return false;
	}

	const Node* Find(const T& x)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < x)
			{
				cur = cur->_right;
			}
			else if (cur->_key>x)
			{
				cur = cur->_left;
			}
			else 
			{
				return cur;
			}
		}
		return cur;
	}
protected:
	void _Destory(Node* cur)
	{
		if (cur == NULL)
			return;
		_Destory(cur->_left);
		_Destory(cur->_right);
		delete cur;
	}

private:
	Node* _root;
};


















































  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值