当前位置:   article > 正文

C++:map和set的封装

C++:map和set的封装

      关于红黑树的模拟实现,大家不清楚的先去看看博主的博客再来看这篇文章,因为set和map的封装底层都是利用用的红黑树。所以这里不会过多介绍红黑树的相关内容,而更多的是去为了契合STL中的红黑树去进行改造,让封装的set和map能够去复用我们的这份代码

DS进阶:AVL树和红黑树-CSDN博客

      在模拟实现之前,我们肯定要尝试去看看源码是如何实现的!我们会发现其实map和set的底层都是用的红黑树去封装的

      但是你可能会有这样的疑惑,map是kv模型,set是k模型,那难道stl底层封装了两颗红黑树么??其实并不是的,创建stl的大佬们为了增加代码的复用性,想方设法地想让map和set同时复用一颗红黑树。而解决方法就是通过控制模版参数来区分map和set。

     既然底层是套的红黑树的壳子,我们就要来研究库里面的红黑树究竟通过了什么方法来让map和set都能够复用这份代码。

一、STL中的红黑树

1.1 利用模版参数控制和区分map和set

我们先来看看stl中的红黑树的模版参数,然后进行分析

   接下来我们来看看第三个模版参数的作用究竟是什么

总结:

第1个模版参数是为了帮助我们拿到Key的类型,因为find、erase的接口都是Key类型比较方便

第2个模版参数决定了红黑树节点中存的是key还是pair,以此来区分map和set

第3个模版参数是通过仿函数决定了是拿什么去进行比较,对set来说就是拿key,对pair来说就是拿他的first。

第4个模版参数是具体的比较逻辑,比如说我们传的是指针,但是我们并不想通过指针比而是通过指针解引用的类型比,就可以通过传这个仿函数去控制其比较的行为。

第5个是stl实现的一个堆内存管理器,是为了提高从堆区申请内存的效率,基本上所有的stl容器都会涉及到这个,所以目前暂时不需要太在意!

1.2 stl中的红黑树结构

在该图中,设置了一个哨兵节点,哨兵节点的左指向最小节点5,最大节点的右指向哨兵节点header, 为什么要这样设计呢??

      STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,
可以得到一个有序的序列,
因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位
置,end()放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块?
能否给成nullptr呢?答案是行不通的,因为对end()位置的迭代器进行--操作,必须要能找最
后一个元素,此处就不行,因此最好的方式是将end()放在头结点的位置:

 

       但是这样虽然方便我们找到第一个节点和最后一个节点,但是每一次都要最最左端和最右端的节点进行和头节点之间的联系,其实比较麻烦,所以下面我们直接改造成不带哨兵节点的红黑树。去模拟实现迭代器。

1.3 改造并模拟实现红黑树的迭代器

但是最最关键的逻辑就是,实现++和--这样迭代器才能跑的起来,下面我们来进行分析

