二叉搜索树

简介: 二叉搜索树

二叉搜索树


概念


二叉搜索树又称二叉排序树,性质如下


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


95523b576682a32b3ed69e717ab5bd60_5ba84c4fde1e42fb8734b22de8fb64a6.png


节点的结构体


template<class T>
struct BSTreenode
{
    //指向左子树
  BSTreenode<T>* _left;
  //指向右子树
  BSTreenode<T>* _right;
  T _key;
    //初始化节点
  BSTreenode(const T& key)
  :_left(nullptr)
  , _right(nullptr)
  , _key(key)
  {
  }
};


操作


caab62f8e9c54201a7d04db91b6c8452_56b1b26d7c8b4e0188e2aeb7f3f4ed48.png


int a[]={15,6,18,3,7,17,20,2,4,13};


插入


非递归


树为空:直接增加新的节点,赋值给根节点

树不为空:先将待插入的数值与根节点的值进行比较,若大于根节点的值,向右子树进行比较;若小于根节点的值,向左子树进行比较;若相等,则返回错误;设计一个父节点用于保存上一个节点的信息,直到节点为空停止

创建一个新节点,保存待插入的数值;如果待插入的数值比父节点的值大,则与右子树连接;如果待插入的数值比父节点的值小,则与左子树连接

bool insert(const T& key)
  {
  if (_root == nullptr)
  {
    _root = new node(key);
    return true;
  }
  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
    {
    return false;
    }
  }
  cur = new node(key);
  if (parent->_key < key)
  {
    parent->_right = cur;
  }
  else
  {
    parent->_left = cur;
  }
  return true;
  }


递归


59452deebfe1f7b81c094f9739f118e4_79043394e92c49b4b486f68773510e15.png


bool _insertr(node*& root, const T& key)
  {
  if (root == nullptr)
  {
    root = new node(key);
    return true;
  }
  if (root->_key < key)
  {
    return _insertr(root->_right, key);
  }
  else if (root->_key > key)
  {
    return _insertr(root->_left, key);
  }
  else
    return false;
  }


这里需要注意的是:bool _insertr(node*& root, const T& key) 递归函数中,根节点的参数类型是引用,也就是说,将待插入节点与父节点连接时,此时的父节点也是前面节点的左节点(或右节点)的引用;例如将12插入,此时节点值为13的节点不仅是12的父节点同时还是节点值为7的节点的左节点的引用;此方法便可很好地完成连接


查找


从根节点的值开始比较,如果带查找的数字比根节点的值大,则向右子树查找;比根节点的值小,向左子树查找

最多查找树的高度次,若没找到则不存在

代码实现如下


非递归


bool find(const T& 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;
  }


递归


bool _findr(node* root, const T& key)
  {
  if (root == nullptr)
  {
    return false;
  }
  if (root->_key < key)
  {
    return _findr(root->_right, key);
  }
  else if (root->_key > key)
  {
    return _findr(root->_left, key);
  }
  else
    return true;
  }


删除


查找元素是否存在于二叉搜索树中,不存在返回错误,存在先查找所在节点的位置

待删除节点的种类存在三种可能:左子树为空(包括左右子树都为空),右子树为空,左右子树都不为空,具体情况具体分析

左子树为空:

如果待删除的节点是父节点的左子树,则将节点的右节点与父节点的左子树连接;如果待删除的节点是父节点的右子树,则将节点的右节点与父节点的右子树连接


91ab4a8f117472f69435c472fc18197e_82d038b3ee3348a58b112f9f5c3245aa.png


右子树为空与左子树类似


左右子树都不为空:

在右子树中寻找大于待删除节点值的节点,且是最小的那个;操作:在右子树中,从根节点开始一直向左寻找节点,直到某节点的左子树为空,则找到该节点;将该节点代替待删除的节点,具体操作与上面一直


3bb33651220c4fa1ce78046701fb33d8_6036abeaa4294c54b9d3a45214f7af1e.png


非递归


bool erase(const T& 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
    {
    //1.左为空
    if (cur->_left == nullptr)
    {
        //只存在根节点
        //parent=nullptr
      if (cur == _root)
      {
      _root = cur->_right;
      }
      else
      {
      if (parent->_left == cur)
      {
        parent->_left = cur->_right;
      }
      else
      {
        parent->_right = cur->_right;
      }
      }
      delete cur;
    }//2.右为空
    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;
    }//3.左右都不为空
    else
    {
      node* parent = cur;
      node* minright = cur->_right;
      while (minright->_left)
      {
      parent = minright;
      minright = minright->_left;
      }
      cur->_key = minright->_key;
      if (minright == parent->_left)
      {
      parent->_left = minright->_right;
      }
      else
      {
      parent->_right = minright->_right;
      }
      delete minright;
    }
    }
  }
  return false;
  }


递归


bool _eraser(node* root, const T& key)
  {
  if (root == nullptr)
  {
    return false;
  }
  if (root->_key < key)
  {
    return _eraser(root->_right, key);
  }
  else if (root->_key > key)
  {
    return _eraser(root->_left, key);
  }
  else
  {
    node* del = root;
    //1.右为空
    if (root->_right == nullptr)
    {
    root = root->_left;
    }
    else if (root->_left = nullptr)
    {
    root = root->_right;
    }
    else
    {
    node* minright = root->_right;
    while (minright->_left)
    {
      minright = minright->_left;
    }
    swap(root->_key, minright->_key);
    return _erasser(root->_right, key);
    }
    delete del;
    return true;
  }
  }


