二叉树进阶 - (C++二叉搜索树的实现)

简介: 二叉树进阶 - (C++二叉搜索树的实现)


二叉搜索树

1. 二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

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

2. 二叉搜索树操作

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

2.1 二叉搜索树的查找

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

b、最多查找高度次,走到到空,还没找到,这个值不存在。

从根节点开始,用 cur 指针指向当前节点。

在遍历过程中,比较要查找的值 key 与当前节点的值 cur->_key 的大小关系,根据比较结果来决定继续在左子树还是右子树中查找。

如果要查找的值 key 大于当前节点的值 cur->_key,则继续在当前节点的右子树中查找。

如果要查找的值 key 小于当前节点的值 cur->_key,则继续在当前节点的左子树中查找。

如果要查找的值 key 等于当前节点的值 cur->_key,表示找到了该值,直接返回 true。

当遍历到叶子节点时,仍然没有找到要查找的值,表示该值不存在于树中,返回 false。

2.2 二叉搜索树的插入

插入的具体过程如下:

a. 树为空,则直接新增节点,赋值给root指针

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

首先判断根节点 _root 是否为空,如果为空,则将新节点作为根节点,并返回插入成功。

如果根节点不为空,则从根节点开始遍历树来查找合适的插入位置。

在遍历过程中,使用 cur 指针来指向当前节点,parent 指针来指向当前节点的父节点。

如果要插入的值 key 大于当前节点的值 cur->_key,则继续在当前节点的右子树中查找。

如果要插入的值 key 小于当前节点的值 cur->_key,则继续在当前节点的左子树中查找。

如果要插入的值 key 等于当前节点的值 cur->_key,表示值已经存在于树中,不进行插入,直接返回插入失败。

当遍历到叶子节点时,将新节点插入到当前节点的左子树或右子树,根据新节点的值与当前节点的值的大小关系来决定插入到左子树还是右子树。
插入完成后,返回插入成功。

2.3 二叉搜索树的删除(重点)

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

a. 要删除的结点无孩子结点

b. 要删除的结点只有左孩子结点

c. 要删除的结点只有右孩子结点

d. 要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

  • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
  • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
  • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除

从根节点开始,用 cur 指针指向当前节点,parent 指针指向当前节点的父节点。

在遍历过程中,比较要删除的值 key 与当前节点的值 cur->_key 的大小关系,根据比较结果来决定继续在左子树还是右子树中查找要删除的节点,并同时记录当前节点的父节点。

如果要删除的值 key 大于当前节点的值 cur->_key,则继续在当前节点的右子树中查找,并更新父节点指针。

如果要删除的值 key 小于当前节点的值 cur->_key,则继续在当前节点的左子树中查找,并更新父节点指针。

如果要删除的值 key 等于当前节点的值 cur->_key,表示找到了要删除的节点。

根据要删除节点的左右子树情况,执行不同的删除操作:

如果要删除的节点的左子树为空,将父节点的右指针指向要删除节点的右子树。
如果要删除的节点的右子树为空,将父节点的左指针指向要删除节点的左子树。
如果要删除的节点的左右子树都不为空,找到要删除节点右子树中的最小节点,将要删除节点的值替换为最小节点的值,然后删除最小节点。
返回 true 表示删除成功。
如果遍历完整棵树都没有找到要删除的节点,返回 false 表示删除失败。

3. 二叉搜索树的(代码)实现


非递归实现

