搜索二叉树(二叉搜索树)的实现(递归与非递归)

简介: 搜索二叉树(二叉搜索树)的实现(递归与非递归)

一、搜索二叉树的概念

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

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为搜索二叉树。

二、搜索二叉树的操作

1. 搜索二叉树的查找

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

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

template <class K>
bool BSTree<K>::Find(const K& key)
{
  node* cur = _root;
  while (cur)
  {
    if (key < cur->_key)//小就往左走
    {
      cur = cur->_left;
    }
    else if (key > cur->_key)//大就往右走
    {
      cur = cur->_right;
    }
    else//找到了
    {
      return true;
    }
  }
  return false;
}

2. 搜索二叉树的插入

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

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

template <class K>
bool BSTree<K>::Insert(const K& key)
{
  //树为空,则直接新增节点,赋值给root指针
  if (_root == nullptr)
  {
    _root = new node(key);
    return true;
  }
  node* parent = nullptr;
  node* cur = _root;
  while (cur)//找到key该去的位置
  {
    parent = cur;
    if (cur->_key < key)//大就往右走
    {
      cur = cur->_right;
    }
    else if (cur->_key > key)//小就往左走
    {
      cur = cur->_left;
    }
    else//有相等的值了无法再插入了
    {
      return false;
    }
  }
  if (parent->_key < key)
  {
    parent->_right = new node(key);
  }
  else
  {
    parent->_left = new node(key);
  }
  return true;
}

3.搜索二叉树的删除

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

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

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

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

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

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

情况a:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除

情况b:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除

情况c:在它的右子树中寻找中序下的第一个结点(关键码最小),或者在它的左子树中寻找中序下的第一个结点(关键码最大)用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除。

template <class K>
bool BSTree<K>::Erase(const K& key)
{
  node* parent = nullptr;
  node* cur = _root;
  while (cur)
  {
    
    if (cur->_key > key)
    {
      parent = cur;
      cur = cur->_left;
    }
    else if (cur->_key < key)
    {
      parent = cur;
      cur = cur->_right;
    }
    else//找到了就跳出循环
    {
      break;
    }
  }
  if (cur == nullptr)//cur走到空就意味着没找到
  {
    return false;
  }
  if (cur->_left == nullptr)//左为空 
  {
    if (cur == _root)
    {
      _root = cur->_right;
    }
    else if (cur == parent->_left)
    {
      parent->_left = cur->_right;
    }
    else if (cur == parent->_right)
    {
      parent->_right = cur->_right;
    }
    delete cur;
    return true;
  }
  else if (cur->_right == nullptr)//右为空
  {
    if (cur == _root)
    {
      _root = cur->_left;
    }
    else if (cur == parent->_left)
    {
      parent->_left = cur->_left;
    }
    else if (cur == parent->_right)
    {
      parent->_right = cur->_left;
    }
    delete cur;
    return true;
  }
  else//左右都不为空,去找它左树最大的节点替换它的值,再删除左树最大的节点
        //下面的图有做说明
  {
    node* parent = nullptr;
    node* leftMax = cur;
    while (leftMax->_right)//找到左树最大的节点
    {
      parent = leftMax;
      leftMax = leftMax->_right;
    }
    swap(cur->_key, leftMax->_key);//交换值
    if (parent->_left == leftMax)
    {
      parent->_left = leftMax->_left;
    }
    else
    {
      parent->_right = leftMax->_left;
    }
    delete leftMax;
    return true;
  }
  return false;
}

三、搜索二叉树的完整代码实现