实现


这里只实现上面没有提到的功能函数


template<class T>
struct BSTreenode
{
  BSTreenode<T>* _left;
  BSTreenode<T>* _right;
  T _key;
  BSTreenode(const T& key)
  :_left(nullptr)
  , _right(nullptr)
  , _key(key)
  {
  }
};
template<class T>
class BSTree
{
  typedef BSTreenode<T> node;
public:
  BSTree()
  :_root(nullptr)
  {
  }
  BSTree(const BSTree<T>& t)
  {
  _root = Copy(t._root);
  }
  BSTree<T>& operator=(BSTree<T> t)
  {
  swap(_root, t._root);
  return *this;
  }
  ~BSTree()
  {
  Destory(_root);
  _root = nullptr;
  }
  void Inorder()
  {
  _Inorderr(_root);
  cout << endl;
  }
private:
  void _Inorderr(node* root)
  {
  if (root == nullptr)
  {
    return;
  }
  _Inorderr(root->_left);
  cout << root->_key << " ";
  _Inorderr(root->_right);
  }
  void Destory(node* root)
  {
  if (root == nullptr)
  {
    return;
  }
  Destory(root->_left);
  Destory(root->_right);
  delete root;
  }
  node* copy(node* root)
  {
  if (root == nullptr)
  {
    return nullptr;
  }
  node* newroot = new node(root->_key);
  newroot->_left = copy(root->_left);
  newroot->_right = copy(root->_right);
  return newroot;
  }
  }
private:
  node* _root = nullptr;
};


应用


K模型


K模型只有 key作为关键码,结构体中只存储了key,key作为需要搜索的值

例如:给定一个英文单词,判断该单词是否拼写正确

将词库中每个单词作为key,构建一棵二叉搜索树,在二叉搜索树中搜索该单词是否存在。若存在则拼写正确;若不存在,则拼写错误


KV模型


每个关键码key,都有与之对应的Value,<key,value> 键值对

对应的关系

英文词典中英文与中文就是KV模型,通过英文可以找到对应的中文,英文单词与其对应的中文<word,chinese>构成键值对


实例如下


KV实例


template<class K,class V>
struct BSTreeNode
{
  BSTreeNode<K, V>* _left; 
  BSTreeNode<K, V>* _right;
  K _key;
  V _value;
  BSTreeNode(const K& key, const V& value)
  :_key(key)
  ,_value(value)
  ,_left(nullptr)
  ,_right(nullptr)
  {
  }
};
template<class K,class V>
class BSTree
{
  typedef BSTreeNode<K, V> Node;
public:
  bool insert(const K& key, const V& value)
  {
  if (_root == nullptr)
  {
    _root = new Node(key, value);
    return true;
  }
  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
    {
    return false;
    }
  }
  cur = new Node(key, value);
  if (parent->_key < key)
  {
    parent->_right = cur;
  }
  else
  {
    parent->_left = cur;
  }
  return true;
  }
  Node* 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 cur;
    }
  }
  return nullptr;
  }
  void Inorder()
  {
  _Inorderr(_root);
  }
  void _Inorderr(Node* root)
  {
  if (root == nullptr)
  {
    return;
  }
  _Inorder(root->_left);
  cout << root->_key << " " << root->_value << endl;
  _Inorder(root->_right);
  }
private:
  Node* _root = nullptr;
};


测试


void testBSTree2()
{
  BSTree<string, string>dict;
  dict.insert("east", "东");
  dict.insert("west", "西");
  dict.insert("south", "南");
  dict.insert("north", "北");
  string str;
  while (cin >> str)
  {
  BSTreeNode<string, string>* ret = dict.Find(str);
  if (ret)
  {
    cout << ret->_value << endl;
  }
  else
  {
    cout << "查无此单词" << endl;
  }
  }
}


f2399ac43de208a06fe2e30741eda89b_87bb3f78ca9a40dbaa56bd5db7539f97.png


目录
相关文章
|
1天前
二叉搜索树
二叉搜索树
11 2
|
5月前
|
存储 安全 C++
C++【二叉搜索树】
C++【二叉搜索树】
41 0
|
7月前
51 # 二叉搜索树的实现
51 # 二叉搜索树的实现
18 0
|
8月前
|
算法 JavaScript 前端开发
|
8月前
|
存储 算法
|
9月前
|
编译器 C语言 C++
【C++】二叉搜索树
【C++】二叉搜索树
40 0
|
9月前
|
存储
【二叉搜索树】
【二叉搜索树】
34 0
|
10月前
|
存储 算法 关系型数据库
有了二叉树,平衡二叉树为什么还需要红黑树
有了二叉树,平衡二叉树为什么还需要红黑树
66 0
有了二叉树,平衡二叉树为什么还需要红黑树
|
11月前
|
算法
二叉搜索树、平衡二叉树
一、二叉搜索树 这里我们不用太多书面化的语言来定义,笔者认为在讨论数据结构、算法相关的内容时用太多书面化、学术化的语言是一种让人很烦的事情。咬文嚼字,不便于读者理解。 简单来说二叉树搜索树,其实就是用来做二分查找的一种二叉树。 特点是:根节点的左子树值均小于根节点的值,根节点的右子树值均大于根节点的值。 比如123 4 567建树的结果就是
38 0
|
12月前
|
C++
【C++】二叉搜索树(下)
【C++】二叉搜索树
39 0