二叉搜索树详解

二叉搜索树(Binary Search Tree,简称BST)是一种具有广泛应用的数据结构,用于高效地管理大量数据。二叉搜索树的操作效率很大程度上取决于树的高度,理想情况下与树的深度(对数深度)成正比。

1. 二叉搜索树的定义

二叉搜索树是具有以下特性的二叉树:

  • 节点的左子树只包含小于当前节点的值。
  • 节点的右子树只包含大于当前节点的值。
  • 左右子树也必须分别为二叉搜索树。

 

2. 基本操作

2.1 查找

查找操作是二叉搜索树中最基本的操作之一。从根节点开始,与目标值进行比较,若小于根节点的值,则继续在左子树中搜索;若大于,则在右子树中搜索。这一过程递归进行,直到找到目标值或遍历至空节点。

2.2 插入

插入操作如下:

  1. 树为空:直接将新节点设为根节点。
  2. 树非空:按照二叉搜索树的性质找到插入位置,将新节点插入到此位置。

2.3 删除

删除操作在二叉搜索树中是相对复杂的,因为它可能涉及到重新调整树的结构。以下是删除操作的详细步骤:

2.3.1 删除无子节点的节点

这是最简单的情况。只需要将父节点指向该节点的指针设为 nullptr,然后释放该节点的内存。

2.3.2 删除只有一个子节点的节点

这种情况下,我们只需要用其子节点来替换它:

  • 如果目标节点只有左子节点,我们将其父节点的相应指针指向目标节点的左子节点。
  • 如果目标节点只有右子节点,相应地,我们将其父节点的指针指向目标节点的右子节点。
2.3.3 删除有两个子节点的节点

当一个节点有两个子节点时,删除操作稍微复杂一些。我们通常采用的策略是:

  1. 找到替代节点:通常有两个选择:
    • 后继节点:在右子树中找最小的节点(最左节点)。
    • 前驱节点:在左子树中找最大的节点(最右节点)。
  2. 替换值:将找到的替代节点的值复制到要删除的节点。
  3. 删除替代节点:由于替代节点已经移动到了要删除的节点的位置,我们现在需要删除原来的替代节点。这个替代节点要么是一个叶节点,要么是只有一个子节点的节点,因此可以使用前面的删除方法。

二叉搜索树的代码实现 

template<class T>
struct BSTNode
{
 BSTNode(const T& data = T())
   : _pLeft(nullptr) , _pRight(nullptr), _data(data)
 {}
 BSTNode<T>* _pLeft;
 BSTNode<T>* _pRight;
 T _data;
};
template<class T>
class BSTree
{
 typedef BSTNode<T> Node;
 typedef Node* PNode;
public:
 BSTree(): _pRoot(nullptr)
 {}
 // 同学们自己实现,与二叉树的销毁类似
 ~BSTree();
 // 根据二叉搜索树的性质查找:找到值为data的节点在二叉搜索树中的位置
 PNode Find(const T& data);
 bool Insert(const T& data)
 {
 // 如果树为空,直接插入
 if (nullptr == _pRoot)
 {
 _pRoot = new Node(data);
 return true;
 }
 // 按照二叉搜索树的性质查找data在树中的插入位置
 PNode pCur = _pRoot;
 // 记录pCur的双亲,因为新元素最终插入在pCur双亲左右孩子的位置
 PNode pParent = nullptr;
 while (pCur)
 {
 pParent = pCur;
 if (data < pCur->_data)
比特就业课
 pCur = pCur->_pLeft;
 else if (data > pCur->_data)
 pCur = pCur->_pRight;  // 元素已经在树中存在
 else
 return false;
 }
 // 插入元素
 pCur = new Node(data);
 if (data < pParent->_data)
 pParent->_pLeft = pCur;
 else
 pParent->_pRight = pCur;
 return true;
 }
 bool Erase(const T& data)
 {
 // 如果树为空,删除失败
 if (nullptr == _pRoot)
 return false;
 // 查找在data在树中的位置
 PNode pCur = _pRoot;
 PNode pParent = nullptr;
 while (pCur)
 {
 if (data == pCur->_data)
 break;
 else if (data < pCur->_data)
 {
 pParent = pCur;
 pCur = pCur->_pLeft;
 }
 else
 {
 pParent = pCur;
 pCur = pCur->_pRight;
 }
 }
 // data不在二叉搜索树中,无法删除
 if (nullptr == pCur)
 return false;
 // 分以下情况进行删除,同学们自己画图分析完成
 if (nullptr == pCur->_pRight)
 {
 // 当前节点只有左孩子或者左孩子为空---可直接删除
 }
 else if (nullptr == pCur->_pRight)
 {
 // 当前节点只有右孩子---可直接删除
 }
 else
 {// 当前节点左右孩子都存在,直接删除不好删除,可以在其子树中找一个替代结点,
比如:
 // 找其左子树中的最大节点,即左子树中最右侧的节点,或者在其右子树中最小的节
点,即右子树中最小的节点
 // 替代节点找到后,将替代节点中的值交给待删除节点,转换成删除替代节点
 }
 return true;
 }
// 同学们自己实现
 void InOrder();
private:
 PNode _pRoot;
};

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqxnb666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值