【C++从0到王者】第二十八站:二叉搜索树的应用

简介: 【C++从0到王者】第二十八站:二叉搜索树的应用


前言

二叉搜索树的在现实世界的应用很广泛,比如Key模型,Key-Value模型就是常见的两种的模型

一、Key模型

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。即就是判断key在不在就可以了。

比如:门禁系统,小区车辆出入系统等等

给一个单词word,判断该单词是否拼写正确,具体方式如下:

以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树

在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

我们前面文章中所完成的二叉搜索树就是key模型的二叉搜身树

二、Key/Value模型

Key/Value每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:比如商场的车辆出入系统(计时付费),高铁实名制车票系统等

比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;

再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对

现在就让我们来实现一个key-value模型的二叉搜索树。

#pragma once
template<class K, class V>
struct BSTreeNode
{
  BSTreeNode(const K& key = K(), const V& val = V())
    :_key(key)
    ,_val(val)
    ,_left(nullptr)
    ,_right(nullptr)
  {}
  K _key;
  V _val;
  BSTreeNode<K,V>* _left;
  BSTreeNode<K,V>* _right;
};
template<class K, class V>
class BSTree
{
  typedef BSTreeNode<K,V> Node;
public:
  BSTree()
    :_root(nullptr)
  {}
  BSTree(const BSTree<K,V>& t)
  {
    _root = Copy(t._root);
  }
  ~BSTree()
  {
    _Destory(_root);
  }
  BSTree<K,V>& operator=(BSTree<K,V> t)
  {
    std::swap(_root, t._root);
    return *this;
  }
  bool Insert(const K& key,const V& val)
  {
    if (_root == nullptr)
    {
      _root = new Node(key,val);
      return true;
    }
    else
    {
      Node* parent = _root;
      Node* cur = _root;
      while (cur != nullptr)
      {
        if (cur->_key == key)
        {
          return false;
        }
        else if (cur->_key > key)
        {
          parent = cur;
          cur = cur->_left;
        }
        else
        {
          parent = cur;
          cur = cur->_right;
        }
      }
      cur = new Node(key,val);
      if (parent->_key > key)
      {
        parent->_left = cur;
      }
      else if (parent->_key < key)
      {
        parent->_right = cur;
      }
      return true;
    }
  }
  void InOrder()
  {
    _InOrder(_root);
  }
  Node* Find(const K& key)
  {
    Node* cur = _root;
    while (cur)
    {
      if (cur->_key == key)
      {
        return cur;
      }
      else if (cur->_key > key)
      {
        cur = cur->_left;
      }
      else if (cur->_key < key)
      {
        cur = cur->_right;
      }
    }
    return nullptr;
  }
  bool Erase1(const K& key)
  {
    Node* cur = _root;
    Node* parent = nullptr;
    while (cur)
    {
      if (cur->_key > key)
      {
        parent = cur;
        cur = cur->_left;
      }
      else if (cur->_key < key)
      {
        parent = cur;
        cur = cur->_right;
      }
      else
      {
        if (parent == nullptr)
        {
          if (cur->_left == nullptr)
          {
            _root = cur->_right;
            delete cur;
            return true;
          }
          else if (cur->_right == nullptr)
          {
            _root = cur->_left;
            delete cur;
            return true;
          }
          else
          {
            Node* leftMaxParent = cur;
            Node* leftMax = cur->_left;
            if (leftMax->_right == nullptr)
            {
              leftMax->_right = cur->_right;
              delete cur;
              _root = leftMax;
              return true;
            }
            while (leftMax->_right)
            {
              leftMaxParent = leftMax;
              leftMax = leftMax->_right;
            }
            std::swap(leftMax->_key, cur->_key);
            std::swap(leftMax->_val, cur->_val);
            leftMaxParent->_right = leftMax->_left;
            delete leftMax;
            leftMax = nullptr;
            return true;
          }
        }
        if (parent->_left == cur)
        {
          if (cur->_left == nullptr)
          {
            parent->_left = cur->_right;
            delete cur;
            return true;
          }
          else if (cur->_right == nullptr)
          {
            parent->_left = cur->_left;
            delete cur;
            return true;
          }
          else 
          {
            Node* leftMaxParent = cur;
            Node* leftMax = cur->_left;
            if (leftMax->_right == nullptr)
            {
              leftMax->_right = cur->_right;
              delete cur;
              parent->_left = leftMax;
              return true;
            }
            while (leftMax->_right)
            {
              leftMaxParent = leftMax;
              leftMax = leftMax->_right;
            }
            std::swap(leftMax->_key, cur->_key);
            std::swap(leftMax->_val, cur->_val);
            leftMaxParent->_right = leftMax->_left;
            delete leftMax;
            leftMax = nullptr;
            return true;
          }
        }
        else
        {
          if (cur->_left == nullptr)
          {
            parent->_right = cur->_right;
            delete cur;
            return true;
          }
          else if (cur->_right == nullptr)
          {
            parent->_right = cur->_left;
            delete cur;
            return true;
          }
          else
          {
            Node* leftMaxParent = cur;
            Node* leftMax = cur->_left;
            if (leftMax->_right == nullptr)
            {
              leftMax->_right = cur->_right;
              delete cur;
              parent->_right = leftMax;
              return true;
            }
            while (leftMax->_right)
            {
              leftMaxParent = leftMax;
              leftMax = leftMax->_right;
            }
            std::swap(leftMax->_key, cur->_key);
            std::swap(leftMax->_val, cur->_val);
            leftMaxParent->_right = leftMax->_left;
            delete leftMax;
            leftMax = nullptr;
            return true;
          }
        }
      }
    }
    return false;
  }
  bool Erase2(const K& key)
  {
    Node* cur = _root;
    Node* parent = nullptr;
    while (cur)
    {
      if (cur->_key > key)
      {
        parent = cur;
        cur = cur->_left;
      }
      else if (cur->_key < key)
      {
        parent = cur;
        cur = cur->_right;
      }
      else
      {
        if (cur->_left == nullptr)
        {
          if (parent == nullptr)
          {
            _root = cur->_right;
          }
          else if (parent->_left == cur)
          {
            parent->_left = cur->_right;
          }
          else if (parent->_right == cur)
          {
            parent->_right = cur->_right;
          }
        }
        else if (cur->_right == nullptr)
        {
          if (parent == nullptr)
          {
            _root = cur->_left;
          }
          else if (parent->_left == cur)
          {
            parent->_left = cur->_left;
          }
          else if (parent->_right = cur)
          {
            parent->_right = cur->_left;
          }
        }
        else
        {
          Node* leftMax = cur->_left;
          Node* leftMaxParent = cur;
          while (leftMax->_right)
          {
            leftMaxParent = leftMax;
            leftMax = leftMax->_right;
          }
          std::swap(cur->_key, leftMax->_key);
          std::swap(cur->_val, leftMax->_val);
          if (leftMaxParent->_left == leftMax)
          {
            leftMaxParent->_left = leftMax->_left;
          }
          else
          {
            leftMaxParent->_right = leftMax->_left;
          }
          cur = leftMax;
        }
        delete cur;
        return true;
      }
    }
  }
  Node* FindR(const K& key)
  {
    return _FindR(_root, key);
  }
  bool InsertR(const K& key,const V& val)
  {
    return _InsertR(_root, key, val);
  }
  bool EraseR(const K& key)
  {
    return _EraseR(_root, key);
  }
private:
  Node* Copy(Node* root)
  {
    if (root == nullptr)
    {
      return nullptr;
    }
    Node* Copyroot = new Node(root->_key, root->val);
    Copyroot->_left = Copy(root->_left);
    Copyroot->_right = Copy(root->_right);
    return Copyroot;
  }
  void _Destory(Node*& root)
  {
    if (root == nullptr)
    {
      return;
    }
    _Destory(root->_left);
    _Destory(root->_right);
    delete root;
    root == nullptr;
  }
  bool _EraseR(Node*& root, const K& 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;
      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;
        }
        std::swap(leftMax->_key, root->_key);
        std::swap(leftMax->_val, root->_val);
        return _EraseR(root->_left, key);
      }
      delete del;
      return true;
    }
  }
  bool _InsertR(Node*& root, const K& key, const V& val)
  {
    if (root == nullptr)
    {
      root = new Node(key, val);
      return true;
    }
    if (root->_key < key)
    {
      return _InsertR(root->_right, key, val);
    }
    else if (root->_key > key)
    {
      return _InsertR(root->_left, key, val);
    }
    else
    {
      return false;
    }
  }
  Node* _FindR(Node* root, const K& key)
  {
    if (root == nullptr)
    {
      return nullptr;
    }
    if (root->_key == key)
    {
      return root;
    }
    else if (root->_key > key)
    {
      return _FindR(root->_left, key);
    }
    else
    {
      return  _FindR(root->_right, key);
    }
  }
  void _InOrder(Node* root)
  {
    if (root == nullptr)
    {
      return;
    }
    _InOrder(root->_left);
    cout << root->_key << " :" << root->_val << endl;
    _InOrder(root->_right);
  }
