二叉搜索树(binary search tree)——数据结构

二叉搜索树

二叉搜索树(Binary Search Tree),任何节点的键值一定大于其左子树中每一个节点的键值,并且小于其右子树中的每一个节点的键值。

二叉搜索树或者是一颗空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上的所有节点的键值小于根节点的键值
  • 若它的左子树不为空,则右子树上的所有节点的键值大于根节点的键值
  • 它的左右子树也分别为二叉搜索树

插入

在这里插入图片描述

  1. 若树为空,则直接插入
  2. 若树不为空,从根节点开始,遇到键值较大的则向左,遇到键值较小的则向右,直到尾端,插入新的节点
//非递归插入
bool insert(const K& key)
{
	//如果二叉树为空
	if (_root == nullptr)
	{
		//创建一个节点作为根节点
		_root = new Node(key);
		return true;
	}
	//二叉树不为空
	Node* parent = nullptr;
	Node* cur = _root;
	//循环遍历二叉树
	while (cur)
	{
		//如果要插入的值大于当前节点的值
		if (cur->key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->key == key)
		{
			return false;
		}
	}
	cur = new Node(key);
	//插入在左边还是右边
	if(parent->key>key)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	return true;
}

//递归插入
bool _InsertR(Node*& root,const K& key)
{
	if (root == nullptr)
	{
		root = new Node(key);
	}
	if (root->key < key)
	{
		return _InsertR(root->_right, key);
	}
	else if (root->key > key)
	{
		return _InsertR(root->_left, key);
	}
	else
	{
		return false;
	}
}
bool InsertR(const K& key)
{
	return _InsertR(_root, key);
}

删除

首先查找元素是否在二叉树中,如果不存在,则返回,否则要删除的结点分为:

  1. 删除该节点,并且让被删除节点的双亲节点,指向被删除节点的左孩子节点
  2. 删除该节点,并且让被删除节点的双亲节点,指向被删除节点的右孩子节点
  3. 在他的右子树中寻找中序下的第一个结点,用它的键值来填补到被删除节点中,再来处理删除该节点的问题
