• map和set模拟实现


    本期我们来对map和set进行模拟实现,此处需要红黑树基础,没有看过红黑树的小伙伴建议先去看看红黑树,如果没了解过map和set的小伙伴也建议先去看一看,博客链接我都放在这里了

    C++红黑树_KLZUQ的博客-CSDN博客

    C++-map和set_KLZUQ的博客-CSDN博客 

    目录

    源码剖析

    代码实现

    迭代器

    全部代码


    源码剖析

    我们先来看看源码

    这是set.h的头文件,其中stl_tree里实现的就是红黑树,里面还有set和multiset,我们先来看set

    我们正常情况会认为,map和set的实现是两棵树,一棵树kv结构,一棵是k结构,但其实不是的,map和set使用的是一棵树

    这里的代码进行了一些裁减,当然裁减的是一些无关紧要的东西,我们来看重点

    我们可以看到上面的rb_tree是一个kv结构

    但是我们从typedef来看,无论是key还是value,他们其实都是Key,下面我们再看看map

    map也是kv结构,这里的key是Key,但是value是一个pair ,我们再看看树是怎么实现的

    我们可以看到,树的成员里有一个header,是link_type,而它的本质其实就是node* ,而树的节点存的是Value

    但是这个value就是真的value吗?不是的,对于map而言,这里的value是pair,对于set而言,这里的value是Key,真正决定树里面存什么的是第二个模板参数传的是什么,我们继续看

    这里先是有一个基类base,里面就是红黑树的正常结构,color,parent,left和right

    然后用了一个子类去继承,这里才是node

    Value是value_field,rb_tree到底是k结构还是kv结构,谁也不知道,这里是搞了一个泛型

    另外,这里的node也不是必须用继承,只是库里面喜欢这样写而已,一会我们实现时可以不用继承

    我们可以体会到,库的设计是非常强的,只用了一棵红黑树就解决了所有问题,只取决于传的第二个模板参数,这里的value到底是key还是pair都可以由我们选择

    另外这里可能会有人提出一个疑问,我们可以不传第一个模板参数Key吗?答案是不行的,因为map和set只是封装而已,核心部分的接口是调用树里面的,而树里面会调用find和erase等等,他们都是需要Key来适配的,我们再想想,map和set用的也并不是同一棵树,而是同一个类模板,同一个类模板用不同的模板参数实现出不同的类,大家要仔细想想

    代码实现

    我们先把之前写的红黑树拿过来(红黑树源码可以去本期博客开头部分的链接里去找)

    1. template<class T>
    2. struct RBTreeNode
    3. {
    4. RBTreeNode* _left;
    5. RBTreeNode* _right;
    6. RBTreeNode* _parent;
    7. T _data;
    8. Colour _col;
    9. RBTreeNode(const T& data)
    10. :_left(nullptr)
    11. , _right(nullptr)
    12. , _parent(nullptr)
    13. , _data(data)
    14. ,_col(RED)
    15. {}
    16. };
    17. template<class K, class T>
    18. struct RBTree
    19. {
    20. typedef RBTreeNode Node;
    21. public:
    22. bool Insert(const T& data)

    并且我们需要修改一下代码,这里我们把V改为了T,并且去掉了pair改为data

    1. //MySet.h
    2. #include"RBTree.h"
    3. namespace bai
    4. {
    5. template<class K>
    6. class set
    7. {
    8. private:
    9. RBTree_t;
    10. };
    11. }
    1. //MyMap.h
    2. #include"RBTree.h"
    3. namespace bai
    4. {
    5. template<class K,class V>
    6. class map
    7. {
    8. private:
    9. RBTree>_t;
    10. };
    11. }

    然后我们写一写框架

    此时的调用关系就是这样的 

    下面我们还要继续修改红黑树里的代码,红黑树里有很多比较大小的语句,对于set没什么,但对于map,我们传的是pair,我们希望用first来比较,所以下面我们要进行多处修改,需要使用仿函数来进行控制

    这个仿函数在库里面也有,意思是把value里的key取出来

    1. namespace bai
    2. {
    3. template<class K>
    4. class set
    5. {
    6. struct SetKeyOfT
    7. {
    8. const K& operator()(const K& key)
    9. {
    10. return key;
    11. }
    12. };
    13. private:
    14. RBTree_t;
    15. };
    16. }

    对于set,我们返回key即可

    1. namespace bai
    2. {
    3. template<class K,class V>
    4. class map
    5. {
    6. struct MapKeyOfT
    7. {
    8. const K& operator()(const pair& kv)
    9. {
    10. return kv.first;
    11. }
    12. };
    13. private:
    14. RBTree, MapKeyOfT>_t;
    15. };
    16. }

    对于map,我们取出pair的first返回

    1. template<class K, class T,class KeyOfT>
    2. struct RBTree
    3. {
    4. typedef RBTreeNode Node;
    5. public:
    6. Node* Find(const K& key)
    7. {
    8. }
    9. bool Insert(const T& data)
    10. {
    11. if (_root == nullptr)
    12. {
    13. _root = new Node(data);
    14. _root->_col = BLACK;
    15. return true;
    16. }
    17. Node* cur = _root;
    18. Node* parent = nullptr;
    19. KeyOfT kot;
    20. while (cur)
    21. {
    22. if (kot(cur->_data) < kot(data))
    23. {
    24. parent = cur;
    25. cur = cur->_right;
    26. }
    27. else if (kot(cur->_data) > kot(data))
    28. {
    29. parent = cur;
    30. cur = cur->_left;
    31. }
    32. else
    33. {
    34. return false;
    35. }
    36. }
    37. cur = new Node(data);
    38. cur->_col = RED;
    39. if (kot(parent->_data) < kot(data))
    40. {
    41. parent->_right = cur;
    42. }
    43. else
    44. {
    45. parent->_left = cur;
    46. }
    47. cur->_parent = parent;

    接着就是修改insert的部分代码,我们可以看到,比较大小时我们都使用的是kot,大家想想,如果不使用仿函数的话,我们该如何比较大小呢?对于set可以直接比较,但是map就不行了(其实这里map的pair也可以直接比较,库里面实现了,但是库里面的比较方法并不是我们需要的比较大小,所以这里需要我们自己写一下)

    我们简单画一下调用关系就是这样 ,这里的比较并不是使用kot比较,而是kot会把T对象的值拿来进行比较,比如map,就会把pair中的first返回

    我们看到库里面除了kot,还有一个compare,这个compare是用来比较T的大小的,也就是说,库用了一个仿函数来取T对象里的值,又用另一个仿函数比较T的大小 

    其实这个kot完全是为了map设计的,因为map的data比较不符合我们的需求,是一个pair,所以需要仿函数的帮助

    大家仔细看,KeyOfT是在树这一层的,在map和set这一层是没有keyoft的

    1. Node* Find(const K& key)
    2. {
    3. Node* cur = _root;
    4. KeyOfT kot;
    5. while (cur)
    6. {
    7. if (kot(cur->_data) < key)
    8. {
    9. cur = cur->_right;
    10. }
    11. else if(kot(cur->_data) > key)
    12. {
    13. cur = cur->_left;
    14. }
    15. else
    16. {
    17. return cur;
    18. }
    19. }
    20. return nullptr;
    21. }

    我们还要给红黑树写一个find

    然后在set和map里再写一层insert,并且加上public 

    我们简单测试一下,没有问题

    迭代器

    接下来我们来实现迭代器

    这是stl库里set的迭代器,是rep_type 

    而它的本质就是rb_tree 

    另外我们还发现,无论是迭代器还是const迭代器,它其实都是const_iterator

    我们继续追溯源头,这是stl_tree.h里的,它的迭代器是这样的 

    这是它的定义,这里和节点那里一样,都是写了一个基类base,然后继承 

    这是base的结构 ,里面有一个节点的指针node

    然后operator*返回里面的value_field,这个value_field对于set而言就是key,对于map而言就是pair,当然这些其实都不是重点

     重点是++和--,我们实现列表等等++和--其实没啥,但是这里是一棵树,它++怎么到下一个节点呢?

    我们写代码一般是这样写的,begin是其实位置,而这棵树是二叉搜索树,所以应该是最左节点,也就是最小的值 ,我们看看库里面是不是也是这样的

    库里面返回的是一个leftmost

    库里面返回的是一个header->left,和我们要实现的有一些不一样,一会我们会讲解一下库里面是什么情况,下面我们来看++怎么走

    这里我们需要不借助栈来完成中序的非递归

    假设it在这个地方,++要找中序的下一个,也就是10,如果右树不为空,我们要访问右树的最左节点,对于所有节点,我们都可以这样做

    我们再看右为空的情况, 我们需要访问它的祖先(注意,这里不一定是父亲),如果it是父亲的左,那我们访问父亲,如果it是父亲的右(也就是it在7的位置时),说明it访问完后父亲也完了,我们需要去祖先里父亲是左的那一个,也就是8的位置

    总结一下:右不为空,访问右树最左节点,右为空,访问孩子是父亲左的那个祖先

    1. template<class T>
    2. struct __TreeIterator
    3. {
    4. typedef RBTreeNode Node;
    5. typedef __TreeIterator Self;
    6. Node* _node;
    7. __TreeIterator(Node* node)
    8. :_node(node)
    9. {}
    10. T& operator*()
    11. {
    12. return _node->_data;
    13. }
    14. T* operator->()
    15. {
    16. return &_node->_data;
    17. }
    18. bool operator!=(const Self& s)
    19. {
    20. return _node != s._node;
    21. }
    22. Self& operator++()
    23. {
    24. }
    25. };

    我们先把框架写好

    1. Self& operator++()
    2. {
    3. if (_node->_right)
    4. {
    5. //右树最左节点
    6. Node* subLeft = _node->_right;
    7. while (subLeft->_left)
    8. {
    9. subLeft = subLeft->_left;
    10. }
    11. _node = subLeft;
    12. }
    13. else
    14. {
    15. Node* cur = _node;
    16. Node* parent = cur->_parent;
    17. //找孩子是父亲左的祖先节点,即下一个要访问的节点
    18. while (parent && cur == parent->_right)
    19. {
    20. cur = cur->_parent;
    21. parent = parent->_parent;
    22. }
    23. _node = parent;
    24. }
    25. return *this;
    26. }

    接着我们来实现++,if里边的逻辑很好理解,就是右树不为空,else里就是右树为空,需要找孩子是父亲左的那个祖先,最后返回*this即可,这里建议画图理解

    接着我们还要在树里面实现一下

     我们还要在set里写一下,但是此时是不能运行的,因为类模板没有被实例化时是没有生成具体代码的,里面可能有一些语法问题等等,编译器在这里是不敢去类模板里找这个iterator的,iterator是属于RBTree这个类域的,找出来还设计没有实例化的具体参数,比如这里的K,这个K具体是int还是char,是不知道的,所以编译器在这里是认不出来的,而且,编译器在类里面去取,取到的可能是一个内嵌类型(一种是typedef,一种是内部类),也可能是静态成员变量,那iterator到底是内嵌类型还是静态成员变量,编译器也不知道

    所以我们需要在这里加一个typename,告诉编译器等类模板实例化了再去找

    这时候我们的迭代器就能跑起来了,是不是很有趣?

    我们再把map的也补上

    和set不一样的是这里出错了 

    我们实现的operator*返回的是data,对于set而言data是key,但是对于map而言,是一个pair

    pair是不支持流插入的

    所以这里我们可以使用->,另外大家还记得吗?这里是两个->,编译器优化了一个,这也是我们之前讲过的知识

    此时我们还可以使用auto和范围for

    虽然上面我们实现了这么多,但是还是有很多大坑的

    比如我们的set是允许修改的,这可出现问题了,所以,任重道远啊

    还记得我们上面说了库里面的无论iterator和const_iterator都是const吗?下面我们就要按照库的方法走

    另外,map不能和set用一样的方法,对于map,key不允许修改,但是value是允许的

    所以map的迭代器是正常的 

    也就是说,对于map来说,我们要不允许first,而允许second ,而且对于first这一行要在编译时就报错

     库里面是这样做的,把key设为了const,下面我们来解决这些问题

    我们给迭代器和树加上两个模板参数,如果是普通迭代器,我们传T*,T&,const就传const版本 

    再修改修改代码

    1. typedef typename RBTree::const_iterator iterator;
    2. typedef typename RBTree::const_iterator const_iterator;
    3. iterator begin()
    4. {
    5. return _t.begin();
    6. }
    7. iterator end()
    8. {
    9. return _t.end();
    10. }
    11. const_iterator begin() const
    12. {
    13. return _t.begin();
    14. }
    15. const_iterator end() const
    16. {
    17. return _t.end();
    18. }

    接着我们在set里写出const版本,并且我们把const和普通迭代器都改为const,和库里面是一样的

    我们再看看库里面的,const版本普通迭代器,和我们的还是有点不一样的

    此时我们运行,这里报错了 

    这里的原因是

    t是一个普通对象

    就会调用普通的begin,返回一个普通迭代器,这里就存在一个转换

    大家要知道,这两个迭代器是同一个类模板,传不同的参数, 实例化出不同的类型 

    首先我们要提供const版本的begin和end

     

    我们再次看看库里面的,这是stl_set.h 里的

    我们和库里面改成一样的,把我们的const版本先屏蔽掉 ,结果成功了

    我们来看,如果我们不加const,t就是普通的t,只能调用普通的begin,返回的是普通的iterator,这里的iterator我们看起来是iterator,其实不是的

    它是我们typedef出来的const_iterator 

    它的本质是这样的,也就是说我们只提供这个就行

    那为什么我们还要写普通的iterator呢?

    因为我们使用的时候写的是普通的,这里set的问题就暂时解决了,下面我们来看map的

    这里我们模仿库里面的写法,在k前加上const

    另外别忘了修改成员里的

    此时就可以只修改value,而key不能修改

    我们还要提供一下const版本的,普通的迭代器key不可以修改,value可以,const迭代器是都不可以修改

    比如这里,使用了const迭代器就都不可以修改了

    我们再把operator==实现一下,然后给这些能加const的加上const,下面我们实现一下operator--

    --就是反过来,++走的是中序,--就是右子树,根,左子树的顺序

    1. Self& operator--()
    2. {
    3. if (_node->_left)
    4. {
    5. //找左树最右节点
    6. Node* subRight = _node->_left;
    7. while (subRight->_right)
    8. {
    9. subRight = subRight->_right;
    10. }
    11. _node = subRight;
    12. }
    13. else
    14. {
    15. //孩子是父亲右的那个节点
    16. Node* cur = _node;
    17. Node* parent = cur->_parent;
    18. while (parent && cur == parent->_left)
    19. {
    20. cur = cur->_parent;
    21. parent = parent->_parent;
    22. }
    23. _node = parent;
    24. }
    25. return *this;
    26. }

    逻辑和++反一下即可,下面我们来看看库里面的结构

     库和我们不同的是它增加了一个哨兵位的头节点,并且让它的左指向最左节点,右指向最右节点

    这样的好处是可以快速找到最小节点和最大节点

    所以库里面的是leftmost和rightmost 

    而它的end就直接是header,而我们的end是空,库里面的begin相对而言更高效一点,不够这是要付出代价的,比如在最左边插入一个节点,header的left就需要修改,另外,这里的header的parent是指向根的,然后root的parent指向header,删除,旋转等等都是需要维护header的

    而且还要单独判断一下这个特殊情况,不然会死循环,这里cur等于parent的右,就会无限循环

    我们看库里面的,这些我们了解即可

    下面我们再实现一下operator[ ]

     operator[ ] 的实现需要insert,我们看看库里面的insert,first是迭代器,second是bool

    所以我们需要把树里面的insert改一下

     

    修改返回值和返回类型

     

    接着修改map和set的insert

    然后我们编译,就出错了 ,set的insert是编不过的

    这里的t是普通对象,调用insert,返回普通迭代器,也就是pair里的迭代器是普通迭代器

    但是这里的迭代器是const_iterator

    是这个样子,我们来看看库里面是怎么解决的

    这是stl_set库,它用了pair的first去构造了一个

     

     结合起来看一下

    再看我们的,大家先想想,这里选中的iterator是const还是普通的 ?
    是const,而后面的ret.first是普通迭代器,这里是不能用make_pair的一个原因,make_pair是自己推

    这里的本质是调用了pair的构造函数

    是这样子的,所以这里的本质是用普通迭代器构造const迭代器,我们以前实现的迭代器都是不支持的

    库里面支持这样玩的原因是因为有这样一个函数 ,我们看最后一行,按理来说迭代器是不需要写拷贝构造的,但是这里并不是纯的拷贝构造,这里没有用self,大家仔细看self和iterator的区别

    self就是这个迭代器,但iterator并不一定是

    再结合这里来看

     当这个类被实例化成const迭代器时,这个函数是一个构造函数,支持普通迭代器构造const迭代器

     

    普通迭代器不受传的Ptr和Ref影响, const迭代器传const Ref和const Ptr时,普通迭代器还是value&和value*,始终是一个普通迭代器,这个函数就相当于一个普通的构造函数,它的参数是普通迭代器,用来构造const迭代器(链表那里也是这样做的)

    当这个类被实例化为普通迭代器时,这个函数就是一个拷贝构造,普通迭代器构造普通迭代器,就是一个拷贝构造

    所以我们也需要加上构造

     我们上面那么费时费力的原因就是因为这个东西,大家要想清楚

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

    此时我们终于可以完成operator[ ] 了,这里先调insert,然后调用make_pair,first是key,value是V的缺省值,如果没有,会先插入,如果有了就不插入,ret是pair,pair.first是一个迭代器,然后用->取second

    我们简单测试一下,就和库里面差不多了

    全部代码

    1. //RBTree.h
    2. #include
    3. using namespace std;
    4. enum Colour
    5. {
    6. RED,
    7. BLACK
    8. };
    9. template<class T>
    10. struct RBTreeNode
    11. {
    12. RBTreeNode* _left;
    13. RBTreeNode* _right;
    14. RBTreeNode* _parent;
    15. T _data;
    16. Colour _col;
    17. RBTreeNode(const T& data)
    18. :_left(nullptr)
    19. , _right(nullptr)
    20. , _parent(nullptr)
    21. , _data(data)
    22. ,_col(RED)
    23. {}
    24. };
    25. template<class T,class Ptr,class Ref>
    26. struct __TreeIterator
    27. {
    28. typedef RBTreeNode Node;
    29. typedef __TreeIterator Self;
    30. typedef __TreeIterator Iterator;
    31. __TreeIterator(const Iterator& it)
    32. :_node(it._node)
    33. {}
    34. Node* _node;
    35. __TreeIterator(Node* node)
    36. :_node(node)
    37. {}
    38. Ref operator*()
    39. {
    40. return _node->_data;
    41. }
    42. Ptr operator->()
    43. {
    44. return &_node->_data;
    45. }
    46. bool operator!=(const Self& s) const
    47. {
    48. return _node != s._node;
    49. }
    50. bool operator==(const Self& s) const
    51. {
    52. return _node == s._node;
    53. }
    54. Self& operator--()
    55. {
    56. if (_node->_left)
    57. {
    58. //找左树最右节点
    59. Node* subRight = _node->_left;
    60. while (subRight->_right)
    61. {
    62. subRight = subRight->_right;
    63. }
    64. _node = subRight;
    65. }
    66. else
    67. {
    68. //孩子是父亲右的那个节点
    69. Node* cur = _node;
    70. Node* parent = cur->_parent;
    71. while (parent && cur == parent->_left)
    72. {
    73. cur = cur->_parent;
    74. parent = parent->_parent;
    75. }
    76. _node = parent;
    77. }
    78. return *this;
    79. }
    80. Self& operator++()
    81. {
    82. if (_node->_right)
    83. {
    84. //右树最左节点
    85. Node* subLeft = _node->_right;
    86. while (subLeft->_left)
    87. {
    88. subLeft = subLeft->_left;
    89. }
    90. _node = subLeft;
    91. }
    92. else
    93. {
    94. Node* cur = _node;
    95. Node* parent = cur->_parent;
    96. //找孩子是父亲左的祖先节点,即下一个要访问的节点
    97. while (parent && cur == parent->_right)
    98. {
    99. cur = cur->_parent;
    100. parent = parent->_parent;
    101. }
    102. _node = parent;
    103. }
    104. return *this;
    105. }
    106. };
    107. template<class K, class T,class KeyOfT>
    108. struct RBTree
    109. {
    110. typedef RBTreeNode Node;
    111. public:
    112. typedef __TreeIterator iterator;
    113. typedef __TreeIteratorconst T*,const T&> const_iterator;
    114. iterator begin()
    115. {
    116. Node* leftMin = _root;
    117. while (leftMin && leftMin->_left)//前面加条件是防止空树
    118. {
    119. leftMin = leftMin->_left;
    120. }
    121. return iterator(leftMin);
    122. }
    123. iterator end()
    124. {
    125. return iterator(nullptr);
    126. }
    127. const_iterator begin() const
    128. {
    129. Node* leftMin = _root;
    130. while (leftMin && leftMin->_left)//前面加条件是防止空树
    131. {
    132. leftMin = leftMin->_left;
    133. }
    134. return const_iterator(leftMin);
    135. }
    136. const_iterator end() const
    137. {
    138. return const_iterator(nullptr);
    139. }
    140. Node* Find(const K& key)
    141. {
    142. Node* cur = _root;
    143. KeyOfT kot;
    144. while (cur)
    145. {
    146. if (kot(cur->_data) < key)
    147. {
    148. cur = cur->_right;
    149. }
    150. else if(kot(cur->_data) > key)
    151. {
    152. cur = cur->_left;
    153. }
    154. else
    155. {
    156. return cur;
    157. }
    158. }
    159. return nullptr;
    160. }
    161. pairbool> Insert(const T& data)
    162. {
    163. if (_root == nullptr)
    164. {
    165. _root = new Node(data);
    166. _root->_col = BLACK;
    167. return make_pair(iterator(_root),true);
    168. }
    169. Node* cur = _root;
    170. Node* parent = nullptr;
    171. KeyOfT kot;
    172. while (cur)
    173. {
    174. if (kot(cur->_data) < kot(data))
    175. {
    176. parent = cur;
    177. cur = cur->_right;
    178. }
    179. else if (kot(cur->_data) > kot(data))
    180. {
    181. parent = cur;
    182. cur = cur->_left;
    183. }
    184. else
    185. {
    186. return make_pair(iterator(cur), false);
    187. }
    188. }
    189. cur = new Node(data);
    190. cur->_col = RED;
    191. Node* newnode = cur;
    192. if (kot(parent->_data) < kot(data))
    193. {
    194. parent->_right = cur;
    195. }
    196. else
    197. {
    198. parent->_left = cur;
    199. }
    200. cur->_parent = parent;
    201. while (parent && parent->_col == RED)
    202. {
    203. Node* grandfather = parent->_parent;
    204. if (parent == grandfather->_left)//parent在grandfather的左边
    205. {
    206. Node* uncle = grandfather->_right;
    207. if (uncle && uncle->_col == RED)//叔叔存在且为红
    208. {
    209. //变色
    210. uncle->_col = BLACK;
    211. parent->_col = BLACK;
    212. grandfather->_col = RED;
    213. //继续向上处理
    214. cur = grandfather;
    215. parent = cur->_parent;
    216. }
    217. else//叔叔不存在/存在且为黑
    218. {
    219. if (cur == parent->_left)
    220. {
    221. RotateR(grandfather);
    222. parent->_col = BLACK;
    223. grandfather->_col = RED;
    224. }
    225. else
    226. {
    227. RotateL(parent);
    228. RotateR(grandfather);
    229. cur->_col = BLACK;
    230. grandfather->_col = RED;
    231. }
    232. break;
    233. }
    234. }
    235. else//parent在grandfather的右边
    236. {
    237. Node* uncle = grandfather->_left;
    238. if (uncle && uncle->_col == RED)//叔叔存在且为红
    239. {
    240. uncle->_col = BLACK;
    241. parent->_col = BLACK;
    242. grandfather->_col = RED;
    243. cur = grandfather;
    244. parent = cur->_parent;
    245. }
    246. else//叔叔不存在/存在且为黑
    247. {
    248. if (cur == parent->_right)
    249. {
    250. RotateL(grandfather);
    251. parent->_col = BLACK;
    252. grandfather->_col = RED;
    253. }
    254. else
    255. {
    256. RotateR(parent);
    257. RotateL(grandfather);
    258. cur->_col = BLACK;
    259. grandfather->_col = RED;
    260. }
    261. break;
    262. }
    263. }
    264. }
    265. _root->_col = BLACK;
    266. return make_pair(iterator(newnode), true);
    267. }
    268. void RotateL(Node* parent)//左单旋
    269. {
    270. Node* cur = parent->_right;
    271. Node* curleft = cur->_left;
    272. parent->_right = curleft;
    273. if (curleft)
    274. {
    275. curleft->_parent = parent;
    276. }
    277. cur->_left = parent;
    278. Node* ppnode = parent->_parent;
    279. parent->_parent = cur;
    280. if (parent == _root)//parent是根节点
    281. {
    282. _root = cur;
    283. cur->_parent = nullptr;
    284. }
    285. else
    286. {
    287. if (ppnode->_left == parent)
    288. {
    289. ppnode->_left = cur;
    290. }
    291. else
    292. {
    293. ppnode->_right = cur;
    294. }
    295. cur->_parent = ppnode;
    296. }
    297. }
    298. void RotateR(Node* parent)//右单旋
    299. {
    300. Node* cur = parent->_left;
    301. Node* curright = cur->_right;
    302. parent->_left = curright;
    303. if (curright)
    304. {
    305. curright->_parent = parent;
    306. }
    307. Node* ppnode = parent->_parent;
    308. cur->_right = parent;
    309. parent->_parent = cur;
    310. if (ppnode == nullptr)
    311. {
    312. _root = cur;
    313. cur->_parent = nullptr;
    314. }
    315. else
    316. {
    317. if (ppnode->_left == parent)
    318. {
    319. ppnode->_left = cur;
    320. }
    321. else
    322. {
    323. ppnode->_right = cur;
    324. }
    325. cur->_parent = ppnode;
    326. }
    327. }
    328. bool IsBalance()
    329. {
    330. return IsBalance(_root);
    331. }
    332. bool CheckColour(Node* root,int blacknum,int benchmark)//检查节点颜色
    333. {
    334. if (root == nullptr)
    335. {
    336. if (benchmark != blacknum)//黑色节点数量不对
    337. return false;
    338. return true;
    339. }
    340. if (root->_col == BLACK)//检测黑色节点数量
    341. {
    342. ++blacknum;
    343. }
    344. if (root->_col == RED && root->_parent && root->_parent->_col == RED)
    345. {
    346. cout << root->_kv.first << "连续红节点" << endl;
    347. return false;
    348. }
    349. return CheckColour(root->_left,blacknum, benchmark)
    350. && CheckColour(root->_right, blacknum, benchmark);
    351. }
    352. bool IsBalance(Node* root)
    353. {
    354. if (root == nullptr)
    355. return true;
    356. if (root->_col != BLACK)
    357. return false;
    358. int benchmark = 0;//黑色节点基准值
    359. Node* cur = _root;
    360. while (cur)
    361. {
    362. if (cur->_col==BLACK)
    363. ++benchmark;
    364. cur = cur->_left;
    365. }
    366. return CheckColour(root,0, benchmark);
    367. }
    368. private:
    369. Node* _root = nullptr;
    370. };
    1. //MySet.h
    2. #include"RBTree.h"
    3. namespace bai
    4. {
    5. template<class K>
    6. class set
    7. {
    8. struct SetKeyOfT
    9. {
    10. const K& operator()(const K& key)
    11. {
    12. return key;
    13. }
    14. };
    15. public:
    16. typedef typename RBTree::const_iterator iterator;
    17. typedef typename RBTree::const_iterator const_iterator;
    18. const_iterator begin() const
    19. {
    20. return _t.begin();
    21. }
    22. const_iterator end() const
    23. {
    24. return _t.end();
    25. }
    26. /*const_iterator begin() const
    27. {
    28. return _t.begin();
    29. }
    30. const_iterator end() const
    31. {
    32. return _t.end();
    33. }*/
    34. pairbool> insert(const K& key)
    35. {
    36. pair::iterator, bool> ret = _t.Insert(key);
    37. return pairbool>(ret.first,ret.second);
    38. }
    39. private:
    40. RBTree_t;
    41. };
    42. }
    1. //MyMap.h
    2. #include"RBTree.h"
    3. namespace bai
    4. {
    5. template<class K,class V>
    6. class map
    7. {
    8. struct MapKeyOfT
    9. {
    10. const K& operator()(const pair& kv)
    11. {
    12. return kv.first;
    13. }
    14. };
    15. public:
    16. typedef typename RBTreeconst K,V>, MapKeyOfT>::iterator iterator;
    17. typedef typename RBTreeconst K, V>, MapKeyOfT>::const_iterator const_iterator;
    18. iterator begin()
    19. {
    20. return _t.begin();
    21. }
    22. iterator end()
    23. {
    24. return _t.end();
    25. }
    26. const_iterator begin() const
    27. {
    28. return _t.begin();
    29. }
    30. const_iterator end() const
    31. {
    32. return _t.end();
    33. }
    34. V& operator[](const K& key)
    35. {
    36. pairbool> ret = insert(make_pair(key, V()));
    37. return ret.first->second;
    38. }
    39. pairbool> insert(const pair& kv)
    40. {
    41. return _t.Insert(kv);
    42. }
    43. private:
    44. RBTreeconst K,V>, MapKeyOfT>_t;
    45. };
    46. }

    以上即为本期全部内容,希望大家可以有所收获

    如有错误,还请指正

  • 相关阅读:
    电脑重装系统后Win11安全中心无法打开如何解决
    最常用的四大Mac磁盘空间清理方法,这些内存占比是最大的
    VoLTE基础自学系列 | VoLTE呼叫流程之VoLTE打VoLTE,主被叫接入域为LTE
    狂神说多线程学习笔记
    Docker下安装oracle环境(以oracle_11g环境为例)
    当下互联网行业趋势,你顶得住吗?
    【力扣-数据结构和算法-头哨兵】移除链表元素
    TFMath Caculator:一个简单的Java AWT计算器
    BI 如何让SaaS产品具有 “安全感”和“敏锐感”(上)
    [UE][C++]Assimp库安装编译,UE_Assimp插件安装使用,各种三维格式转换
  • 原文地址:https://blog.csdn.net/KLZUQ/article/details/133198101