• C++:map和set容器


    "我们都无可奈何地选择了,自己的人生。也无可奈何地出演自己拿到的剧本"


    (1) set;

    ①set是什么?

    set是一种管理数据的容器,其底层是由红黑树来实现的。

     

    ②set的性质:

    1.set是按照一定序列存储的容器;

    2.set中的元素(value)是唯一的;

    3.......

     

    与set相对的就是multiset

    很显然,这个容器可以存放相同的数.


     

    (2)map;

    ①map介绍:

    map也是一种关联式容器。和set不同的地方是,map会多一个修饰key的参数value

    在map中,这两个值 会被封装到一个pair中,本质上pair 就是一个结构体

     

    ②map的性质:

    1.和set一样 底层用红黑树实现

    2.只能存一个key值。但可以存同一value

    3.map支持[]访问

     

    使用map的时候,需要注意的是 他底层去重载的[].

     [],返回的是pair中value的值 , 并可以对其进行修改。

    与map相对的也有mutltimap:

     


    (3)map/set的底层封装:

    重新搭建BRTree框架;

    我们在实现红黑树的时候,对于 节点存储的模板为K,V。

    怎么能让底层,去同时封装 不同存储类型的容器?!

    1. //template
    2. template<class T>
    3. struct RBTreeNode
    4. {
    5. RBTreeNode* _left;
    6. RBTreeNode* _right;
    7. RBTreeNode* _parent;
    8. T _data;
    9. Colour _col;
    10. RBTreeNode(const T& data)
    11. :_left(nullptr),
    12. _right(nullptr),
    13. _parent(nullptr),
    14. _data(data),
    15. _col(RED)
    16. {}
    17. };

    所以我么你相应对 红黑树的节点 再次泛化。因为它并不知道存储的是什么。

    1. template<class K,class T,class KeyOFT>
    2. struct RBTree
    3. {
    4. typedef RBTreeNode Node;
    5. RBTree()
    6. :_root(nullptr)
    7. {}
    8. Node* _root;
    9. }

    我们不妨给红黑树的模板增加一个参数。让T 去决定 节点存什么!

    既然T 是未知的,不同的T有不同的比较方法

    KeyOFT----->就去弥补 实现不同T数据 的比较。(实现的仿函数)

     


     

    set/map框架:4

    1. template<class K,class T>
    2. class map
    3. {
    4. public:
    5. struct MapOFT
    6. {
    7. const K& operator()(const pair& kv)
    8. {
    9. return kv.first;
    10. }
    11. };
    12. private:
    13. RBTreeconst K, V>, MapOFT> _m;
    14. };
    15. template<class K>
    16. class set
    17. {
    18. public:
    19. struct SetOFT
    20. {
    21. K& operator()(const K& key)
    22. {
    23. return key;
    24. }
    25. };
    26. private:
    27. RBTree _s;
    28. };

    三者关系整理成图就成了这样。 这种设计极为巧妙。

    BRtree迭代器封装; 

    1. template<class T,class Ref,class Ptr> //这里的迭代器封装和 list 极为相似 所谓的红黑树迭代器 就是指的 红黑树的节点
    2. struct _RBTree_iterator
    3. {
    4. typedef RBTreeNode Node;
    5. typedef _RBTree_iterator Self;
    6. _RBTree_iterator(Node* node)
    7. :_node(node)
    8. {}
    9. Node* _node;
    10. //opertor*
    11. Ref operator*()
    12. {
    13. return _node->_data;
    14. }
    15. Ptr operator->()
    16. {
    17. return &_node->_data;
    18. }
    19. bool operator!=(const Self& s)
    20. {
    21. return _node != s._node;
    22. }
    23. bool operator==(const Self& s)
    24. {
    25. return _node == s._node;
    26. }
    27. //难点;
    28. //set/map走的是一个 中序
    29. Self& operator++()
    30. {
    31. //此时_node 一定是最左节点
    32. if (_node->_right)
    33. {
    34. //此时如果不为空
    35. //证明右边还需要访问;
    36. Node* left = _node->_right;
    37. while (left->_left)
    38. {
    39. left = left->_left;
    40. }
    41. //此时找到 不为空的 右边的 第一个左边给 _node
    42. _node = left;
    43. }
    44. else
    45. {
    46. //由node出发
    47. //找到 右不为空的 父节点
    48. Node* cur = _node;
    49. Node* parent = cur->_parent;
    50. while (parent && cur == parent->_right)
    51. {
    52. cur = cur->_parent;
    53. parent = parent->_parent;
    54. }
    55. //下一次进来 就是去访问 _node 右根
    56. _node = parent;
    57. }
    58. return *this;
    59. }
    60. //右子树 根 左子树
    61. Self& operator--()
    62. {
    63. if (_node->_left)
    64. {
    65. Node* right = _node->_left;
    66. while (right->_right)
    67. {
    68. right = right->_right;
    69. }
    70. _node = right;
    71. }
    72. else
    73. {
    74. Node* cur = _node;
    75. Node* parent = cur->_parent;
    76. while (parent && cur == parent->_left)
    77. {
    78. cur = parent;
    79. parent = parent->_parent;
    80. }
    81. _node = parent;
    82. }
    83. return *this;
    84. }
    85. };

    operator++; 

     

     operator--;

     

     

    RBTree封装迭代器+set/map使用:
     

    1. template
    2. class map
    3. {
    4. public:
    5. struct MapOFT
    6. {
    7. const K& operator()(const pair& kv)
    8. {
    9. return kv.first;
    10. }
    11. };
    12. //去红黑树 里找到 被封装好的 迭代器
    13. //此时要添加typename 因为迭代器实例化要在后面才进行
    14. // 这里要让编译器 这是个类
    15. typedef typename RBTree, MapOFT>:: iterator iterator;
    16. iterator begin()
    17. {
    18. return _m.begin();
    19. }
    20. iterator end()
    21. {
    22. return _m.end();
    23. }
    24. pair insert(const pair& kv)
    25. {
    26. return _m.insert(kv);
    27. }
    28. private:
    29. RBTree, MapOFT> _m;
    30. };
    31. template
    32. class set
    33. {
    34. public:
    35. struct SetOFT
    36. {
    37. const K& operator()(const K& key)
    38. {
    39. return key;
    40. }
    41. };
    42. typedef typename RBTree ::iterator iterator;
    43. iterator begin()
    44. {
    45. return _s.begin();
    46. }
    47. iterator end()
    48. {
    49. return _s.end();
    50. }
    51. pair insert(const K& key)
    52. {
    53. return _s.insert(key);
    54. }
    55. private:
    56. RBTree _s;
    57. };

    封装完成,我们就先拿来用一用;

     

     map/set大致的玩法 行得通。

    1. V& operator[](const K& key)
    2. {
    3. pairbool> ret = insert(make_pair(key,V()));
    4. return (ret.first)->second;
    5. }

    当然不能忘了map 重载的[];


     

    (4)反向迭代器:

    这里的反向迭代器,并非来自迭代器萃取。而是由正向迭代器构造出来的。

    1. template<class Iterator>
    2. struct _RBTree_Reverse_iterator
    3. {
    4. //这里只设置了一个 模板参数
    5. //因为 反向迭代器 可以借用正向迭代器的 其他两个模板参数
    6. //同样这是 内置类型的模板 需要typename
    7. typedef typename Iterator::reference Ref;
    8. typedef typename Iterator::pointer Ptr;
    9. typedef _RBTree_Reverse_iterator Self;
    10. Iterator _it;
    11. };

     

    1. template<class Iterator>
    2. struct _RBTree_Reverse_iterator
    3. {
    4. //这里只设置了一个 模板参数
    5. //因为 反向迭代器 可以借用正向迭代器的 其他两个模板参数
    6. //同样这是 内置类型的模板 需要typename
    7. typedef typename Iterator::reference Ref;
    8. typedef typename Iterator::pointer Ptr;
    9. typedef _RBTree_Reverse_iterator Self;
    10. Iterator _it;
    11. //拿正向 迭代器初始化
    12. _RBTree_Reverse_iterator(Iterator it)
    13. :_it(it)
    14. {}
    15. //operator*
    16. Ref& operator*()
    17. {
    18. return *_it;
    19. }
    20. Self& operator++()
    21. {
    22. --_it;
    23. return *this;
    24. }
    25. Self& operator--()
    26. {
    27. ++_it;
    28. return *this;
    29. }
    30. bool operator!=(const Self& s) const
    31. {
    32. return _it != s._it;
    33. }
    34. bool operator==(const Self& s) const
    35. {
    36. return _it == s._it;
    37. }
    38. Ptr operator->()
    39. {
    40. return _it.operator->();
    41. }
    42. };

     

     


    本篇也就到此为止。

    感谢你的阅读

    祝你好运~

  • 相关阅读:
    RocketMQ 消息存储机制分析
    Python中利用SQLAlchemy模块操作MySQL数据库
    TCP/IP四层模型对比OSI七层网络模型的区别是啥?数据传输过程原来是这样的
    浏览器网页上如何播放dash视频、hls(m3u8)视频和flv格式视频?
    项目管理——评审中的误区
    qt creator 设置 项目依赖关系
    [附源码]计算机毕业设计JAVA超市收银系统论文
    JS 算法专辑【4】链表
    VTK Filter-Modeling模块讲解
    通过 DevOps、CI/CD 和容器增强您的软件开发之旅...
  • 原文地址:https://blog.csdn.net/RNGWGzZs/article/details/126023813