迭代器的封装

  1. template<class T,class Ref,class Ptr>
  2. struct _RBTreeIterator
  3. {
  4. typedef RBTreeNode<T> Node;
  5. typedef _RBTreeIterator<T, Ref, Ptr> Self; //返回一个自身的迭代器
  6. typedef _RBTreeIterator<T, T&, T*> iterator; //用来转化成const迭代器
  7. Node* _node;
  8. _RBTreeIterator(Node* node) //利用节点去构造迭代器
  9. :_node(node)
  10. {}
  11. // 1、typedef __RBTreeIterator<T, T&, T*> itertaor; 拷贝构造
  12. // 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
  13. // 支持普通迭代器构造const迭代器的构造函数
  14. _RBTreeIterator(const iterator& it) //隐私类型转化
  15. :_node(it._node)
  16. {}
  17. Ref operator*()
  18. {
  19. return _node->_data; //解引用拿到对应的东西 map拿到pair set拿到key
  20. }
  21. Ptr operator->() //返回对应的指针类型
  22. {
  23. return &operator*();
  24. }
  25. bool operator!=(const Self& s)
  26. {
  27. return _node != s._node;//判断两个迭代器是否相同
  28. }
  29. bool operator==(const Self& s)
  30. {
  31. return _node == s._node;//判断两个迭代器是否相同
  32. }
  33. Self& operator++() //实现迭代器的++
  34. {
  35. if (_node->_right)
  36. {
  37. //如有右不为空,那么就去找到 右子树的最左路节点
  38. Node* subright = _node->_right;
  39. while (subright->_left) subright = subright->_left; //找到最左路节点
  40. _node = subright;
  41. }
  42. else
  43. {
  44. //右为空,沿着到根的路径,找孩子是父亲左的那个祖先
  45. Node* cur = _node;
  46. Node* parent = cur->_parent;
  47. while (parent && parent->_right == cur)
  48. {
  49. cur = parent;
  50. parent = parent->_parent;
  51. }
  52. _node = parent;
  53. }
  54. return *this;
  55. }
  56. Self operator++(int) //实现迭代器的后置++
  57. {
  58. Self temp = *this;
  59. ++*this;
  60. return temp;
  61. }
  62. Self& operator--() //实现迭代器的-- 右 根 左
  63. {
  64. if (_node->_left)
  65. {
  66. //如有左不为空,那么就去找到 左子树的最右路节点
  67. Node* subright = _node->_left;
  68. while (subright->_right) subright = subright->_right; //找到最左路节点
  69. _node = subright;
  70. }
  71. else
  72. {
  73. //左为空,沿着到根的路径,找孩子是父亲右的那个祖先
  74. Node* cur = _node;
  75. Node* parent = cur->_parent;
  76. while (parent && parent->_left == cur)
  77. {
  78. cur = parent;
  79. parent = parent->_parent;
  80. }
  81. _node = parent;
  82. }
  83. return *this;
  84. }
  85. Self operator--(int) //实现迭代器的后置--
  86. {
  87. Self temp = *this;
  88. --*this;
  89. return temp;
  90. }
  91. };