//非递归删除
bool Erase(const K& key)
{
	Node* parent = nullptr;
	Node* cur = _root;
    //寻找要删除的结点
	while (cur)
	{
		if (cur->key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
        //找到了要删除的结点,开始删除
		else
		{
             //1、删除的结点只有右孩子
			if (cur->_left == nullptr)
			{
				if (parent == nullptr)
				{
					_root = cur->_right;
				}
				else
				{
					if (cur == parent->_left)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
				}
				delete cur;
			}
             //2、删除的结点只有左孩子
			else if (cur->_right == nullptr)
			{
				if (parent == nullptr)
				{
					_root = cur->_left;
				{
				if (cur == parent->_left)
				{
					parent->_left = cur->_left;
				}
				else						
                 {
					parent->_right = cur->_left;
				}
				delete cur;
			}
         	//3、删除的结点左右孩子都有或者都没有
			else
			{
				Node* rightminParent = cur;
				Node* rightmin = cur->_right;
                 //寻找右子树的左孩子
				while (rightmin->_left)
				{
					rightminParent = rightmin;
					rightmin = rightmin->_left;
				}
				swap(cur->key, rightmin->key);
				if (rightminParent->_right == rightmin)
				{
					rightminParent->_right = rightmin->_right;
                  }
				else
				{
					rightminParent->_left = rightmin->_right;
				}
				delete rightmin;
			}
			return true;
		}
	}
	return false;
}

//递归的删除
bool _EraseR(Node*& cur,const K& key)
{
    if(cur==nullptr)
    {
        return false;
    }
    if(cur->key<key)
    {
        return _EraseR(cur->_right,key);
    }
    else if(cur->key>key)
    {
        return _EraseR(cur->_left,key);
    }
    else if(cur->key==key)
    {
        //1、左为空
        //2、右为空
        //3、左右都不为空
        Node* del=cur;
        if(cur->_left==nullptr)
        {
            cur=cur->_right;
            delete del;
            return true;
        }
        else if(cur->_right==nullptr)
        {
            cur=cur->_left;
            delete del;
            return true;
        }
        else 
        {
            //替换删除法,左子树的最大节点或者 右子树的最小节点
            Node* minNode=cur->_right;
            while(minNode->_left)
            {
                minNode=minNode->left;
            }
            cur->key=minNode->key;
            //转换成删除右子树的最小节点
            return _EraseR(cur->_right,minNode->key);
        }
    }
}
bool EraseR(const K& key)
{
    return _EraseR(_root,key);
}

搜索

根据二叉树的性质进行搜索:

  1. 如果目标值等于节点的值,则返回节点
  2. 如果目标值小于节点的值,则继续在左子树中搜索
  3. 如果目标值大于节点的值,则继续在右子树中搜索
//非递归查找
Node* Find(const K& key)
{
	Node* cur=_root;
    //遍历二叉树
    while(cur)
    {
        if(cur->key>key)
        {
            cur=cur->_left;
        }
        else if(cur->key<key)
        {
            cur=cur->_right;
        }
        else if(cur->key==key)
        {
            return cur;
        }
    }
    //如果没有找到返回nullptr
    return nullptr;
}

//递归查找
Node* FindR(const K& key)
{
    return _FindR(_root,key);
}
Node* _FindR(Node* root,const K& key)
{
    if(root==nullptr)
    {
        return nullptr;
    }
    if(root->key>key)
    {
        return _FindR(root->_left,key);
    }
    else if(root->key<key)
    {
        return _FindR(root->_right,key);
    }
    else if(root->key==key) 
    {
        return root;
    }
}

模拟实现

#pragma once
#include<iostream>
using namespace std;

//二叉树的节点
template<class K>
struct BSTreeNode
{
	BSTreeNode<K>* _left;//左节点
	BSTreeNode<K>* _right;//右节点
	K key;//节点的key
	
	//构造函数
	BSTreeNode(const K& key)
		:_left(nullptr)
		,_right(nullptr)
		,key(key)
	{

	}
};

//K->key
template<class K>
//Binary Search Tree
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	//插入
	bool insert(const K& key)
	{
		//如果二叉树为空
		if (_root == nullptr)
		{
			//创建一个节点作为根节点
			_root = new Node(key);
			return true;
		}
		//二叉树不为空
		//定义parent指针,用来指向cur的根节点
		Node* parent = nullptr;
		//定义cur指针指当前节点
		Node* cur = _root;
		//循环遍历二叉树
		while (cur)
		{
			//如果要插入的值大于当前节点的值
			if (cur->key < key)
			{
				//记录根节点
				parent = cur;
				//往右边遍历
				cur = cur->_right;
			}
			else if (cur->key > key)
			{
				parent = cur;
				//往左边遍历
				cur = cur->_left;
			}
			else if (cur->key == key)
			{
				return false;
			}
		}
		//找到插入的位置,将key放入
		cur = new Node(key);
		//如果要插入位置的跟节点大于key
		if(parent->key>key)
		{
			//插入的节点做左节点
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		return true;
	}

	//递归插入
	bool _InsertR(Node*& root,const K& key)
	{
		if (root == nullptr)
		{
			root = new Node(key);
		}
		if (root->key < key)
		{
			return _InsertR(root->_right, key);
		}
		else if (root->key > key)
		{
			return _InsertR(root->_left, key);
		}
		else
		{
			return false;
		}
	}
	bool InsertR(const K& key)
	{
		return _InsertR(_root, key);
	}

	//查找
	Node* Find(const K& key)
	{
		//定义cur节点指针指向根节点
		Node* cur = _root;
		//遍历二叉搜索树
		while (cur)
		{
			//如果当前节点的值大于要找的值
			if (cur->key > key)
			{
				//当前节点的左子树寻找
				cur = cur->_left;
			}
			//如果当前节点的值小于于要找的值
			else if (cur->key < key)
			{
				//当前节点的右子树寻找
				cur = cur->_right;
			}
			//如果当前节点的值等于要找的值
			else if (cur->key == key)
			{
				//找到,返回节点指针
				return cur;
			}
		}
		//遍历完还没有找到,返回空
		return nullptr;
	}

	//递归查找
	Node* _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		if (root->key > key)
		{
			return _FindR(root->_left, key);
		}
		else if (root->key < key)
		{
			return _FindR(root->_right, key);
		}
		else if (root->key == key)
		{
			return root;
		}
	}
	Node* FindR(const K& key)
	{
		return _FindR(_root, key);
	}

	//递归的删除
	bool _EraseR(Node*& cur, const K& key)
	{
		if (cur == nullptr)
		{
			return false;
		}
		if (cur->key < key)
		{
			return _EraseR(cur->_right, key);
		}
		else if (cur->key > key)
		{
			return _EraseR(cur->_left, key);
		}
		else if (cur->key == key)
		{
			//1.左为空,2.右为空,3.左右都不为空
			Node* del = cur;
			if (cur->_left == nullptr)
			{
				cur = cur->_right;
				delete del;
				return true;
			}
			else if (cur->_right == nullptr)
			{
				cur = cur->_left;
				delete del;
				return true;
			}
			else
			{
				//替换法删除,左树的最大节点或者右树的最小节点
				Node* minNode = cur->_right;
				while (minNode->_left)
				{
					minNode = minNode->_left;
				}
				cur->key = minNode->key;
				//转化成删除右子树的最小节点
				return _EraseR(cur->_right,minNode->key);
			}
		}
	}
	bool EraseR(const K& key)
	{
		return _EraseR(_root,key);
	}

	//删除
	bool Erase(const K& key)
	{
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//找到了,开始删除
				if (cur->_left == nullptr)
				{
					if (parent == nullptr)
					{
						_root = cur->_right;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (parent == nullptr)
					{
						_root = cur->_left;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
						delete cur;
					}
				}
				else
				{
					Node* rightminParent = cur;
					Node* rightmin = cur->_right;
					while (rightmin->_left)
					{
						rightminParent = rightmin;
						rightmin = rightmin->_left;
					}
					swap(cur->key, rightmin->key);
					if (rightminParent->_right == rightmin)
					{
						rightminParent->_right = rightmin->_right;
					}
					else
					{
						rightminParent->_left = rightmin->_right;
					}
					delete rightmin;
				}
				return true;
			}
		}
		return false;
	}
	//中序遍历
	void _Inorder(Node* root)
	{
		if(root==nullptr)
		{
			return;
		}
		_Inorder(root->_left);
		cout << root->key << " ";
		_Inorder(root->_right);
	}
	void Inorder()
	{
		_Inorder(_root);
		cout << endl;
	}
private:
	Node* _root = nullptr;
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值