C++红黑树模拟实现map和set(1)

简介: C++红黑树模拟实现map和set(1)

零、前言


本章是继红黑树的介绍和实现后,讲解使用红黑树来封装实现map和set

一、红黑树及其节点的设计


对于底层都是红黑树的map和set来说,他们之间存在的最大的区别就是:对于set是K模型的容器,而map是KV模型的容器。为了更好的灵活兼容实现map和set,就需要在红黑树以及树节点上进行特别的设计


1、树节点的设计


对于红黑树的节点我们需要节点对于set来说储存key,对于map来说储存key-value键值对,所以这里我们就直接让节点类型的阈值类型为T,用来控制储存类型


实现代码:


template<class T>
struct RBTreeNode
{
  RBTreeNode<T>* _left;
  RBTreeNode<T>* _right;
  RBTreeNode<T>* _parent;
  T _data;//T可以是key也可以是pair<K,V>
  Colour _col;
  RBTreeNode(const T& data)
    :_left(nullptr)
    , _right(nullptr)
    , _parent(nullptr)
    , _data(data)
    , _col(RED)
  {}
};


  • 解释:

对于set实现我们传入key,对于map实现我们传入pair<key,value>,由此满足set和map各自的需求


2、红黑树的设计


想要兼容map和set,我们依旧需要红黑树的模板有两个类型来控制和满足上层对下层的需求


  • 实现代码:


template<class K, class T>
class RBTree
{
    typedef RBTreeNode<T> Node;
public:
  //.......
private:
  Node* _root;
};


注:这里的Node我们不想让外部直接获取使用,我们typedef在private域中


解释:

为了兼容set和map,对于第一个参数我们是用来比较的key类型,第二个参数是用来储存数据的类型


这里我们对红黑树第二个模板参数进行灵活传参,可能是键值key,也可能是pair<key,value>


对于set传入底层红黑树的模板参数就是key和key;对于map传入底层红黑树的模板参数就是key和pair<key,value>


注:对于set来说第二个参数有点多余,但是对于map来说,因为map的接口当中有些是只要求给出键值key用来比较的(如find()和erase()),如果只有一个参数传入pair<key,value>类型,但是只能得到第一个key类型的值,无法获得key的类型(不能实现模板函数)


3、取值仿函数的使用


我们在设计树节点之后达到了对于不同容器存入不同类型的效果,但是真实在实现时在插入或者删除时,我们需要要拿出节点中储存类型的数据进行比较


分析:

对于set的T本身就是键值key,直接用T进行比较即可,但是对于map的储存类型是pair<Key, Value>我们需要取出pair的first(key值)进行比较


这两种的都是取值比较,但是需要的行为是不一样的,由此我们还需要一个仿函数用来灵活取值比较


对于不同容器我们需要不同的仿函数类型,由此在红黑树的模板列表中还需要一个模板类型参数,灵活控制传入的仿函数类型


注:仿函数,就是使一个类的使用看上去像一个函数,其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了


红黑树框架:


template<class K, class T, class KeyOfT>
class RBTree
{
    typedef RBTreeNode<T> Node;
public:
  //...
private:
  Node* _root;
};


  • map实现框架:


namespace cole
{
  template<class K, class V>
  class map
  {
    struct MapOfKey
    {
      const K& operator()(const pair<K, V>& kv)
      {
        return kv.first;
      }
    };
  public:
    //...
  private:
    RBTree<K, pair<const K, V>, MapOfKey> _t;
  };
}


  • set实现框架:


namespace cole
{
  template<class K>
  class set
  {
    struct SetOfKey
    {
      const K& operator()(const K& key)
      {
        return key;
      }
    };
  public:
    //...
  private:
    RBTree<K, K, SetOfKey> _t;
  };
}


  • 仿函数使用示例:


Node* Find(const K& key)
{
    KeyOfT kot;
    Node* cur = _root;
    while (cur)
    {
        if (kot(cur->_kv.first) > key)
        {
            cur = cur->_left;
        }
        else if (kot(cur->_kv.first) < key)
        {
            cur = cur->_right;
        }
        else
        {
            return cur;
        }
    }
    return nullptr;
}
相关文章
|
3天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
16 3
|
3天前
|
存储 搜索推荐 C++
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
|
23天前
|
存储 JavaScript 前端开发
set和map的区别
set和map的区别
31 4
|
30天前
|
存储 C++
【C++练级之路】【Lv.16】红黑树(冰与火的碰撞,红与黑的史诗)
【C++练级之路】【Lv.16】红黑树(冰与火的碰撞,红与黑的史诗)
|
1月前
|
存储 算法 C语言
【C++入门到精通】C++入门 —— map & multimap (STL)
之前我们学习了C++的基础和一些概念,现在将探讨重要的STL组件——map与multimap。map是关联容器,提供有序键值对存储,基于红黑树,支持高效查找、插入和删除。每个键唯一对应一个值。multimap则允许键的重复。两者都提供迭代器支持,但map的键是唯一的,而multimap允许键重复,插入和查找效率不同。更多详情,请查阅官方文档。祝学习愉快!
12 0
|
1月前
|
存储 算法 C++
【C++ map结构 】std::map 和 std::unordered_map 在使用上的差异
【C++ map结构 】std::map 和 std::unordered_map 在使用上的差异
22 0
|
1月前
|
存储 编译器 容器
用红黑树封装实现map和set
用红黑树封装实现map和set
14 0
|
4天前
|
存储 编译器 C语言
c++的学习之路:5、类和对象(1)
c++的学习之路:5、类和对象(1)
19 0
|
4天前
|
C++
c++的学习之路:7、类和对象(3)
c++的学习之路:7、类和对象(3)
19 0
|
3天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计