二叉搜索树

发布于:2025-06-02 ⋅ 阅读:(30) ⋅ 点赞:(0)

目录

二叉搜索树简介

代码结构

核心操作实现详解

插入操作(insert)

删除操作(erase)

搜索操作(Find)

测试与验证

总结


在数据结构与算法的世界里,二叉搜索树(Binary Search Tree,简称BST)是一种非常重要的数据结构,它以其高效的查找、插入和删除操作,在众多应用场景中发挥着关键作用。本文将通过一段C++ 代码,详细解析二叉搜索树的实现过程。

二叉搜索树简介

二叉搜索树是一种特殊的二叉树,它满足以下性质:

- 对于树中的每个节点,其左子树中所有节点的值都小于该节点的值。

- 对于树中的每个节点,其右子树中所有节点的值都大于该节点的值。

基于这些性质,二叉搜索树能够在平均情况下以O(\log n) 的时间复杂度完成查找、插入和删除操作,其中n 是树中节点的数量。

代码结构

我们来看的这段C++ 代码定义了一个  BSTree  类,用于实现二叉搜索树。代码主要包含以下几个部分:

1. 节点定义: Node  结构体定义了二叉搜索树的节点,每个节点包含一个键值  _key  以及指向左子节点和右子节点的指针  _left  和  _right 。


 

cpp

template<class K>

struct BSTreeNode

{

 BSTreeNode(const K& key)

  :_key(key)

  , _left(nullptr)

  , _right(nullptr)

 {}

 K _key;

 BSTreeNode<K>* _left;

 BSTreeNode<K>* _right;

};



1. 树类定义: BSTree  类包含了二叉搜索树的主要操作,如插入、删除、搜索等,并且包含一个指向根节点的指针  _root 。

cpp

template<class K>

class BSTree

{

 typedef BSTreeNode<K> Node;

public:

 // 插入操作

 bool insert(const K& key)

 {

  // 代码实现...

 }

 // 删除操作

 bool erase(const K& key)

 {

  // 代码实现...

 }

 // 搜索操作

 bool Find(const K& key)

 {

  // 代码实现...

 }

private:

 Node* _root;

};

1. 测试函数: TestBtNode  函数用于测试二叉搜索树的功能,通过创建一个  BSTree  对象,并向其中插入一些数据,然后进行相关操作的测试。

cpp

void TestBtNode()

{

 int arr[] = { 8,3,1,10,6,4,7,14,13 };

 BSTree<int> t;

 for (auto e : arr)

 {

  t.insert(e);

 }

 t._InOrder();

}

核心操作实现详解

插入操作(insert)

插入操作是向二叉搜索树中添加新节点的过程。其基本思路是从根节点开始,根据要插入的值与当前节点值的大小关系,决定向左子树或右子树移动,直到找到合适的插入位置。

cpp

bool insert(const K& key)

{

 if (_root == nullptr)

 {

  _root = new Node(key);

  return true;

 }

 Node* parent = nullptr;

 Node* cur = _root;

 while (cur)

 {

  parent = cur;

  if (cur->_key < key)

  {

   cur = cur->_right;

  }

  else if (cur->_key > key)

  {

   cur = cur->_left;

  }

  else

  {

   return false;

  }

 }

 cur = new Node(key);

 if (parent->_key < key)

 {

  parent->_right = cur;

 }

 else

 {

  parent->_left = cur;

 }

 return true;

}

在这段代码中,首先判断根节点是否为空,如果为空则直接创建新节点作为根节点。否则,通过一个循环,在树中找到合适的插入位置,最后将新节点插入到相应的位置。

删除操作(erase)

删除操作相对复杂一些,需要考虑多种情况:

1. 删除节点为叶子节点:直接删除该节点。

2. 删除节点只有左子树或右子树:用子树替换该节点。

3. 删除节点左右子树都存在:通常有两种方法,一种是用左子树的最大值节点或右子树的最小值节点替换该节点,然后删除替换节点。这里采用的是用左子树的最大值节点替换。

cpp

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 (cur == _root)

    {

     _root = cur->_right;

    }

    else if (parent->_left == cur)

    {

     parent->_left = cur->_right;

    }

    else

    {

     parent->_right = cur->_right;

    }

    delete cur;

   }

   else if (cur->_right == nullptr)

   {

    if (cur == _root)

    {

     _root = cur->_left;

    }

    else if (parent->_left == cur)

    {

     parent->_left = cur->_left;

    }

    else

    {

     parent->_right = cur->_left;

    }

    delete cur;

   }

   // 双不为空

   else

   {

    Node* parent = cur;

    Node* lm = cur->_left;

    while (lm->_right)

    {

     parent = lm;

     lm = lm->_right;

    }

    // 交换

    swap(cur->_key, lm->_key);



    if (parent->_left == lm)

    {

     parent->_left == lm->_left;

    }

    else

    {

     parent->_right == lm->_left;

    }

    cur = lm;

   }

   delete cur;

   return true;

  }

 }

 return false;

}



代码中首先找到要删除的节点,然后根据不同情况进行处理。如果是叶子节点或单支节点,直接进行删除和子树连接操作;如果是左右子树都存在的节点,找到左子树的最大值节点,交换值后删除该节点。

搜索操作(Find)

搜索操作是在二叉搜索树中查找指定值的过程。通过比较当前节点的值与目标值的大小关系,决定向左子树或右子树继续查找,直到找到目标值或遍历完整个树。

cpp

bool Find(const K& key)

{

 Node* cur = _root;

 while (cur)

 {

  if (cur->_key < key)

  {

   cur = cur->_right;

  }

  else if (cur->_key > key)

  {

   cur = cur->_left;

  }

  else

  {

   return true;

  }

 }

 return false;

}

这段代码通过一个循环,从根节点开始,不断比较当前节点值与目标值,直到找到目标值返回  true ,或者遍历完树未找到返回  false 。

测试与验证

在  TestBtNode  函数中,通过创建一个  BSTree  对象,并向其中插入一组数据  { 8,3,1,10,6,4,7,14,13 } ,然后可以调用相关操作进行测试,例如搜索某个值是否存在,删除某个节点等。虽然代码中  t._InOrder()  这里的  _InOrder  方法未给出实现(推测是中序遍历用于打印树的节点),但我们可以补充一个简单的中序遍历实现来查看树的结构:


 

cpp

void _InOrder(Node* root)

{

 if (root == nullptr)

 {

  return;

 }

 _InOrder(root->_left);

 std::cout << root->_key << " ";

 _InOrder(root->_right);

}

void InOrder()

{

 _InOrder(_root);

 std::cout << std::endl;

}



通过调用  InOrder  方法,我们可以看到插入数据后的二叉搜索树按照中序遍历的结果,即节点值从小到大排列,验证二叉搜索树的性质。

总结

本文通过详细解析一段C++ 代码,介绍了二叉搜索树的基本概念、核心操作的实现原理以及测试方法。二叉搜索树作为一种重要的数据结构,其高效的查找、插入和删除操作使其在许多算法和实际应用中都有着广泛的应用。理解和掌握二叉搜索树的实现,对于进一步学习更复杂的数据结构和算法具有重要意义。 同时,代码中也存在一些可以优化和改进的地方,例如增加内存管理的安全性检查,添加更多的辅助函数来提高代码的可读性和可维护性等。希望本文能帮助读者更好地理解二叉搜索树及其实现过程。


网站公告

今日签到

点亮在社区的每一天
去签到