#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{
  BSTreeNode<K>* _left;
  BSTreeNode<K>* _right;
  K _key;
  BSTreeNode(const K& key)
    :_left(nullptr)
    , _right(nullptr)
    , _key(key)
  {}
};
template <class K>
class BSTree
{
  typedef BSTreeNode<K> Node;
public:
  //插入
  bool Insert(const K& key)
  {
    if (_root == nullptr)
    {
      _root = new Node(key);
      return true;
    }
    Node* cur = _root;
    Node* parent = nullptr;
    while (cur)
    {
      parent = cur;
      if (key > cur->_key)
      {
        cur = cur->_right;
      }
      else if (key < cur->_key)
      {
        cur = cur->_left;
      }
      else
      {
        return false;
      }
    }
    cur = new Node(key);
    if (key > parent->_key)
    {
      parent->_right = cur;
    }
    if (key < parent->_key)
    {
      parent->_left = cur;
    }
    return true;
  }
  //中序打印
  void InOrder()
  {
    _InOrder(_root);
    cout << endl;
  }
  //查找
  void Find(const K& key)
  {
    Node* cur = _root;
    while (cur)
    {
      if (key > cur->_key)
      {
        cur = cur->_right;
      }
      else if (key < cur->_key)
      {
        cur = cur->_left;
      }
      else
      {
        return true;
      }
    }
    return false;
  }
  //删除
  bool Erase(const K& key)
  {
    Node* cur = _root;
    Node* parent = nullptr;
    while (cur)
    {
      if (key > cur->_key)
      {
        parent = cur;
        cur = cur->_right;
      }
      else if (key < cur->_key)
      {
        parent = cur;
        cur = cur->_left;
      }
      else
      {
        //开删
        if (cur->_left == nullptr)
        {//左为空
          if (cur == _root)
          {
            _root = cur->_right;
          }
          else if (cur == parent->_left)
          {
            parent->_left = cur->_right;
          }
          else
          {
            parent->_right = cur->_right;
          }
        }
        else if (cur->_right == nullptr)
        {//右为空
          if (cur == _root)
          {
            _root = cur->_left;
          }
          else if (cur == parent->_left)
          {
            parent->_left = cur->_left;
          }
          else
          {
            parent->_right = cur->_left;
          }
        }
        else
        {//左右都不为空
          Node* SubLeft = cur->_right;
          Node* _parent = cur;
          while (SubLeft->_left)
          {
            _parent = SubLeft;
            SubLeft = SubLeft->_left;
          }
          swap(cur->_key, SubLeft->_key);
          if (SubLeft == _parent->_left)
          {
            _parent->_left = SubLeft->_right;
          }
          else
          {
            _parent->_right = SubLeft->_right;
          }
        }
        return true;
      }
    }
    return false;
  }
  //析构
  ~BSTree()
  {
    Destroy(_root);
  }
  //BSTree = default;
  BSTree()
  {}
  //拷贝构造
  BSTree(const BSTree<K>& t)
  {
    _root = Copy(t._root);
  }
  //赋值拷贝构造
  BSTree<K>& operator=(BSTree<K> t)
  {
    swap(_root, t._root);
    return *this;
  }
private:
  Node* Copy(Node* root)
  {
    if (root == nullptr)
    {
      return 0;
    }
    Node* NewRoot = new Node(root->_key);
    NewRoot->_left = Copy(root->_left);
    NewRoot->_right = Copy(root->_right);
    return NewRoot;
  }
  void Destroy(Node*& root)
  {
    if (root == nullptr)
    {
      return;
    }
    return Destroy(root->_left);
    return Destroy(root->_right);
    delete root;
    root = nullptr; 
  }
  void _InOrder(Node* root)
  {
    if (root == nullptr)
    {
      return;
    }
    _InOrder(root->_left);
    cout << root->_key << " ";
    _InOrder(root->_right);
  }
private:
  Node* _root = nullptr;
};

递归实现