private:
  Node* _root;
};

如上就是我们的KV模型的二叉搜索树。我们可以使用如下的两个模型,就是我们的这棵树的应用

void test1()
{
  BSTree<string, string> dic;
  dic.Insert("review", "复习");
  dic.Insert("product", "产品,产物");
  dic.Insert("education", "教育");
  dic.Insert("interfere", "干涉");
  cout << "请输入单词" << endl;
  string str;
  while (cin >> str)
  {
    BSTreeNode<string, string>* ret = dic.Find(str);
    if (ret)
    {
      cout << ret->_val << endl;
    }
    else
    {
      cout << "无此单词" << endl;
      cout << "请你添加单词的意思:" << endl;
      string str_val;
      cin >> str_val;
      dic.Insert(str, str_val);
    }
    cout << "请输入单词" << endl;
  }
}

如上就是一个查找单词的模型,可以帮我们快速找出单词的意思,如果没有,可以自行添加意思

如下所示是一个水果计数的应用

void test2()
{
  string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
  BSTree<string, int> FruitCount;
  for (auto& e : arr)
  {
    BSTreeNode<string, int>* ret = FruitCount.Find(e);
    if (ret == nullptr)
    {
      FruitCount.Insert(e, 1);
    }
    else
    {
      ret->_val++;
    }
  }
  FruitCount.InOrder();
}