1.4 红黑树实现的全部代码 

  1. enum Colour
  2. {
  3. RED,
  4. BLACK,
  5. };
  6. template<class T> //T表示传的是K还是pair
  7. struct RBTreeNode
  8. {
  9. RBTreeNode<T>* _left;
  10. RBTreeNode<T>* _right;
  11. RBTreeNode<T>* _parent;
  12. T _data;
  13. Colour _col;
  14. RBTreeNode(const T& data)
  15. : _left(nullptr)
  16. , _right(nullptr)
  17. , _parent(nullptr)
  18. , _data(data)
  19. , _col(RED)
  20. {}
  21. };
  22. template<class T,class Ref,class Ptr>
  23. struct _RBTreeIterator
  24. {
  25. typedef RBTreeNode<T> Node;
  26. typedef _RBTreeIterator<T, Ref, Ptr> Self; //返回一个自身的迭代器
  27. typedef _RBTreeIterator<T, T&, T*> iterator; //用来转化成const迭代器
  28. Node* _node;
  29. _RBTreeIterator(Node* node) //利用节点去构造迭代器
  30. :_node(node)
  31. {}
  32. // 1、typedef __RBTreeIterator<T, T&, T*> itertaor; 拷贝构造
  33. // 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
  34. // 支持普通迭代器构造const迭代器的构造函数 为的是隐式类型转化
  35. _RBTreeIterator(const iterator& it) //隐私类型转化 为了set去服务的 因为set的普通迭代器也是const迭代器
  36. :_node(it._node)
  37. {}
  38. Ref operator*()
  39. {
  40. return _node->_data; //解引用拿到对应的东西 map拿到pair set拿到key
  41. }
  42. Ptr operator->() //返回对应的指针类型
  43. {
  44. return &operator*();
  45. }
  46. bool operator!=(const Self& s)
  47. {
  48. return _node != s._node;//判断两个迭代器是否相同
  49. }
  50. bool operator==(const Self& s)
  51. {
  52. return _node == s._node;//判断两个迭代器是否相同
  53. }
  54. Self& operator++() //实现迭代器的++
  55. {
  56. if (_node->_right)
  57. {
  58. //如有右不为空,那么就去找到 右子树的最左路节点
  59. Node* subright = _node->_right;
  60. while (subright->_left) subright = subright->_left; //找到最左路节点
  61. _node = subright;
  62. }
  63. else
  64. {
  65. //右为空,沿着到根的路径,找孩子是父亲左的那个祖先
  66. Node* cur = _node;
  67. Node* parent = cur->_parent;
  68. while (parent && parent->_right == cur)
  69. {
  70. cur = parent;
  71. parent = parent->_parent;
  72. }
  73. _node = parent;
  74. }
  75. return *this;
  76. }
  77. Self operator++(int) //实现迭代器的后置++
  78. {
  79. Self temp = *this;
  80. ++*this;
  81. return temp;
  82. }
  83. Self& operator--() //实现迭代器的-- 右 根 左
  84. {
  85. if (_node->_left)
  86. {
  87. //如有左不为空,那么就去找到 左子树的最右路节点
  88. Node* subright = _node->_left;
  89. while (subright->_right) subright = subright->_right; //找到最左路节点
  90. _node = subright;
  91. }
  92. else
  93. {
  94. //左为空,沿着到根的路径,找孩子是父亲右的那个祖先
  95. Node* cur = _node;
  96. Node* parent = cur->_parent;
  97. while (parent && parent->_left == cur)
  98. {
  99. cur = parent;
  100. parent = parent->_parent;
  101. }
  102. _node = parent;
  103. }
  104. return *this;
  105. }
  106. Self operator--(int) //实现迭代器的后置--
  107. {
  108. Self temp = *this;
  109. --*this;
  110. return temp;
  111. }
  112. };
  113. //K是为了单独拿到key的类型 因为find erase 的接口都是key 而第二个模版参数T决定是这边传的是pair还是key
  114. template<class K, class T,class KeyOfT> //KeyofT 取出来比较的是k 还是pair中的k
  115. class RBTree
  116. {
  117. typedef RBTreeNode<T> Node;
  118. public:
  119. typedef _RBTreeIterator<T, T&, T*> iterator;
  120. typedef _RBTreeIterator<T, const T&, const T*> const_iterator;
  121. iterator begin()
  122. {
  123. Node* cur = _root;
  124. while (cur && cur->_left) cur = cur->_left;
  125. //找到最左路的节点
  126. return iterator(cur);
  127. }
  128. iterator end()
  129. {
  130. return iterator(nullptr);
  131. }
  132. const_iterator begin() const
  133. {
  134. Node* cur = _root;
  135. while (cur && cur->_left) cur = cur->_left;
  136. //找到最左路的节点
  137. return const_iterator(cur);
  138. }
  139. const_iterator end() const
  140. {
  141. return const_iterator(nullptr);
  142. }
  143. ~RBTree()
  144. {
  145. _Destroy(_root);
  146. _root = nullptr;
  147. }
  148. iterator Find(const K& key) const
  149. {
  150. Node* cur = _root;
  151. KeyOfT kot;//控制 是在pair中拿key还是直接拿key
  152. while (cur)
  153. {
  154. if (kot(cur->_data) < key) cur = cur->_right; //我比你小,你往右找
  155. else if (kot(cur->_data) > key) cur = cur->_left; //我比你大,你往左找
  156. else return iterator(cur);
  157. }
  158. return iterator(nullptr);//说明找不到
  159. }
  160. //先用搜索树的逻辑插入节点,然后再去更新平衡因子。
  161. pair<iterator,bool> Insert(const T& data)
  162. {
  163. //如果为空树,新节点就是根
  164. if (_root == nullptr)
  165. {
  166. _root = new Node(data);
  167. _root->_col = BLACK;
  168. return make_pair(iterator(_root),true);
  169. }
  170. KeyOfT kot;//控制 是在pair中拿key还是直接拿key
  171. //如果不为空树
  172. Node* parent = nullptr;
  173. Node* cur = _root;
  174. while (cur)
  175. {
  176. if (kot(cur->_data) > kot(data)) //如果我比你大,到左子树去
  177. {
  178. parent = cur;
  179. cur = cur->_left;
  180. }
  181. else if (kot(cur->_data) < kot(data)) //比你小,你去右子树
  182. {
  183. parent = cur;
  184. cur = cur->_right;
  185. }
  186. else return make_pair(iterator(cur), false);//相等
  187. }
  188. //此时肯定是对应地接在parent的后面
  189. cur = new Node(data);
  190. Node* newnode = cur;//记住新加入的节点
  191. if (kot(parent->_data)> kot(data)) parent->_left = cur; //比父亲小连左边
  192. else parent->_right = cur; //比父亲大连右边
  193. //别忘了父亲指针
  194. cur->_parent = parent;
  195. while (parent && parent->_col == RED)
  196. {
  197. Node* grandfather = parent->_parent;
  198. //情况1,如果u为存在且为红
  199. if (grandfather->_left == parent)//如果p是g的左边,u就在右边
  200. {
  201. Node* uncle = grandfather->_right;
  202. //情况1,如果u为存在且为红 p u变黑,g变红 向上调整
  203. if (uncle && uncle->_col == RED)
  204. {
  205. parent->_col = BLACK;
  206. uncle->_col = BLACK;
  207. grandfather->_col = RED;
  208. //继续向上调整
  209. cur = grandfather;
  210. parent = cur->_parent;
  211. }
  212. else //情况2或者情况3, u为黑或者不存在 旋转+变色
  213. {
  214. if (cur == parent->_left) //情况2 右单旋+p变黑 g变红
  215. {
  216. // g
  217. // p u
  218. // c
  219. RotateR(grandfather);
  220. parent->_col = BLACK;
  221. grandfather->_col = RED;
  222. }
  223. else //情况3 右左双旋 c变黑 g变红
  224. {
  225. // g
  226. // p u
  227. // c
  228. RotateL(parent);
  229. RotateR(grandfather);
  230. cur->_col = BLACK;
  231. grandfather->_col = RED;
  232. }
  233. break;//情况2和情况3都要跳出循环
  234. }
  235. }
  236. else//if (grandfather->_right == parent)//如果p是g的右边,u就在左边 几乎一样,就是旋转的逻辑不同
  237. {
  238. Node* uncle = grandfather->_left;
  239. //情况1,如果u为存在且为红 p u变黑,g变红 向上调整
  240. if (uncle && uncle->_col == RED)
  241. {
  242. parent->_col = BLACK;
  243. uncle->_col = BLACK;
  244. grandfather->_col = RED;
  245. //继续向上调整
  246. cur = grandfather;
  247. parent = cur->_parent;
  248. }
  249. else//情况2或者情况3, u为黑或者不存在 旋转+变色
  250. {
  251. if (cur == parent->_right) //情况2 左单旋+p变黑 g变红
  252. {
  253. // g
  254. // p u
  255. // c
  256. RotateL(grandfather);
  257. parent->_col = BLACK;
  258. grandfather->_col = RED;
  259. }
  260. else //情况3 左右双旋 c变黑 g变红
  261. {
  262. // g
  263. // p u
  264. // c
  265. RotateR(parent);
  266. RotateL(grandfather);
  267. cur->_col = BLACK;
  268. grandfather->_col = RED;
  269. }
  270. break;//情况2和情况3都要跳出循环
  271. }
  272. }
  273. }
  274. _root->_col = BLACK; //预防情况1出现 parent就是根的情况 此时无论如何_root变成黑,总没错
  275. return make_pair(iterator(newnode), true);
  276. }
  277. void InOrder()
  278. {
  279. _InOrder(_root);
  280. cout << endl;
  281. }
  282. bool IsBalance()
  283. {
  284. if (_root && _root->_col == RED)
  285. {
  286. cout << "根节点颜色是红色" << endl;
  287. return false;
  288. }
  289. int benchmark = 0;//找到一条路径作为基准值 然后看看其他路径是否相等
  290. Node* cur = _root;
  291. while (cur)
  292. {
  293. if (cur->_col == BLACK)
  294. ++benchmark;
  295. cur = cur->_left;
  296. }
  297. // 连续红色节点
  298. return _Check(_root, 0, benchmark);
  299. }
  300. int Height()
  301. {
  302. return _Height(_root);
  303. }
  304. private:
  305. void _Destroy(Node* root)
  306. {
  307. if (root == nullptr) return;
  308. //后序遍历销毁
  309. _Destroy(root->_left);
  310. _Destroy(root->_right);
  311. delete root;
  312. }
  313. int _Height(Node* root)
  314. {
  315. if (root == nullptr)
  316. return 0;
  317. int leftH = _Height(root->_left);
  318. int rightH = _Height(root->_right);
  319. return leftH > rightH ? leftH + 1 : rightH + 1;
  320. }
  321. bool _Check(Node* root, int blackNum, int benchmark)
  322. {
  323. if (root == nullptr)
  324. {
  325. if (benchmark != blackNum)
  326. {
  327. cout << "某条路径黑色节点的数量不相等" << endl;
  328. return false;
  329. }
  330. return true;
  331. }
  332. if (root->_col == BLACK)
  333. {
  334. ++blackNum;
  335. }
  336. if (root->_col == RED
  337. && root->_parent
  338. && root->_parent->_col == RED)
  339. {
  340. cout << "存在连续的红色节点" << endl;
  341. return false;
  342. }
  343. return _Check(root->_left, blackNum, benchmark)
  344. && _Check(root->_right, blackNum, benchmark);
  345. }
  346. void _InOrder(Node* root)
  347. {
  348. if (root == nullptr)
  349. {
  350. return;
  351. }
  352. _InOrder(root->_left);
  353. cout << root->_kv.first << " ";
  354. _InOrder(root->_right);
  355. }
  356. //旋转代码和AVL树是一样的,只不过不需要搞平衡因子
  357. void RotateL(Node* parent)
  358. {
  359. //旋转前,先记录对应的节点
  360. Node* subR = parent->_right;
  361. Node* subRL = subR->_left;
  362. Node* ppnode = parent->_parent;//子树的前驱节点
  363. //先让b变成30的边
  364. parent->_right = subRL;
  365. if (subRL) subRL->_parent = parent;
  366. //让30变成60的左边
  367. subR->_left = parent;
  368. parent->_parent = subR;
  369. //此时与前驱节点连接起来 如果前驱节点为空,直接改变根
  370. if (ppnode == nullptr)
  371. {
  372. _root = subR;
  373. _root->_parent = nullptr;
  374. }
  375. //如果前驱节点不为空,此时要根据之前paernt的情况决定插在哪边
  376. else
  377. {
  378. if (ppnode->_left == parent) ppnode->_left = subR;
  379. else ppnode->_right = subR;
  380. //向上连接
  381. subR->_parent = ppnode;
  382. }
  383. }
  384. void RotateR(Node* parent)
  385. {
  386. //旋转前,先记录对应的节点
  387. Node* subL = parent->_left;
  388. Node* subLR = subL->_right;
  389. Node* ppnode = parent->_parent;//子树的前驱节点
  390. //先让b变成60的左边
  391. parent->_left = subLR;
  392. if (subLR) subLR->_parent = parent;
  393. //让60变成30的右边
  394. subL->_right = parent;
  395. parent->_parent = subL;
  396. //此时与前驱节点连接起来 如果前驱节点为空,直接改变根
  397. if (ppnode == nullptr)
  398. {
  399. _root = subL;
  400. _root->_parent = nullptr;
  401. }
  402. //如果前驱节点不为空,此时要根据之前paernt的情况决定插在哪边
  403. else
  404. {
  405. if (ppnode->_left == parent) ppnode->_left = subL;
  406. else ppnode->_right = subL;
  407. //向上连接
  408. subL->_parent = ppnode;
  409. }
  410. }
  411. Node* _root = nullptr;
  412. };