#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{
  BSTreeNode<K>* _left;
  BSTreeNode<K>* _right;
  K _key;
  BSTreeNode(const K& key)
    :_left(nullptr)
    , _right(nullptr)
    , _key(key)
  {}
};
template <class K>
class BSTree
{
  typedef BSTreeNode<K> Node;
public:
  bool findR(const K& key)
  {
    return _findR(_root, key);
  }
  bool InsertR(const K& key)
  {
    return _InsertR(_root, key);
  }
  bool EraseR(const K& key)
  {
    return _EraseR(_root, key);
  }
  void InOrder()
  {
    _InOrder(_root);
    cout << endl;
  }
    //析构
  ~BSTree()
  {
    Destroy(_root);
  }
  //BSTree = default;
  BSTree()
  {}
  //拷贝构造
  BSTree(const BSTree<K>& t)
  {
    _root = Copy(t._root);
  }
  //赋值拷贝构造
  BSTree<K>& operator=(BSTree<K> t)
  {
    swap(_root, t._root);
    return *this;
  }
private:
  Node* Copy(Node* root)
  {
    if (root == nullptr)
    {
      return 0;
    }
    Node* NewRoot = new Node(root->_key);
    NewRoot->_left = Copy(root->_left);
    NewRoot->_right = Copy(root->_right);
    return NewRoot;
  }
  void Destroy(Node*& root)
  {
    if (root == nullptr)
    {
      return;
    }
    return Destroy(root->_left);
    return Destroy(root->_right);
    delete root;
    root = nullptr; 
  }
  //递归实现删除
  bool _EraseR(Node*& root, const K& key)
  {
    if (root == nullptr)
    {
      return false;
    }
    if (key < root->_key)
    {
      return _EraseR(root->_left, key);
    }
    else if (key > root->_key)
    {
      return _EraseR(root->_right, key);
    }
    else
    {
      if (root->_left == nullptr)
      {
        Node* del = root;
        root = root->_right;
        delete del;
        return true;
      }
      else if (root->_right == nullptr)
      {
        Node* del = root;
        root = root->_left;
        delete del;
        return true;
      }
      else
      {
        Node* SubLeft = root->_right;
        while (SubLeft->_left)
        {
          SubLeft = SubLeft->_left;
        }
        swap(root->_key, SubLeft->_key);
        //转换在子树中去递归删除   
        return _EraseR(root->_right, key);
      }
    }
  }
  //递归实现插入
  bool _InsertR(Node*& root, const K& key)
  {
    if (root == nullptr)
    {
      root = new Node(key);
      return true;
    }
    if (key > root->_key)
    {
      return _InsertR(root->_right, key);
    }
    if (key < root->_key)
    {
      return _InsertR(root->_left, key);
    }
    else
    {
      return false;
    }
  }
  //递归实现查找
  bool _findR(Node* root, const K& key)
  {
    if (root == nullptr)
    {
      return false;
    }
    else if (key > root->_key)
    {
      return _findR(root->_right, key);
    }
    else if (key < root->_key)
    {
      return _findR(root->_left, key);
    }
    else
    {
      return true;
    }
  }
  //中序遍历打印
  void _InOrder(Node* root)
  {
    if (root == nullptr)
    {
      return;
    }
    _InOrder(root->_left);
    cout << root->_key << " ";
    _InOrder(root->_right);
  }
private:
  Node* _root = nullptr;
};

(本章完)

相关文章
|
3月前
|
Java C++
c++ 红黑树(自平衡二叉搜索树)(k,v型)
因为红黑树是一种特殊的AVL树(但少了平衡因子的存在),所以其结点的定义是在AVL树上加上新的成员变量,用于表示结点的颜色。RED,BLACK,//三叉链, _kv(kv){}首先我们在默认构造上,默认构造结点的颜色默认情况下为红色所以为什么构造结点时,默认将结点的颜色设置为红色?这是因为:当我们向红黑树插入结点时,若我们插入的是黑色结点,那么插入路径上黑色结点的数目就比其他路径上黑色结点的数目多了一个,即破坏了红黑树的性质4,此时我们就需要对红黑树进行调整。
87 0
|
7月前
|
C++ 容器
c++中的二叉搜索树
c++中的二叉搜索树
|
8月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
171 12
|
8月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
159 10
|
8月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
238 3
|
10月前
|
存储 C++
【C++】二叉搜索树(BST)
二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,其每个节点的左子树所有节点值小于该节点值,右子树所有节点值大于该节点值,且左右子树也均为二叉搜索树。BST支持高效的数据查找、插入和删除操作,时间复杂度通常为O(log n)。本文档详细介绍了BST的基本概念、存储结构及其实现,包括迭代和递归两种方式的查找、插入、删除等操作的具体代码示例。
190 3
|
存储 C++
【C++】二叉树进阶之二叉搜索树(下)
【C++】二叉树进阶之二叉搜索树(下)
78 4
|
Java 编译器 C++
【C++】二叉树进阶之二叉搜索树(上)
【C++】二叉树进阶之二叉搜索树(上)
70 3
|
算法 测试技术 C++
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
97 2
|
算法 C++
【C++高阶】高效搜索的秘密:深入解析搜索二叉树
【C++高阶】高效搜索的秘密:深入解析搜索二叉树
88 2