当前位置:   article > 正文

红黑树——学习总结以及封装map和set_map红黑树

map红黑树

红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

 

红黑树的性质

  1. 每个节点不是红色就是黑色
  2. 节点是黑色
  3. 如果一个节点是红色的,则它的两个子节点是黑色的
  4. 对于每个节点,从该节点到其所有后代夜节点的简单路径上,均包含数目相同的黑色节点
  5. 每个叶子节点都是黑色的(此处的叶子节点指的是空节点)NIL节点

最短路径全黑 
最长路径:一黑一红,黑红相间

 

上面这种树,AVL一定旋转,RB不一定旋转

旋转

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

情况一:cur为红,p为红,g为黑,u存在且为红

解决方方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整

 

再向上调整即g改为黑

情况二:cur为红, p为红,g为黑,u不存在/u存在且为黑

 

 

情况三:cur为红(左p右边/右p左边),p为红,g为黑,u不存在/u存在且为黑

和情况二完全类似,只是情况二是单旋,情况三是双旋

 

红黑树的实现

节点结构

  1. enum Colour
  2. {
  3. RED,
  4. BLACK,
  5. };
  6. template<class T>
  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. };

红黑树中的节点和AVL相比就多了一个颜色_col ,只需要用两种状态表示即可,这里用枚举类型当作颜色

插入

  1. template<class K, class T, class KeyOfT>
  2. bool Insert(const T& data)
  3. {
  4. if (_root == nullptr)
  5. {
  6. _root = new Node(data);
  7. _root->_col = BLACK;
  8. return true;
  9. }
  10. KeyOfT kot;
  11. Node* parent = nullptr;
  12. Node* cur = _root;
  13. while (cur)
  14. {
  15. if (kot(cur->_data) < kot(data))
  16. {
  17. parent = cur;
  18. cur = cur->_right;
  19. }
  20. else if (kot(cur->_data) > kot(data))
  21. {
  22. parent = cur;
  23. cur = cur->_left;
  24. }
  25. else
  26. {
  27. return false;
  28. }
  29. }
  30. cur = new Node(data);
  31. if (kot(parent->_data) > kot(data))
  32. {
  33. parent->_left = cur;
  34. }
  35. else
  36. {
  37. parent->_right = cur;
  38. }
  39. cur->_parent = parent;
  40. //颜色变更以及旋转.....
  41. }

插入和AVL树插入一样,只不过是后续的旋转由平衡因子的修改变成了颜色的修改,且旋转规则不一样

template<class K, class T, class KeyOfT>

模版中的KeyOfT是为了以后同时实现set和map而做的仿函数因为set是单个key值,而map是pair作key值,所以当map比较数据插入时,pair没有重载比较符> , < , >= , <= , == 所以当map插入值时,需要通过仿函数MapKeyOfT来传递first的值,依靠first的值来判断插入位置。而set只是为了配合map才会有仿函数SetKeyOfT

  1. class map
  2. {
  3. struct MapKeyOfT
  4. {
  5. const K& operator()(const pair<const K, V>& kv)
  6. {
  7. return kv.first;
  8. }
  9. };
  10. }
  11. class set
  12. {
  13. struct SetKeyOfT
  14. {
  15. const K& operator()(const K& key)
  16. {
  17. return key;
  18. }
  19. };
  20. }

此时可以通过定义KeyOfT kot; 来比大小kot(cur->_data) < kot(data) ,实现map时传入的则就是cur->_data->first < data->first

颜色变更以及旋转

分为前面说的三种情况

情况一:cur为红,p为红且在祖父节点左边,g为黑,**u存在且为红