二、set的模拟实现

前面我们已经将架子搭好了,这个时候就可以直接开始用了!!

  1. namespace cyx
  2. {
  3. template<class K>
  4. class set
  5. {
  6. struct SetKeyofT
  7. {
  8. const K& operator()(const K& key) //为了跟map保持一致
  9. {
  10. return key;
  11. }
  12. };
  13. public:
  14. typedef typename RBTree< K,K,SetKeyofT>::const_iterator iterator;//在没有实例化的时候 编译器并不知道这是一个成员还是一个类型 typename可以帮助我们解决这个问题
  15. typedef typename RBTree< K, K, SetKeyofT>::const_iterator const_iterator;
  16. iterator begin()
  17. {
  18. return _t.begin();
  19. }
  20. iterator end()
  21. {
  22. return _t.end();
  23. }
  24. const_iterator begin() const
  25. {
  26. return _t.begin();
  27. }
  28. const_iterator end() const
  29. {
  30. return _t.end();
  31. }
  32. pair<iterator, bool> insert(const K&key)
  33. {
  34. return _t.Insert(key);
  35. }
  36. private:
  37. RBTree<K, K, SetKeyofT> _t;
  38. };
  39. void test_set1()
  40. {
  41. int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
  42. set<int> s;
  43. for (auto e : a)
  44. {
  45. s.insert(e);
  46. }
  47. set<int>::iterator it = s.begin();
  48. while (it != s.end())
  49. {
  50. cout << *it << " ";
  51. //*it = 1;
  52. ++it;
  53. }
  54. cout << endl;
  55. for (auto e : s)
  56. {
  57. cout << e << " ";
  58. }
  59. cout << endl;
  60. }
  61. }