总结

本节主要讨论了二叉搜索树的两种应用。希望能对大家带来帮助

相关文章
|
21天前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
1月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
53 2
|
2月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
22 3
|
3月前
|
存储 算法 C++
C++ STL应用宝典:高效处理数据的艺术与实战技巧大揭秘!
【8月更文挑战第22天】C++ STL(标准模板库)是一组高效的数据结构与算法集合,极大提升编程效率与代码可读性。它包括容器、迭代器、算法等组件。例如,统计文本中单词频率可用`std::map`和`std::ifstream`实现;对数据排序及找极值则可通过`std::vector`结合`std::sort`、`std::min/max_element`完成;而快速查找字符串则适合使用`std::set`配合其内置的`find`方法。这些示例展示了STL的强大功能,有助于编写简洁高效的代码。
50 2
|
3月前
|
存储 搜索推荐 Serverless
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
36 1
|
3月前
|
存储 编译器 C++
C++多态实现的原理:深入探索与实战应用
【8月更文挑战第21天】在C++的浩瀚宇宙中,多态性(Polymorphism)无疑是一颗璀璨的星辰,它赋予了程序高度的灵活性和可扩展性。多态允许我们通过基类指针或引用来调用派生类的成员函数,而具体调用哪个函数则取决于指针或引用所指向的对象的实际类型。本文将深入探讨C++多态实现的原理,并结合工作学习中的实际案例,分享其技术干货。
74 0
|
3月前
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
|
4月前
|
存储 C++
【C++】二叉树进阶之二叉搜索树(下)
【C++】二叉树进阶之二叉搜索树(下)
32 4
|
4月前
|
Java 编译器 C++
【C++】二叉树进阶之二叉搜索树(上)
【C++】二叉树进阶之二叉搜索树(上)
36 3
|
4月前
|
算法 测试技术 C++
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
35 2