将p,u改为黑,g改为红,然后把g当成cur,继续向上调整**

  1. while (parent && parent->_col == RED)//当cur不是根节点或父节点的颜色是红时
  2. {
  3. Node* grandfather = parent->_parent;
  4. if (grandfather->_left == parent)
  5. {
  6. Node* uncle = grandfather->_right;
  7. // 情况1:u存在且为红,变色处理,并继续往上处理
  8. if (uncle && uncle->_col == RED)
  9. {
  10. parent->_col = BLACK;//p改黑
  11. uncle->_col = BLACK;//u改黑
  12. grandfather->_col = RED;//g改红
  13. // 继续往上调整
  14. cur = grandfather;//g当作c,继续调整
  15. parent = cur->_parent;
  16. }

情况二:cur为红(左p左边),p为红(g左),g为黑,u不存在/u存在且为黑

情况三:cur为红(左p右边),p为红(g左),g为黑,u不存在/u存在且为黑

  1. //代码接上面
  2. else // 情况2+3:u不存在/u存在且为黑,旋转+变色
  3. {
  4. // g
  5. // p u
  6. // c
  7. if (cur == parent->_left)
  8. {
  9. RotateR(grandfather);//右旋
  10. parent->_col = BLACK;
  11. grandfather->_col = RED;
  12. }
  13. else
  14. {
  15. // g
  16. // p u
  17. // c
  18. RotateL(parent);
  19. RotateR(grandfather);
  20. cur->_col = BLACK;
  21. //parent->_col = RED;
  22. grandfather->_col = RED;
  23. }
  24. break;
  25. }
  26. }

情况二:cur为红(右p右边),p为红(g右),g为黑,u不存在/u存在且为黑

情况三:cur为红(右p左边),p为红(g右),g为黑,u不存在/u存在且为黑

  1. //代码接上面
  2. else // (grandfather->_right == parent)
  3. {
  4. // g
  5. // u p
  6. // c
  7. Node* uncle = grandfather->_left;
  8. // 情况1:u存在且为红,变色处理,并继续往上处理
  9. if (uncle && uncle->_col == RED)
  10. {
  11. parent->_col = BLACK;
  12. uncle->_col = BLACK;
  13. grandfather->_col = RED;
  14. // 继续往上调整
  15. cur = grandfather;
  16. parent = cur->_parent;
  17. }
  18. else // 情况2+3:u不存在/u存在且为黑,旋转+变色
  19. {
  20. // g
  21. // u p
  22. // c
  23. if (cur == parent->_right)
  24. {
  25. RotateL(grandfather);
  26. grandfather->_col = RED;
  27. parent->_col = BLACK;
  28. }
  29. else
  30. {
  31. // g
  32. // u p
  33. // c
  34. RotateR(parent);
  35. RotateL(grandfather);
  36. cur->_col = BLACK;
  37. grandfather->_col = RED;
  38. }
  39. break;
  40. }
  41. }
  42. }
  43. _root->_col = BLACK;
  44. return true;
  45. }

旋转——和AVL一样

  1. void RotateL(Node* parent)
  2. {
  3. Node* subR = parent->_right;
  4. Node* subRL = subR->_left;
  5. parent->_right = subRL;
  6. if (subRL)
  7. subRL->_parent = parent;
  8. Node* ppnode = parent->_parent;
  9. subR->_left = parent;
  10. parent->_parent = subR;
  11. if (ppnode == nullptr)
  12. {
  13. _root = subR;
  14. _root->_parent = nullptr;
  15. }
  16. else
  17. {
  18. if (ppnode->_left == parent)
  19. {
  20. ppnode->_left = subR;
  21. }
  22. else
  23. {
  24. ppnode->_right = subR;
  25. }
  26. subR->_parent = ppnode;
  27. }
  28. }
  29. void RotateR(Node* parent)
  30. {
  31. Node* subL = parent->_left;
  32. Node* subLR = subL->_right;
  33. parent->_left = subLR;
  34. if (subLR)
  35. subLR->_parent = parent;
  36. Node* ppnode = parent->_parent;
  37. subL->_right = parent;
  38. parent->_parent = subL;
  39. if (parent == _root)
  40. {
  41. _root = subL;
  42. _root->_parent = nullptr;
  43. }
  44. else
  45. {
  46. if (ppnode->_left == parent)
  47. {
  48. ppnode->_left = subL;
  49. }
  50. else
  51. {
  52. ppnode->_right = subL;
  53. }
  54. subL->_parent = ppnode;
  55. }
  56. }

迭代器的实现 

迭代器结构

  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. Node* _node;
  7. __RBTreeIterator(Node* node)
  8. :_node(node)
  9. {}
  10. // 1、typedef __RBTreeIterator<T, T&, T*> itertaor; 拷贝构造
  11. // 2、typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
  12. // 支持普通迭代器构造const迭代器的构造函数
  13. __RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)
  14. :_node(it._node)
  15. {}

红黑树的迭代器拷贝构造自身节点即可,然后再实现其他各种功能,如-> , * , != , ++ , -- 操作符号重载。

typedef __RBTreeIterator<T, T&, T*> itertaor; 使用迭代器时重命名它,把需要的参数传给模版,Ref为引用,Ptr为解引用,Self为迭代器。

  1. Ref operator*()//T&
  2. {
  3. return _node->_data;
  4. }
  5. Ptr operator->()
  6. {
  7. return &_node->_data;
  8. }//T*
  9. bool operator!=(const Self& s)
  10. {
  11. return _node != s._node;
  12. }

迭代器遍历:++和--

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

右不为空,下一个就是右子树的最左节点

 

右为空,沿着到根的路径,找孩子是父亲左的那个祖先。

 

自减的重载也是如此,把left换成right,right换成left即可

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

注意:这里返回的是Self迭代器类型,也就是对象类型,返回*this

基本的函数调用