注意:

1、在没有实例化的时候 ,编译器并不知道这是一个成员还是一个类型 typename可以帮助我们解决这个问题

 2、对于insert返回值的改造,本质上是为了map去服务的,set只是配合而已。

三、map的模拟实现

3.1 insert的改装

在stl中 insert的返回值是pair<iterator,bool> 一开始我不太能理解为什么要这么设计。后来我明白了其实本质上为了后面重载[ ]的实现做铺垫。我们可以通过返回值去拿到iterator,并对对应节点的value进行直接修改!!

  1. //先用搜索树的逻辑插入节点,然后再去更新平衡因子。
  2. pair<iterator,bool> Insert(const T& data)
  3. {
  4. //如果为空树,新节点就是根
  5. if (_root == nullptr)
  6. {
  7. _root = new Node(data);
  8. _root->_col = BLACK;
  9. return make_pair(iterator(_root),true);
  10. }
  11. KeyOfT kot;//控制 是在pair中拿key还是直接拿key
  12. //如果不为空树
  13. Node* parent = nullptr;
  14. Node* cur = _root;
  15. while (cur)
  16. {
  17. if (kot(cur->_data) > kot(data)) //如果我比你大,到左子树去
  18. {
  19. parent = cur;
  20. cur = cur->_left;
  21. }
  22. else if (kot(cur->_data) < kot(data)) //比你小,你去右子树
  23. {
  24. parent = cur;
  25. cur = cur->_right;
  26. }
  27. else return make_pair(iterator(cur), false);//相等
  28. }
  29. //此时肯定是对应地接在parent的后面
  30. cur = new Node(data);
  31. Node* newnode = cur;//记住新加入的节点
  32. if (kot(parent->_data)> kot(data)) parent->_left = cur; //比父亲小连左边
  33. else parent->_right = cur; //比父亲大连右边
  34. //别忘了父亲指针
  35. cur->_parent = parent;
  36. while (parent && parent->_col == RED)
  37. {
  38. Node* grandfather = parent->_parent;
  39. //情况1,如果u为存在且为红
  40. if (grandfather->_left == parent)//如果p是g的左边,u就在右边
  41. {
  42. Node* uncle = grandfather->_right;
  43. //情况1,如果u为存在且为红 p u变黑,g变红 向上调整
  44. if (uncle && uncle->_col == RED)
  45. {
  46. parent->_col = BLACK;
  47. uncle->_col = BLACK;
  48. grandfather->_col = RED;
  49. //继续向上调整
  50. cur = grandfather;
  51. parent = cur->_parent;
  52. }
  53. else //情况2或者情况3, u为黑或者不存在 旋转+变色
  54. {
  55. if (cur == parent->_left) //情况2 右单旋+p变黑 g变红
  56. {
  57. // g
  58. // p u
  59. // c
  60. RotateR(grandfather);
  61. parent->_col = BLACK;
  62. grandfather->_col = RED;
  63. }
  64. else //情况3 右左双旋 c变黑 g变红
  65. {
  66. // g
  67. // p u
  68. // c
  69. RotateL(parent);
  70. RotateR(grandfather);
  71. cur->_col = BLACK;
  72. grandfather->_col = RED;
  73. }
  74. break;//情况2和情况3都要跳出循环
  75. }
  76. }
  77. else//if (grandfather->_right == parent)//如果p是g的右边,u就在左边 几乎一样,就是旋转的逻辑不同
  78. {
  79. Node* uncle = grandfather->_left;
  80. //情况1,如果u为存在且为红 p u变黑,g变红 向上调整
  81. if (uncle && uncle->_col == RED)
  82. {
  83. parent->_col = BLACK;
  84. uncle->_col = BLACK;
  85. grandfather->_col = RED;
  86. //继续向上调整
  87. cur = grandfather;
  88. parent = cur->_parent;
  89. }
  90. else//情况2或者情况3, u为黑或者不存在 旋转+变色
  91. {
  92. if (cur == parent->_right) //情况2 左单旋+p变黑 g变红
  93. {
  94. // g
  95. // p u
  96. // c
  97. RotateL(grandfather);
  98. parent->_col = BLACK;
  99. grandfather->_col = RED;
  100. }
  101. else //情况3 左右双旋 c变黑 g变红
  102. {
  103. // g
  104. // p u
  105. // c
  106. RotateR(parent);
  107. RotateL(grandfather);
  108. cur->_col = BLACK;
  109. grandfather->_col = RED;
  110. }
  111. break;//情况2和情况3都要跳出循环
  112. }
  113. }
  114. }
  115. _root->_col = BLACK; //预防情况1出现 parent就是根的情况 此时无论如何_root变成黑,总没错
  116. return make_pair(iterator(newnode), true);
  117. }

