二叉树进阶 - (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;
};

(本章完)

相关文章
|
4天前
|
编译器 C++
【C++初阶】13. 模板进阶
【C++初阶】13. 模板进阶
29 2
|
4天前
|
存储 C语言 C++
数据结构/C++:二叉搜索树
数据结构/C++:二叉搜索树
13 1
|
4天前
|
存储 算法 编译器
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
14 1
|
4天前
|
存储 机器学习/深度学习 算法
【C++入门到精通】C++入门 —— AVL 树(自平衡二叉搜索树)
【C++入门到精通】C++入门 —— AVL 树(自平衡二叉搜索树)
11 2
|
4天前
|
编译器 C++
【C++进阶】引用 & 函数提高
【C++进阶】引用 & 函数提高
|
4天前
|
C++
【C++高阶(一)】二叉搜索树深度剖析
【C++高阶(一)】二叉搜索树深度剖析
|
4天前
|
存储 C++
【C++进阶(九)】C++多态深度剖析
【C++进阶(九)】C++多态深度剖析
|
4天前
|
编译器 C++
【C++进阶(八)】C++继承深度剖析
【C++进阶(八)】C++继承深度剖析
|
4天前
|
编译器 C语言 C++
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
|
4天前
|
设计模式 C语言 C++
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理