begin和end

  1. itertaor begin()
  2. {
  3. Node* cur = _root;
  4. while (cur && cur->_left)//最左边就是begin
  5. {
  6. cur = cur->_left;
  7. }
  8. return itertaor(cur);//返回的迭代器类型要构造cur节点
  9. }
  10. itertaor end()
  11. {
  12. return itertaor(nullptr);
  13. }
  14. const_itertaor begin() const
  15. {
  16. Node* cur = _root;
  17. while (cur && cur->_left)
  18. {
  19. cur = cur->_left;
  20. }
  21. return const_itertaor(cur);//返回的迭代器类型要构造cur节点
  22. }
  23. const_itertaor end() const
  24. {
  25. return const_itertaor(nullptr);
  26. }

begin和end返回的都是迭代器类型,所以要调用迭代器的构造函数,支持普通迭代器构造const迭代器的构造函数,属于权限缩小。

判断平衡、高度、销毁

平衡

  1. public:
  2. bool IsBalance()
  3. {
  4. if (_root && _root->_col == RED)
  5. {
  6. cout << "根节点颜色是红色" << endl;
  7. return false;
  8. }
  9. int benchmark = 0;//算出一条路上的黑节点个数
  10. Node* cur = _root;
  11. while (cur)
  12. {
  13. if (cur->_col == BLACK)
  14. ++benchmark;
  15. cur = cur->_left;
  16. }
  17. // 连续红色节点
  18. return _Check(_root, 0, benchmark);
  19. }
  20. private:
  21. bool _Check(Node* root, int blackNum, int benchmark)
  22. {
  23. if (root == nullptr)
  24. {
  25. if (benchmark != blackNum)
  26. {
  27. cout << "某条路径黑色节点的数量不相等" << endl;
  28. return false;
  29. }
  30. return true;
  31. }
  32. if (root->_col == BLACK)
  33. {
  34. ++blackNum;
  35. }
  36. if (root->_col == RED
  37. && root->_parent
  38. && root->_parent->_col == RED)
  39. {
  40. cout << "存在连续的红色节点" << endl;
  41. return false;
  42. }
  43. return _Check(root->_left, blackNum, benchmark)
  44. && _Check(root->_right, blackNum, benchmark);
  45. }

高度

  1. int _Height(Node* root)
  2. {
  3. if (root == NULL)
  4. return 0;
  5. int leftH = _Height(root->_left);
  6. int rightH = _Height(root->_right);
  7. return leftH > rightH ? leftH + 1 : rightH + 1;
  8. }

销毁

  1. ~RBTree()
  2. {
  3. _Destroy(_root);
  4. _root = nullptr;
  5. }
  6. private:
  7. void _Destroy(Node* root)
  8. {
  9. if (root == nullptr)
  10. {
  11. return;
  12. }
  13. _Destroy(root->_left);
  14. _Destroy(root->_right);
  15. delete root;
  16. }

封装set和map

map

对象结构

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

C++语言默认情况下,假定通过作用域运算符访问的名字不是类型,所以当我们要访问的是类型时候,必须显示的告诉编译器这是一个类型,通过关键字typename来实现这一点。 typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::itertaor iterator;
语句的真是面目是: typedef创建了存在类型的别名,而typename告诉编译器
RBTree<K, pair<const K, V>, MapKeyOfT>::itertaor 是一个类型而不是一个成员。

[ ]重载

begin和end的实现就不用说了,只需要返回_t.begin(); _t.end(); 即可。 而[ ]重载是这样的:

  1. V& operator[](const K& key)
  2. {
  3. pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
  4. return ret.first->second;
  5. //first==iterator first-> == _node->_data first->second==_node->_data->second,也就是V值
  6. }

用一个pair<iterator,bool> 类型来接收插入后的返回结果,以便使用字典的方式插入值。

for (auto& e : map){ countMap[e]++; } 返回的countMap[e]值是_node->_data->second 也就是树中的V值。

我们前面Insert函数相应的也需要改变类型以及返回值

  1. pair<itertaor, bool> Insert(const T& data)
  2. {
  3. //已有data在,插入失败
  4. return make_pair(itertaor(cur), false);
  5. //要用newnode保存一下cur
  6. Node* newnode = cur;
  7. //data不在,插入成功
  8. return make_pair(itertaor(newnode), true);
  9. }

然后调用即可

  1. pair<iterator, bool> insert(const pair<const K, V>& kv)
  2. {
  3. return _t.Insert(kv);
  4. }

set

对象结构

  1. template<class K>
  2. class set
  3. {
  4. struct SetKeyOfT
  5. {
  6. const K& operator()(const K& key)
  7. {
  8. return key;
  9. }
  10. };
  11. public:
  12. typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor iterator;
  13. typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor const_iterator;
  14. private:
  15. RBTree<K, K, SetKeyOfT> _t;

set和map相比只是少了[ ]重载,没什么好说的

  1. iterator begin()
  2. {
  3. return _t.begin();
  4. }
  5. iterator end()
  6. {
  7. return _t.end();
  8. }
  9. pair<iterator, bool> insert(const K& key)
  10. {
  11. return _t.Insert(key);
  12. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/214715?site
推荐阅读
相关标签
  

闽ICP备14008679号