#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{
  BSTreeNode* _left;
  BSTreeNode* _right;
  K _key;
  BSTreeNode(const K& key)
    :_left(nullptr)
    ,_right(nullptr)
    ,_key(key)
  {}
};
template <class K>
class BSTree
{
private:
  BSTreeNode<K>* _root;
  typedef BSTreeNode<K> node;
public:
  BSTree()
    :_root(nullptr)
  {
  }
  ~BSTree()
  {
    Destroy(_root);
  }
  //增删查
  bool Insert(const K& key);
  bool Find(const K& key);
  bool Erase(const K& key);
  //中序遍历
  void InOrder();
  void _InOrder(node* root);
  //增删查的递归实现
  bool InsertR(const K& key);
  bool _InsertR(const K& key, node*& root);
  //为了对节点进行修改,这里的插入和删除的节点必须用引用传,这里是一个细节 
  bool EraseR(const K& key);
  bool _EraseR(const K& key, node*& root);
  bool FindR(const K& key);
  bool _FindR(const K& key, node* root);
  void Destroy(node* root);
};
template <class K>
bool BSTree<K>::Insert(const K& key)
{
  //树为空,则直接新增节点,赋值给root指针
  if (_root == nullptr)
  {
    _root = new node(key);
    return true;
  }
  node* parent = nullptr;
  node* cur = _root;
  while (cur)//找到key该去的位置
  {
    parent = cur;
    if (cur->_key < key)//大就往右走
    {
      cur = cur->_right;
    }
    else if (cur->_key > key)//小就往左走
    {
      cur = cur->_left;
    }
    else//有相等的值了无法再插入了
    {
      return false;
    }
  }
  if (parent->_key < key)
  {
    parent->_right = new node(key);
  }
  else
  {
    parent->_left = new node(key);
  }
  return true;
}
template <class K>
bool BSTree<K>::Find(const K& key)
{
  node* cur = _root;
  while (cur)
  {
    if (key < cur->_key)//小就往左走
    {
      cur = cur->_left;
    }
    else if (key > cur->_key)//大就往右走
    {
      cur = cur->_right;
    }
    else//找到了
    {
      return true;
    }
  }
  return false;
}
template <class K>
bool BSTree<K>::Erase(const K& key)
{
  node* parent = nullptr;
  node* cur = _root;
  while (cur)
  {
    
    if (cur->_key > key)
    {
      parent = cur;
      cur = cur->_left;
    }
    else if (cur->_key < key)
    {
      parent = cur;
      cur = cur->_right;
    }
    else//找到了就跳出循环
    {
      break;
    }
  }
  if (cur == nullptr)//cur走到空就意味着没找到
  {
    return false;
  }
  if (cur->_left == nullptr)//左为空 
  {
    if (cur == _root)
    {
      _root = cur->_right;
    }
    else if (cur == parent->_left)
    {
      parent->_left = cur->_right;
    }
    else if (cur == parent->_right)
    {
      parent->_right = cur->_right;
    }
    delete cur;
    return true;
  }
  else if (cur->_right == nullptr)//右为空
  {
    if (cur == _root)
    {
      _root = cur->_left;
    }
    else if (cur == parent->_left)
    {
      parent->_left = cur->_left;
    }
    else if (cur == parent->_right)
    {
      parent->_right = cur->_left;
    }
    delete cur;
    return true;
  }
  else//左右都不为空,去找它左树最大的节点替换它的值,再删除左树最大的节点
  {
    node* parent = nullptr;
    node* leftMax = cur;
    while (leftMax->_right)//找到左树最大的节点
    {
      parent = leftMax;
      leftMax = leftMax->_right;
    }
    swap(cur->_key, leftMax->_key);//交换值
    if (parent->_left == leftMax)
    {
      parent->_left = leftMax->_left;
    }
    else
    {
      parent->_right = leftMax->_left;
    }
    delete leftMax;
    return true;
  }
  return false;
}
template <class K>
void BSTree<K>::_InOrder(node* root)
{
  if (root == nullptr)
    return;
  _InOrder(root->_left);
  cout << root->_key << " ";
  _InOrder(root->_right);
}
template <class K>
void BSTree<K>::InOrder()
{
  _InOrder(_root);
  cout << endl;
}
template <class K>
bool BSTree<K>::EraseR(const K& key)
{
  return _EraseR(key, _root);
}
template <class K>
bool BSTree<K>::_EraseR(const K& key, node*& root)
{
  if (root == nullptr)
    return false;
  if (root->_key < key)
  {
    _EraseR(key, root->_right);
  }
  else if (root->_key > key)
  {
    _EraseR(key, root->_left);
  }
  else//找到要删除的节点了
  {
    //准备开始删除
    node* del = root;
    if (root->_left == nullptr)
    {
      root = root->_right;
    }
    else if (root->_right == nullptr)
    {
      root = root->_left;
    }
    else
    {
      node* leftMax = root->_left;
      while (leftMax->_right)
      {
        leftMax = leftMax->_right;
      }
      swap(root->_key, leftMax->_key);
      return _EraseR(key, root->_left);//交换完后去要删除节点的左子树删除最大的节点
    }
    delete del;
  }
  return true;
}
template <class K>
bool BSTree<K>::FindR(const K& key)
{
  return _FindR(key, _root);
}
template <class K>
bool BSTree<K>::_FindR(const K& key, node* root)
{
  if (root == nullptr)
  {
    return false;
  }
  if (root->_key < key)
  {
    return _FindR(key, root->_right);
  }
  else if (root->_key > key)
  {
    return _FindR(key, root->_left);
  }
  else
  {
    return true;
  }
}
template <class K>
bool BSTree<K>::InsertR(const K& key)
{
  return _InsertR(key, _root);
}
template <class K>
bool BSTree<K>::_InsertR(const K& key, node*& root)
{
  if (root == nullptr)
  {
    root = new node(key);
    return true;
  }
  if (root->_key < key)
  {
    return _InsertR(key, root->_right);
  }
  else if (root->_key > key)
  {
    return _InsertR(key, root->_left);
  }
  else
  {
    return false;
  }
}
template <class K>
void BSTree<K>::Destroy(node* root)
{
  if (root == nullptr)
    return;
  Destroy(root->_left);
  Destroy(root->_right);
  delete root;
}
//test.c
#include "BinarySearchTree.h"
int main()
{
  BSTree<int> bs;
  int arr[] = { 1,3,6,4,7,8,10,14,13 };
  for (auto e : arr)
  {
    bs.Insert(e);
  }
  bs.InOrder();
  bs.EraseR(1);
  bs.InOrder();
  bs.Insert(20);
  bs.InsertR(9);
  bs.InOrder();
  bool ret = bs.FindR(20);
  cout << ret << endl;
  return 0;
}
相关文章
|
6月前
二叉树的几个递归问题
二叉树的几个递归问题
25 0
|
4月前
|
存储 C++
二叉搜索树详解以及C++实现二叉搜索树(递归和非递归)
二叉搜索树详解以及C++实现二叉搜索树(递归和非递归)
47 0
|
11月前
|
存储
非递归方式实现二叉树的前、中、后序遍历
非递归方式实现二叉树的前、中、后序遍历
|
11月前
|
存储 算法
二叉树的前序/中序/后序遍历—采用递归与迭代两种方法实现嗷
二叉树的前序/中序/后序遍历—采用递归与迭代两种方法实现嗷
|
iOS开发
二叉树非递归前中后遍历
因为个人身体原因,本周都在医院住院治疗身体,身边没有电脑,只能分享一些这周看过的比较好的书籍内容。iPad上传csdn图片顺序会有误,看书的页码就好。
二叉树非递归前中后遍历
|
数据采集 算法
数据结构与算法—二叉树的层序、前序中序后序(递归、非递归)遍历
层序遍历。听名字也知道是按层遍历。我们知道一个节点有左右节点。而每一层一层的遍历都和左右节点有着很大的关系。也就是我们选用的数据结构不能一股脑的往一个方向钻,而左右应该均衡考虑。这样我们就选用队列来实现。
159 0
数据结构与算法—二叉树的层序、前序中序后序(递归、非递归)遍历
|
算法 搜索推荐
从二叉树的前中后序遍历,我们来说递归和快速排序
从二叉树的前中后序遍历,我们来说递归和快速排序
从二叉树的前中后序遍历,我们来说递归和快速排序
|
机器学习/深度学习 编译器
590. N 叉树的后序遍历 :「递归」&「非递归」&「通用非递归」
590. N 叉树的后序遍历 :「递归」&「非递归」&「通用非递归」
|
机器学习/深度学习
1305. 两棵二叉搜索树中的所有元素 : BST 的中序遍历与归并排序运用题
1305. 两棵二叉搜索树中的所有元素 : BST 的中序遍历与归并排序运用题
|
机器学习/深度学习 编译器
589. N 叉树的前序遍历 :「递归」&「非递归」&「通用非递归」
589. N 叉树的前序遍历 :「递归」&「非递归」&「通用非递归」