3.2 重载[ ]的实现

  1. V& operator[](const K& key)
  2. {
  3. pair<iterator, bool> ret = _t.Insert(make_pair(key, V())); //默认构造
  4. return ret.first->second;
  5. }

通过insert拿到对应位置的迭代器,然后指向其second 这样就可以直接进行修改了。 

3.3 模拟实现的代码

  1. namespace cyx
  2. {
  3. template<class K, class V>
  4. class map
  5. {
  6. struct MapKeyofT
  7. {
  8. const K& operator()(const pair<const K, V>& kv) //为了跟map保持一致
  9. {
  10. return kv.first;
  11. }
  12. };
  13. public:
  14. //模版类型的内嵌类型 加typename
  15. typedef typename RBTree<K, pair<const K, V>, MapKeyofT>::iterator iterator;//在没有实例化的时候 编译器并不知道这是一个成员还是一个类型 typename可以帮助我们解决这个问题
  16. typedef typename RBTree<K, pair<const K, V>, MapKeyofT>::iterator const_iterator;
  17. iterator begin()
  18. {
  19. return _t.begin();
  20. }
  21. iterator end()
  22. {
  23. return _t.end();
  24. }
  25. const_iterator begin() const
  26. {
  27. return _t.begin();
  28. }
  29. const_iterator end() const
  30. {
  31. return _t.end();
  32. }
  33. V& operator[](const K& key)
  34. {
  35. pair<iterator, bool> ret = _t.Insert(make_pair(key, V())); //默认构造
  36. return ret.first->second;
  37. }
  38. pair<iterator, bool> insert(const pair<const K, V>& kv)
  39. {
  40. return _t.Insert(kv);
  41. }
  42. private:
  43. RBTree<K, pair<const K,V>, MapKeyofT> _t;
  44. };
  45. void test_map()
  46. {
  47. map<string, string> dict;
  48. dict.insert(make_pair("sort", "排序"));
  49. dict.insert(make_pair("left", "左边"));
  50. dict.insert(make_pair("right", "右边"));
  51. dict.insert(make_pair("hello", "你好"));
  52. map<string, string>::iterator it = dict.begin();
  53. cout << it->first<<endl;
  54. it++;
  55. cout << it->first << endl;
  56. it--;
  57. cout << it->first << endl;
  58. while (it != dict.end())
  59. {
  60. cout << it->first << ":" << it->second << endl;
  61. ++it;
  62. }
  63. //for(auto&kv:dict) cout << kv.first << ":" << kv.second << endl;
  64. }
  65. void test_map2()
  66. {
  67. string arr[] = { "西瓜", "梨子", "香蕉", "香蕉", "苹果", "西瓜", "梨子", "香蕉", "西瓜", "西瓜", "苹果", "火龙果", "橙子", "梨子"};
  68. map<string, int> countMap;
  69. for (auto& e : arr)
  70. {
  71. ++countMap[e];
  72. }
  73. for (auto& kv : countMap)
  74. {
  75. //kv.second = 2; 控制first不能被修改 或者是key不能被修改
  76. cout << kv.first << ":" << kv.second << endl;
  77. }
  78. }
  79. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/645397
推荐阅读
相关标签
  

闽ICP备14008679号