• 【C++】-- STL之用红黑树模拟实现map和set


    目录

    一、map和set类模板​​​​​​

    二、红黑树节点定义

    1.红黑树的节点修改 

    2.仿函数 

    (1)节点比较大小时存在的问题 

    (2)仿函数

    (3)修改红黑树定义

    (4)修改红黑树插入

    (5)修改红黑树查找

    三、红黑树迭代器

    1.红黑树中迭代器重命名

    2.正向迭代器定义

    3.迭代器构造 

    4.正向迭代器重载* 

    5.正向迭代器重载-> 

    6.正向迭代器重载==

    7.正向迭代器重载!=

    8.正向迭代器++

    9.正向迭代器--

    10.红黑树中实现迭代器

    四、set模拟实现

    五、map模拟实现

    六、红黑树完整代码段


    一、map和set类模板​​​​​​

    【C++】-- STL之map和set详解一文中提到,set用value标识元素(value就是key,类型为T),并且每个value必须唯一 。

    template < class Key>//set

    在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:

    typedef pair<const Key, T> value_type;
    template < class Key, class T>//map

     用红黑树同时封装出set和map时,set传给value的是一个value,map传给value的是一个pair,set和map传给红黑树的value决定了这棵树里面存的节点值类型。上层容器不同,底层红黑树的Key和T也不同。

     ​​​​​​

    在上层容器set中,K和T都代表Key,底层红黑树节点当中存储K和T都是一样的;map中,K代表键值Key,T代表由Key和Value构成的键值对,底层红黑树中只能存储T。所以红黑树为了满足同时支持set和map,节点当中存储T。

    这就要对红黑树进行改动。

    二、红黑树节点定义

    1.红黑树的节点修改 

    【C++】-- 红黑树详解的红黑树节点定义由类模板

    template<class K,class V>

    修改为

    template<class T>

     那么节点定义就修改为

    1. //红黑树节点定义
    2. template<class T>
    3. struct RBTreeNode
    4. {
    5. RBTreeNode* _left;//节点的左孩子
    6. RBTreeNode* _right;//节点的右孩子
    7. RBTreeNode* _parent;//节点的父亲
    8. T _data;//节点的值,_data里面存的是K就传K,存的是pair就传pair
    9. Colour _col;//节点颜色
    10. RBTreeNode(const T& x)
    11. :_left(nullptr)
    12. , _right(nullptr)
    13. , _parent(nullptr)
    14. , _data(x)
    15. , _col(RED)
    16. {}
    17. };

    由于红黑树不知道上层传的是K还是pair,这是由上层传递的模板参数T决定的,上层是封装我的map和set。

    2.仿函数 

    (1)节点比较大小时存在的问题 

    红黑树插入节点时,需要比较节点的大小,kv需要改成_data:

    1. //插入
    2. pairbool> Insert(const T& data)
    3. {
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(data);
    7. _root->_col = BLACK;
    8. return make_pair(_root, true);
    9. }
    10. //1.先看树中,kv是否存在
    11. Node* parent = nullptr;
    12. Node* cur = _root;
    13. while (cur)
    14. {
    15. if (cur->_data < data)
    16. {
    17. //kv比当前节点值大,向右走
    18. parent = cur;
    19. cur = cur->_right;
    20. }
    21. else if (cur->_data > data)
    22. {
    23. //kv比当前节点值小,向左走
    24. parent = cur;
    25. cur = cur->_left;
    26. }
    27. else
    28. {
    29. //kv和当前节点值相等,已存在,插入失败
    30. return make_pair(cur, false);
    31. }
    32. }
    33. //2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
    34. Node* newNode = new Node(kv);
    35. newNode->_col = RED;
    36. if (parent->_data < data)
    37. {
    38. //kv比parent值大,插入到parent的右边
    39. parent->_right = newNode;
    40. newNode->_parent = parent;
    41. }
    42. else
    43. {
    44. //kv比parent值小,插入到parent的左边
    45. parent->_left = newNode;
    46. newNode->_parent = parent;
    47. }
    48. cur = newNode;
    49. //如果父亲存在,且父亲颜色为红就要处理
    50. while (parent && parent->_col == RED)
    51. {
    52. //情况一和情况二、三的区别关键看叔叔
    53. Node* grandfather = parent->_parent;//当父亲是红色时,根据规则(2)根节点一定是黑色,祖父一定存在
    54. if (parent == grandfather->_left)//父亲是祖父的左子树
    55. {
    56. Node* uncle = grandfather->_right;
    57. //情况一:叔叔存在且为红
    58. if (uncle->_col == RED)
    59. {
    60. parent->_col = uncle->_col = BLACK;
    61. grandfather->_col = RED;
    62. //继续向上调整
    63. cur = grandfather;
    64. parent = cur->_parent;
    65. }
    66. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    67. {
    68. //情况二:单旋
    69. if (cur == parent->_left)
    70. {
    71. RotateR(grandfather);
    72. parent->_col = BLACK;
    73. grandfather->_col = RED;
    74. }
    75. else//情况三:双旋
    76. {
    77. RotateL(parent);
    78. RotateR(grandfather);
    79. cur->_col = BLACK;
    80. grandfather->_col = RED;
    81. }
    82. break;//插入结束
    83. }
    84. }
    85. else//父亲是祖父的右子树
    86. {
    87. Node* uncle = grandfather->_left;
    88. //情况一:叔叔存在且为红
    89. if (uncle && uncle->_col == RED)
    90. {
    91. parent->_col = uncle->_col = BLACK;
    92. grandfather->_col = RED;
    93. //继续往上调整
    94. cur = grandfather;
    95. parent = grandfather->_parent;
    96. }
    97. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    98. {
    99. //情况二:单旋
    100. if (cur == parent->_right)
    101. {
    102. RotateL(grandfather);
    103. parent->_col = BLACK;
    104. grandfather->_col = RED;
    105. }
    106. else//情况三:双旋
    107. {
    108. RotateR(parent);
    109. RotateL(grandfather);
    110. cur->_col = BLACK;
    111. grandfather->_col = RED;
    112. }
    113. break;//插入结束
    114. }
    115. }
    116. }
    117. _root->_col = BLACK;
    118. return make_pair(newNode, true);
    119. }

    但是以上代码在插入新节和查找节点时,当和当前节点比较大小时,Key可以比较,但是pair比较不了,也就是set可以比较,但是map比较不了。这就需要写一个仿函数,如果是map就取_data里面的first也就是Key进行比较,通过泛型解决红黑树里面存的是什么。所以上层容器map需要向底层的红黑树提供仿函数来获取T里面的Key,这样无论上层容器是set还是map,都可以用统一的方式进行比较了。

    (2)仿函数

    仿函数让一个类的使用看上去像个函数。仿函数是在类中实现了一个operator( ),是一个类的对象,这个类就有了类似函数的行为,所以这个类就是一个仿函数类,目的是为了让函数拥有类的性质。

    这个类的对象即仿函数,可以当作一般函数去用,只不过仿函数的功能是在一个类中的运算符operator()中实现的,使用的时候把函数作为参进行传递即可。更详细的理解请参考【C++】-- STL容器适配器之priority_queue第三节第1小节的内容。

    set有set的仿函数,map有map的仿函数,尽管set的仿函数看起来没有什么作用,但是,必须要把它传给底层红黑树,这样红黑树就能根据仿函数分别获取set的key和map的first。

     ①set的仿函数

    1. namespace delia
    2. {
    3. template<class K>
    4. class set
    5. {
    6. //仿函数,获取set的key
    7. struct SetKeyOfT
    8. {
    9. const K& operator()(const K& key)
    10. {
    11. return key;
    12. }
    13. };
    14. public:
    15. bool insert(const K& k)
    16. {
    17. _t.Insert(k);
    18. return true;
    19. }
    20. private:
    21. RBTree _t;
    22. };
    23. }

     ②map的仿函数

    1. namespace delia
    2. {
    3. template<class K,class V>
    4. class map
    5. {
    6. //仿函数,获取map的first
    7. struct MapKeyOfT
    8. {
    9. const K& operator()(const pair<const K, V>& kv)
    10. {
    11. return kv.first;
    12. }
    13. };
    14. public:
    15. //插入
    16. bool insert(const pair<const K, V>& kv)
    17. {
    18. _t.Insert(kv);
    19. return true;
    20. }
    21. private:
    22. RBTreeconst K, V>, MapKeyOfT> _t;
    23. };
    24. }

     有了仿函数红黑树的类在实现时,就要在模板参数中增加KeyOfT仿函数。

    (3)修改红黑树定义

    1. template<class K, class T, class KeyOfT>
    2. class RBTree
    3. {
    4. typedef RBTreeNode Node;
    5. private:
    6. Node* _root;
    7. };

    (4)修改红黑树插入

    1. //插入
    2. pairbool> Insert(const pair& kv)
    3. {
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. _root->_col = BLACK;
    8. return make_pair(_root, true);
    9. }
    10. KeyOfT kot;
    11. //1.先看树中,kv是否存在
    12. Node* parent = nullptr;
    13. Node* cur = _root;
    14. while (cur)
    15. {
    16. if (kot(cur->_data) < kot(data))
    17. {
    18. //kv比当前节点值大,向右走
    19. parent = cur;
    20. cur = cur->_right;
    21. }
    22. else if (kot(cur->_data) > kot(data))
    23. {
    24. //kv比当前节点值小,向左走
    25. parent = cur;
    26. cur = cur->_left;
    27. }
    28. else
    29. {
    30. //kv和当前节点值相等,已存在,插入失败
    31. return make_pair(cur, false);
    32. }
    33. }
    34. //2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
    35. Node* newNode = new Node(kv);
    36. newNode->_col = RED;
    37. if (kot(parent->_data) < kot(data))
    38. {
    39. //kv比parent值大,插入到parent的右边
    40. parent->_right = newNode;
    41. newNode->_parent = parent;
    42. }
    43. else
    44. {
    45. //kv比parent值小,插入到parent的左边
    46. parent->_left = newNode;
    47. newNode->_parent = parent;
    48. }
    49. cur = newNode;
    50. //如果父亲存在,且父亲颜色为红就要处理
    51. while (parent && parent->_col == RED)
    52. {
    53. //情况一和情况二、三的区别关键看叔叔
    54. Node* grandfather = parent->_parent;//当父亲是红色时,根据规则(2)根节点一定是黑色,祖父一定存在
    55. if (parent == grandfather->_left)//父亲是祖父的左子树
    56. {
    57. Node* uncle = grandfather->_right;
    58. //情况一:叔叔存在且为红
    59. if (uncle->_col == RED)
    60. {
    61. parent->_col = uncle->_col = BLACK;
    62. grandfather->_col = RED;
    63. //继续向上调整
    64. cur = grandfather;
    65. parent = cur->_parent;
    66. }
    67. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    68. {
    69. //情况二:单旋
    70. if (cur == parent->_left)
    71. {
    72. RotateR(grandfather);
    73. parent->_col = BLACK;
    74. grandfather->_col = RED;
    75. }
    76. else//情况三:双旋
    77. {
    78. RotateL(parent);
    79. RotateR(grandfather);
    80. cur->_col = BLACK;
    81. grandfather->_col = RED;
    82. }
    83. break;//插入结束
    84. }
    85. }
    86. else//父亲是祖父的右子树
    87. {
    88. Node* uncle = grandfather->_left;
    89. //情况一:叔叔存在且为红
    90. if (uncle && uncle->_col == RED)
    91. {
    92. parent->_col = uncle->_col = BLACK;
    93. grandfather->_col = RED;
    94. //继续往上调整
    95. cur = grandfather;
    96. parent = grandfather->_parent;
    97. }
    98. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    99. {
    100. //情况二:单旋
    101. if (cur == parent->_right)
    102. {
    103. RotateL(grandfather);
    104. parent->_col = BLACK;
    105. grandfather->_col = RED;
    106. }
    107. else//情况三:双旋
    108. {
    109. RotateR(parent);
    110. RotateL(grandfather);
    111. cur->_col = BLACK;
    112. grandfather->_col = RED;
    113. }
    114. break;//插入结束
    115. }
    116. }
    117. }
    118. _root->_col = BLACK;
    119. return make_pair(newNode, true);
    120. }
    121. void RotateR(Node* parent)
    122. {
    123. Node* subL = parent->_left;
    124. Node* subLR = nullptr;
    125. if (subL)
    126. {
    127. subLR = subL->_right;
    128. }
    129. //1.左子树的右子树变我的左子树
    130. parent->_left = subLR;
    131. if (subLR)
    132. {
    133. subLR->_parent = parent;
    134. }
    135. //左子树变父亲
    136. subL->_right = parent;
    137. Node* parentParent = parent->_parent;
    138. parent->_parent = subL;
    139. if (parent == _root)//parent是根
    140. {
    141. _root = subL;
    142. _root->_parent = nullptr;
    143. }
    144. else//parent不是根,是子树
    145. {
    146. if (parentParent->_left == parent)
    147. {
    148. //parent是自己父亲的左子树,将subL作为parent父亲的左孩子
    149. parentParent->_left = subL;
    150. }
    151. else
    152. {
    153. //parent是自己父亲的右子树,将subL作为parent父亲的右孩子
    154. parentParent->_right = subL;
    155. }
    156. //subL的父亲就是parent的父亲
    157. subL->_parent = parentParent;
    158. }
    159. }
    160. void RotateL(Node* parent)
    161. {
    162. Node* subR = parent->_right;
    163. Node* subRL = nullptr;
    164. if (subR)
    165. {
    166. subRL = subR->_left;
    167. }
    168. //1.右子树的左子树变我的右子树
    169. parent->_right = subRL;
    170. if (subRL)
    171. {
    172. subRL->_parent = parent;
    173. }
    174. //2.右子树变父亲
    175. subR->_left = parent;
    176. Node* parentParent = parent->_parent;
    177. parent->_parent = subR;
    178. if (parent == _root)//parent是根
    179. {
    180. _root = parent;
    181. _root->_parent = nullptr;
    182. }
    183. else//parent不是根,是子树
    184. {
    185. if (parentParent->_left == parent)
    186. {
    187. //parent是自己父亲的左子树,将subR作为parent父亲的左孩子
    188. parentParent->_left = subR;
    189. }
    190. else
    191. {
    192. //parent是自己父亲的右子树,将subR作为parent父亲的右孩子
    193. parentParent->_right = subR;
    194. }
    195. //subR的父亲就是parent的父亲
    196. subR->_parent = parentParent;
    197. }
    198. }

    (5)修改红黑树查找

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

    三、红黑树迭代器

    map和set的迭代器的实现其实本质上是红黑树迭代器的实现,迭代器的实现需要定义模板类型、模板类型引用、模板类型指针。 

    1.红黑树中迭代器重命名

     在红黑树中重命名模板类型、模板类型引用、模板类型指针,定义为public,外部就能使用iterator了:

    1. template<class K, class T, class KeyOfT>
    2. class RBTree
    3. {
    4. typedef RBTreeNode Node;
    5. public:
    6. typedef __TreeIterator iterator;//模板类型、模板类型引用、模板类型指针
    7. //红黑树函数...
    8. private:
    9. Node* _root;
    10. };

    2.正向迭代器定义

    红黑树的迭代器的本质是对节点指针进行封装,所以迭代器中只有封装红黑树节点指针这一个成员变量 。正向迭代器:

    1. template<class T,class Ref,class ptr>
    2. struct __TreeIterator
    3. {
    4. typedef RBTreeNode Node;
    5. typedef __TreeIterator Self;
    6. Node* _node;//成员变量
    7. };

    3.迭代器构造 

    用节点指针构造正向迭代器:

    1. //构造函数
    2. __TreeIterator(Node* node)
    3. :_node(node)
    4. {}

    4.正向迭代器重载* 

    Ref对正向迭代器解引用,返回节点数据引用:

    1. //* 解引用,返回节点数据
    2. Ref Operator*()
    3. {
    4. return _node->_data;
    5. }

    5.正向迭代器重载-> 

    Ptr对正向迭代器使用->,返回节点数据指针:

    1. //-> 返回节点数据地址
    2. Ptr Operator->()
    3. {
    4. return &_node->_data;
    5. }

    6.正向迭代器重载==

    判断节点是否相同 

    1. //判断两个迭代器是否相同
    2. bool operator==(const Self& s)
    3. {
    4. return _node == s._node;//判断节点是否相同
    5. }

    7.正向迭代器重载!=

    判断节点是否不同 

    1. //判断两个迭代器是否不同
    2. bool operator!=(const Self& s)
    3. {
    4. return _node != s._node;//判断节点是否不同
    5. }

    8.正向迭代器++

     ①当节点的右子树不为空时,++就要走到右子树的最左节点

     ②当节点的右子树为空时,++就要走到节点的父亲

    1. //红黑树迭代器的++也就是红黑树的++
    2. Self operator++()
    3. {
    4. //1.右子树不为空
    5. if (_node->_right)
    6. {
    7. //下一个访问的是右树的中序第一个节点(即右子树最左节点)。
    8. Node* left = _node->_right;
    9. //找最左节点
    10. while (left->_left)
    11. {
    12. left = left->_left;
    13. }
    14. _node = left;
    15. }
    16. else//2.右子树为空,下一个访问的就是当前节点的父亲
    17. {
    18. Node* cur = _node;
    19. Node* parent = cur->_parent;
    20. while (parent && cur == parent->_right)
    21. {
    22. cur = cur->_parent;
    23. parent = parent->_parent;
    24. }
    25. _node = parent;
    26. }
    27. return *this;
    28. }
    29. };

    9.正向迭代器--

     ①当节点的左子树不为空时,++就要走到左子树的最右节点

     ②当节点的左子树为空时,++就要走到节点的父亲

    1. //红黑树迭代器的--也就是红黑树的--
    2. Self operator--()
    3. {
    4. //1.左子树不为空
    5. if (_node->_left)
    6. {
    7. //下一个访问的是左树的中序左后节点(即做子树最右节点)。
    8. Node* right = _node->_left;
    9. //找最右节点
    10. while (right->_right)
    11. {
    12. right = right->_right;
    13. }
    14. _node = right;
    15. }
    16. else//2.左子树为空,下一个访问的就是当前节点的父亲
    17. {
    18. Node* cur = _node;
    19. Node* parent = cur->_parent;
    20. while (parent && cur == parent->_left)
    21. {
    22. cur = cur->_parent;
    23. parent = parent->_parent;
    24. }
    25. _node = parent;
    26. }
    27. return *this;
    28. }

    10.红黑树中实现迭代器

     实现begin( )找最左节点,end( )最后一个节点的下一个位置

    1. template<class K, class T, class KeyOfT>
    2. class RBTree
    3. {
    4. typedef RBTreeNode Node;
    5. public:
    6. typedef __TreeIterator iterator;//模板类型、模板类型引用、模板类型指针
    7. //找最左节点
    8. iterator begin()
    9. {
    10. Node* left = _root;
    11. while (left && left->_left)
    12. {
    13. left = left->_left;
    14. }
    15. return iterator(left)//返回最左节点的正向迭代器
    16. }
    17. //结束
    18. iterator end()
    19. {
    20. return iterator(nullptr);
    21. }
    22. private:
    23. Node* _root;
    24. };

    四、set模拟实现

    调用红黑树对应接口实现set,插入和查找函数返回值当中的节点指针改为迭代器:

    1. #pragma once
    2. #include "RBTree.h"
    3. namespace delia
    4. {
    5. template<class K>
    6. class set
    7. {
    8. //仿函数,获取set的key
    9. struct SetKeyOfT
    10. {
    11. const K& operator()(const K& key)
    12. {
    13. return key;
    14. }
    15. };
    16. public:
    17. typedef typename RBTree::iterator iterator;
    18. //迭代器开始
    19. iterator begin()
    20. {
    21. return _t.begin();
    22. }
    23. //迭代器结束
    24. iterator end()
    25. {
    26. return _t.end();
    27. }
    28. //插入函数
    29. pairbool> insert(const K& key)
    30. {
    31. return _t.Insert(key);
    32. }
    33. //查找
    34. iterator find(const K& key)
    35. {
    36. return _t.find(key);
    37. }
    38. private:
    39. RBTree _t;
    40. };
    41. }

    五、map模拟实现

    调用红黑树对应接口实现map,插入和查找函数返回值当中的节点指针改为迭代器,增加operator[ ]的重载:

    1. #pragma once
    2. #include "RBTree.h"
    3. namespace delia
    4. {
    5. template<class K, class V>
    6. class map
    7. {
    8. //仿函数,获取map的first
    9. struct MapKeyOfT
    10. {
    11. const K& operator()(const pair<const K, V>& kv)
    12. {
    13. return kv.first;
    14. }
    15. };
    16. public:
    17. typedef typename RBTree::iterator iterator;
    18. //迭代器开始
    19. iterator begin()
    20. {
    21. return _t.begin();
    22. }
    23. //迭代器结束
    24. iterator end()
    25. {
    26. return _t.end();
    27. }
    28. //插入
    29. pairbool> insert(const pair<const K, V>& kv)
    30. {
    31. return _t.Insert(kv);
    32. }
    33. //重载operator[]
    34. V& operator[](const K& key)
    35. {
    36. pairbool> ret = insert(make_pair(key, V()));
    37. iterator it = ret.first;
    38. return it->second;
    39. }
    40. //查找
    41. iterator find(const K& key)
    42. {
    43. return _t.find(key);
    44. }
    45. private:
    46. RBTreeconst K, V>, MapKeyOfT> _t;
    47. };
    48. }

    六、红黑树完整代码段

    1. #pragma once
    2. #include
    3. using namespace std;
    4. //节点颜色
    5. enum Colour
    6. {
    7. RED,
    8. BLACK,
    9. };
    10. //红黑树节点定义
    11. template<class T>
    12. struct RBTreeNode
    13. {
    14. RBTreeNode* _left;//节点的左孩子
    15. RBTreeNode* _right;//节点的右孩子
    16. RBTreeNode* _parent;//节点的父亲
    17. T _data;//节点的值
    18. Colour _col;//节点颜色
    19. RBTreeNode(const T& x)
    20. :_left(nullptr)
    21. , _right(nullptr)
    22. , _parent(nullptr)
    23. , _data(x)
    24. , _col(RED)
    25. {}
    26. };
    27. template<class T,class Ref,class ptr>
    28. struct __TreeIterator
    29. {
    30. typedef RBTreeNode Node;
    31. typedef __TreeIterator Self;
    32. Node* _node;
    33. //构造函数
    34. __TreeIterator(Node* node)
    35. :_node(node)
    36. {}
    37. //* 解引用,返回节点数据
    38. Ref operator*()
    39. {
    40. return _node->_data;
    41. }
    42. //-> 返回节点数据地址
    43. //Ptr operator->()
    44. //{
    45. // return &_node->_data;
    46. //}
    47. //判断两个迭代器是否相同
    48. bool operator==(const Self& s)
    49. {
    50. return _node == s._node;
    51. }
    52. //判断两个迭代器是否不同
    53. bool operator!=(const Self& s)
    54. {
    55. return _node != s._node;
    56. }
    57. //红黑树迭代器的++也就是红黑树的++
    58. Self operator++()
    59. {
    60. //1.右子树不为空
    61. if (_node->_right)
    62. {
    63. //下一个访问的是右树的中序第一个节点(即右子树最左节点)。
    64. Node* left = _node->_right;
    65. //找最左节点
    66. while (left->_left)
    67. {
    68. left = left->_left;
    69. }
    70. _node = left;
    71. }
    72. else//2.右子树为空,下一个访问的就是当前节点的父亲
    73. {
    74. Node* cur = _node;
    75. Node* parent = cur->_parent;
    76. while (parent && cur == parent->_right)
    77. {
    78. cur = cur->_parent;
    79. parent = parent->_parent;
    80. }
    81. _node = parent;
    82. }
    83. return *this;
    84. }
    85. //红黑树迭代器的--也就是红黑树的--
    86. Self operator--()
    87. {
    88. //1.左子树不为空
    89. if (_node->_left)
    90. {
    91. //下一个访问的是左树的中序左后节点(即做子树最右节点)。
    92. Node* right = _node->_left;
    93. //找最右节点
    94. while (right->_right)
    95. {
    96. right = right->_right;
    97. }
    98. _node = right;
    99. }
    100. else//2.左子树为空,下一个访问的就是当前节点的父亲
    101. {
    102. Node* cur = _node;
    103. Node* parent = cur->_parent;
    104. while (parent && cur == parent->_left)
    105. {
    106. cur = cur->_parent;
    107. parent = parent->_parent;
    108. }
    109. _node = parent;
    110. }
    111. return *this;
    112. }
    113. };
    114. //插入节点颜色是红色好,还是黑色好,红色
    115. //因为插入红色节点,可能破坏规则3,影响不大
    116. //插入黑色节点,一定破坏规则4 ,并且影响其他路径,影响很大
    117. template<class K, class T, class KeyOfT>
    118. class RBTree
    119. {
    120. typedef RBTreeNode Node;
    121. public:
    122. typedef __TreeIterator iterator;//模板类型、模板类型引用、模板类型指针
    123. //构造函数
    124. RBTree()
    125. :_root(nullpte)
    126. {}
    127. //析构
    128. ~RBTree()
    129. {
    130. _Destroy(_root);
    131. _root = nullptr;
    132. }
    133. void _Destroy(Node* root)
    134. {
    135. if (root == nullptr)
    136. {
    137. return;
    138. }
    139. _Destroy(root->_left);
    140. _Destroy(root->_right);
    141. delete root;
    142. }
    143. //找最左节点
    144. iterator begin()
    145. {
    146. Node* left = _root;
    147. while (left && left->_left)
    148. {
    149. left = left->_left;
    150. }
    151. return iterator(left);//返回最左节点的正向迭代器
    152. }
    153. //结束
    154. iterator end()
    155. {
    156. return iterator(nullptr);
    157. }
    158. //构造函数
    159. RBTree()
    160. :_root(nullptr)
    161. {}
    162. void Destroy(Node* root)
    163. {
    164. if (root == nullptr)
    165. {
    166. return;
    167. }
    168. Destroy(root->_left);
    169. Destroy(root->_right);
    170. }
    171. ~RBTree()
    172. {
    173. Destroy(_root);
    174. _root = nullptr;
    175. }
    176. //插入
    177. pairbool> Insert(const T& data)
    178. {
    179. if (_root == nullptr)
    180. {
    181. _root = new Node(data);
    182. _root->_col = BLACK;
    183. return make_pair(_root, true);
    184. }
    185. KeyOfT kot;
    186. //1.先看树中,kv是否存在
    187. Node* parent = nullptr;
    188. Node* cur = _root;
    189. while (cur)
    190. {
    191. if (kot(cur->_data) < kot(data))
    192. {
    193. //kv比当前节点值大,向右走
    194. parent = cur;
    195. cur = cur->_right;
    196. }
    197. else if (kot(cur->_data) > kot(data))
    198. {
    199. //kv比当前节点值小,向左走
    200. parent = cur;
    201. cur = cur->_left;
    202. }
    203. else
    204. {
    205. //kv和当前节点值相等,已存在,插入失败
    206. return make_pair(cur, false);
    207. }
    208. }
    209. //2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
    210. Node* newNode = new Node(data);
    211. newNode->_col = RED;
    212. if (kot(parent->_data) < kot(data))
    213. {
    214. //kv比parent值大,插入到parent的右边
    215. parent->_right = newNode;
    216. newNode->_parent = parent;
    217. }
    218. else
    219. {
    220. //kv比parent值小,插入到parent的左边
    221. parent->_left = newNode;
    222. newNode->_parent = parent;
    223. }
    224. cur = newNode;
    225. //如果父亲存在,且父亲颜色为红就要处理
    226. while (parent && parent->_col == RED)
    227. {
    228. //情况一和情况二、三的区别关键看叔叔
    229. Node* grandfather = parent->_parent;//当父亲是红色时,根据规则(2)根节点一定是黑色,祖父一定存在
    230. if (parent == grandfather->_left)//父亲是祖父的左子树
    231. {
    232. Node* uncle = grandfather->_right;
    233. //情况一:叔叔存在且为红
    234. if (uncle->_col == RED)
    235. {
    236. parent->_col = uncle->_col = BLACK;
    237. grandfather->_col = RED;
    238. //继续向上调整
    239. cur = grandfather;
    240. parent = cur->_parent;
    241. }
    242. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    243. {
    244. //情况二:单旋
    245. if (cur == parent->_left)
    246. {
    247. RotateR(grandfather);
    248. parent->_col = BLACK;
    249. grandfather->_col = RED;
    250. }
    251. else//情况三:双旋
    252. {
    253. RotateL(parent);
    254. RotateR(grandfather);
    255. cur->_col = BLACK;
    256. grandfather->_col = RED;
    257. }
    258. break;//插入结束
    259. }
    260. }
    261. else//父亲是祖父的右子树
    262. {
    263. Node* uncle = grandfather->_left;
    264. //情况一:叔叔存在且为红
    265. if (uncle && uncle->_col == RED)
    266. {
    267. parent->_col = uncle->_col = BLACK;
    268. grandfather->_col = RED;
    269. //继续往上调整
    270. cur = grandfather;
    271. parent = grandfather->_parent;
    272. }
    273. else//情况二+情况三:叔叔不存在或叔叔存在且为黑
    274. {
    275. //情况二:单旋
    276. if (cur == parent->_right)
    277. {
    278. RotateL(grandfather);
    279. parent->_col = BLACK;
    280. grandfather->_col = RED;
    281. }
    282. else//情况三:双旋
    283. {
    284. RotateR(parent);
    285. RotateL(grandfather);
    286. cur->_col = BLACK;
    287. grandfather->_col = RED;
    288. }
    289. break;//插入结束
    290. }
    291. }
    292. }
    293. _root->_col = BLACK;
    294. return make_pair(newNode, true);
    295. }
    296. void RotateR(Node* parent)
    297. {
    298. Node* subL = parent->_left;
    299. Node* subLR = nullptr;
    300. if (subL)
    301. {
    302. subLR = subL->_right;
    303. }
    304. //1.左子树的右子树变我的左子树
    305. parent->_left = subLR;
    306. if (subLR)
    307. {
    308. subLR->_parent = parent;
    309. }
    310. //左子树变父亲
    311. subL->_right = parent;
    312. Node* parentParent = parent->_parent;
    313. parent->_parent = subL;
    314. if (parent == _root)//parent是根
    315. {
    316. _root = subL;
    317. _root->_parent = nullptr;
    318. }
    319. else//parent不是根,是子树
    320. {
    321. if (parentParent->_left == parent)
    322. {
    323. //parent是自己父亲的左子树,将subL作为parent父亲的左孩子
    324. parentParent->_left = subL;
    325. }
    326. else
    327. {
    328. //parent是自己父亲的右子树,将subL作为parent父亲的右孩子
    329. parentParent->_right = subL;
    330. }
    331. //subL的父亲就是parent的父亲
    332. subL->_parent = parentParent;
    333. }
    334. }
    335. void RotateL(Node* parent)
    336. {
    337. Node* subR = parent->_right;
    338. Node* subRL = nullptr;
    339. if (subR)
    340. {
    341. subRL = subR->_left;
    342. }
    343. //1.右子树的左子树变我的右子树
    344. parent->_right = subRL;
    345. if (subRL)
    346. {
    347. subRL->_parent = parent;
    348. }
    349. //2.右子树变父亲
    350. subR->_left = parent;
    351. Node* parentParent = parent->_parent;
    352. parent->_parent = subR;
    353. if (parent == _root)//parent是根
    354. {
    355. _root = parent;
    356. _root->_parent = nullptr;
    357. }
    358. else//parent不是根,是子树
    359. {
    360. if (parentParent->_left == parent)
    361. {
    362. //parent是自己父亲的左子树,将subR作为parent父亲的左孩子
    363. parentParent->_left = subR;
    364. }
    365. else
    366. {
    367. //parent是自己父亲的右子树,将subR作为parent父亲的右孩子
    368. parentParent->_right = subR;
    369. }
    370. //subR的父亲就是parent的父亲
    371. subR->_parent = parentParent;
    372. }
    373. }
    374. //查找
    375. Node* Find(const K& key)
    376. {
    377. KeyOfT kot;
    378. Node* cur = _root;
    379. while (cur)
    380. {
    381. if (kot(cur->_data) < key)
    382. {
    383. cur = cur->_right;
    384. }
    385. else if (kot(cur->_data) > key)
    386. {
    387. cur = cur->_left;
    388. }
    389. else
    390. {
    391. return cur;
    392. }
    393. }
    394. return nullptr;//空树,直接返回
    395. }
    396. bool _CheckBalance(Node* root, int blackNum, int count)
    397. {
    398. if (root == nullptr)
    399. {
    400. if (count != blackNum)
    401. {
    402. cout << "黑色节点数量不相等" << endl;
    403. return false;
    404. }
    405. return true;
    406. }
    407. if (root->_col == RED && root->_parent->_col == RED)
    408. {
    409. cout << "存在连续红色节点" << endl;
    410. return false;
    411. }
    412. if (root->_col == BLACK)
    413. {
    414. count++;
    415. }
    416. return _CheckBalance(root->_left, blackNum, count)
    417. && _CheckBalance(root->_right, blackNum, count);
    418. }
    419. //检查是否平衡
    420. bool CheckBalance()
    421. {
    422. if (_root == nullptr)
    423. {
    424. return true;
    425. }
    426. if (_root->_col == RED)
    427. {
    428. cout << "根节点为红色" << endl;
    429. return false;
    430. }
    431. //找最左路径做黑色节点数量参考值
    432. int blackNum = 0;
    433. Node* left = _root;
    434. while (left)
    435. {
    436. if (left->_col == BLACK)
    437. {
    438. blackNum++;
    439. }
    440. left = left->_left;
    441. }
    442. int count = 0;
    443. return _CheckBalance(_root, blackNum, count);
    444. }
    445. //遍历
    446. void _InOrder(Node* root)
    447. {
    448. if (root == nullptr)
    449. {
    450. return;
    451. }
    452. _InOrder(root->_left);
    453. cout << root->_kv.first << ":" << root->_kv.second << endl;
    454. _InOrder(root->_right);
    455. }
    456. void InOrder()
    457. {
    458. _InOrder(_root);
    459. cout << endl;
    460. }
    461. private:
    462. Node* _root;
    463. };

    验证代码:

    1. #pragma once
    2. #include "RBTree.h"
    3. #include
    4. #include
    5. #include
    6. #include "Map.h"
    7. #include "Set.h"
    8. int main()
    9. {
    10. delia::map<int, int> m;
    11. m.insert(make_pair(1, 1));
    12. m.insert(make_pair(3, 3));
    13. m.insert(make_pair(0, 0));
    14. m.insert(make_pair(9, 9));
    15. delia::set<int> s;
    16. s.insert(1);
    17. s.insert(5);
    18. s.insert(2);
    19. s.insert(1);
    20. s.insert(13);
    21. s.insert(0);
    22. s.insert(15);
    23. s.insert(18);
    24. delia::set<int>::iterator sit = s.begin();
    25. while (sit != s.end())
    26. {
    27. cout << *sit << " ";
    28. ++sit;
    29. }
    30. cout << endl;
    31. return 0;
    32. }

  • 相关阅读:
    【机器学习-周志华】学习笔记-第三章
    递归:快速排序,归并排序和堆排序
    每日一题 1993. 树上的操作
    Leetcode Daily Challenge 1845. Seat Reservation Manager
    浏览器“四巨头”首度合作 解决网页适配问题
    贝塞尔曲线的一些资料收集
    【C语言】sizeof操作符详解
    数字信号处理-10-并行FIR滤波器MATLAB与FPGA实现
    智慧公厕:探索未来公共厕所的创新设计
    17:00面试,17:04就出来了 ,问的实在是太...
  • 原文地址:https://blog.csdn.net/gx714433461/article/details/126721634