赞
踩
红黑树是map,set,mutilmap,mutilset容器的底层数据结构,也是一种非常重要的数据结构,它在效率上对AVL又做了进一步的优化,因为AVL结构在插入,或删除时,无法避免大量的旋转操作,导致效率有所损耗,但是红黑树,就在这一点有了更好的优化,但是牺牲了平衡性,所以是不是一个完全平衡的二叉搜索树。
概念:
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
性质:
1、根节点是黑色的
2、每个节点不是红色的就是黑色的
3、红色节点的子节点一定是黑色的
4、红色节点不能相连
5、从任意节点出发,它每一条路径上的黑色节点数目是相同的
这里有一条总结红黑树的顺口溜:
一头一脚黑,
黑连红不连。
插入看叔伯,
删除看兄弟。
这四句话就概括了红黑树的所有性质,以及插入和删除时应该怎样处理的情况。
#include<iostream> #include<stack> #include<vector> using namespace std; enum Color{BLACK = 0,RED = 1}; //设置颜色 template<typename Type> //类的前向声明,不然因为编译器版本原因可能在声明友元类的时候出错 class RBTree; template<typename Type> class RBTreeNode { friend class RBTree<Type>; //成为友元类,可以访问节点私有成员 public: RBTreeNode(Type val = Type()) :_rightChild(nullptr),_leftChild(nullptr),_parent(nullptr),_Val(val),_color(RED) {} ~RBTreeNode() {} private: Type _Val; RBTreeNode<Type>* _rightChild; RBTreeNode<Type>* _leftChild; RBTreeNode<Type>* _parent; Color _color; }; template<typename Type> class RBTree { public: RBTree():Nul(_BuyNode()),_root(Nul) { Nul->_leftChild = Nul->_rightChild = Nul->_parent = nullptr; Nul->_color = BLACK; } protected: RBTreeNode<Type>* _BuyNode(const Type val = Type()) { RBTreeNode<Type>* s = new RBTreeNode<Type>(val); s->_leftChild = s->_rightChild = Nul; return s; } private: RBTreeNode<Type>* Nul; RBTreeNode<Type>* _root; };
我们有两个类,一个类是我们的红黑树类,另一个类是叶子节点类
红黑树类:
有两个成员,这里就有红黑树的另一个人为的看法,就是所有空节点,都为黑色节点,根一定是黑色节点,所以在初始化的时候我们不能没有根,初始化时一定要有一个黑色节点作为根节点,那么就有了为什么除了 _root以外还有一个节点作为空节点,所有空节点都指向这个节点。
然后呢,我们为了调整时方便,多使用了一个父指针,指向自己的父节点,因为不用这个的话,未来插入,删除都将变的超级麻烦!后面会有说到。
这里我们就不需要再像AVL树一样写四个旋转方法了,因为初学,所以我们需要详细一点,现在我们直接选择同时调用左单旋和右单旋实现双旋转,这样就不需要重复实现了。提高了代码的复用性。
因为我们在旋转之前就已经完成了颜色的修改,所以我们只需要进行单纯的旋转即可
template<typename Type> void RBTree<Type>::RotateR(RBTreeNode<Type>*& t, RBTreeNode<Type>* p) { RBTreeNode<Type>* s = p->_leftChild; /*判断即将要旋转的位置是否有左子树,有的话就将其挂在未来旋转过来的节点的右子树上 其次。如果没有,因为开头说过,所有节点的空节点,都指向了我们自己设置的空节点Nul, 所以只需要让p的右子树指向它就好了。*/ if (s->_rightChild != Nul) s->_rightChild->_parent = p; p->_leftChild = s->_rightChild; s->_parent = p->_parent; if (p->_parent == Nul) //被旋转的节点是根节点 t = s; else if (p == p->_parent->_leftChild) //不是根节点,判断是左子树还是右子树进行连接 p->_parent->_leftChild = s; else p->_parent->_rightChild = s; s->_rightChild = p; //将节点的其他指针调整指向 p->_parent = s; }
为什么这次不同于AVL树使用引用传需要被旋转的值呢,从代码可以知道,这次直接在旋转的同时完成了连接,具体步骤的意义会标识在代码中,这样看着比较方便。
void RBTree<Type>::RotateL(RBTreeNode<Type>*& t, RBTreeNode<Type>* p) { RBTreeNode<Type>* s = p->_rightChild; /*判断即将要旋转的位置是否有左子树,有的话就将其挂在未来旋转过来的节点的右子树上 其次。如果没有,因为开头说过,所有节点的空节点,都指向了我们自己设置的空节点Nul, 所以只需要让p的右子树指向它就好了。*/ if (s->_leftChild != Nul) s->_leftChild->_parent = p; p->_rightChild = s->_leftChild; s->_parent = p->_parent; if (p->_parent == Nul) //被旋转的节点是根节点 t = s; else if (p == p->_parent->_leftChild) //不是根节点,判断是左子树还是右子树进行连接 p->_parent->_leftChild = s; else p->_parent->_rightChild = s; s->_leftChild = p; //将节点的其他指针调整指向 p->_parent = s; }
template<typename Type> void RBTree<Type>::_Insert(RBTreeNode<Type>* &t, const Type val) { RBTreeNode<Type>* p = t; RBTreeNode<Type>* pr = Nul; while (p != Nul) //寻找插入位置 { if (val == p->_Val) //不接受相同数据 return; pr = p; if (val > p->_Val) p = p->_rightChild; else p = p->_leftChild; } p = _BuyNode(val); if (pr == Nul) // 插入的是第一个根节点 { t = p; t->_parent = pr; } if (val > pr->_Val) pr->_rightChild = p; else pr->_leftChild = p; p->_parent = pr; /*调整平衡*/ In_balance(t, p); } template<typename Type> void RBTree<Type>::In_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m) { while (m->_parent->_color == RED) { RBTreeNode<Type>* u; //uncle节点 if (m->_parent == m->_parent->_parent->_leftChild) //左分支 { u = m->_parent->_parent->_rightChild; if (u->_color == RED) //状况三 uncle为红色节点 { m->_parent->_color = BLACK; m->_parent->_parent->_color = RED; u->_color = BLACK; m = m->_parent->_parent; } else //uncle为黑色节点 { if (m == m->_parent->_rightChild) //状况二 { m = m->_parent; RotateL(t, m); } m->_parent->_color = BLACK; //状况一 m->_parent->_parent->_color = RED; RotateR(t, m->_parent->_parent); } } else //右分支 { u = m->_parent->_parent->_leftChild; if (u->_color == RED) //uncle为红色节点 { //状况三 m->_parent->_color = BLACK; m->_parent->_parent->_color = RED; u->_color = BLACK; m = m->_parent->_parent; } else //uncle为黑色节点 { if (m == m->_parent->_leftChild) //状况二 { m = m->_parent; RotateR(t, m); } m->_parent->_color = BLACK; //状况一 m->_parent->_parent->_color = RED; RotateL(t, m->_parent->_parent); } } } t->_color = BLACK; //不管如何调整,根节点一定是黑色 }
寻找插入位置就不多说了,仔细看一下就会了,主要说一下调整平衡这里:
uncle可能存在也可能不存在,无所谓,不存在的话在我们设置的时候也是指向我们自己设置的黑色空节点Nul
情况一 插入节点在外侧插入(单旋转)
我们只需要先将其父节点改为黑色,祖父节点改为红色,在进行单旋转即可达到平衡
情况二 插入节点在内侧插入(双旋转)
先将其进行一次单旋转,使其变成情况一,再通过情况一着色,旋转,达到平衡,这里有一个小细节,就是我们需要提前将m节点追到m的父节点,因为我们的目标就是要让其成为情况一,仔细看过旋转函数的同学一定都发现了,旋转完之后父节点会转下去,所以我们需要根据旋转函数体现追到父节点,使其旋转过后成为情况一
这时我们的处理比较简单,我们只需要将其father节点和uncle节点的颜色改为黑色,grandfather节点的颜色改为红色,然后继续向上调整即可,这时又会转换成上面的情况一或者情况二,再根据相应的调整方式进行调整即可
template<class Type> void RBTree<Type>::_Remove(RBTreeNode<Type>*& t, const Type val) { RBTreeNode<Type>* p = t; while (p != Nul) //寻找要被删除的节点 { if (p->_Val == val) break; if (val > p->_Val) p = p->_rightChild; else p = p->_leftChild; } RBTreeNode<Type>* q; if (p == Nul) //被删除节点不存在 return; if (p->_leftChild != Nul && p->_rightChild != Nul) //被删除节点有左右子树 { q = p->_leftChild; while (q->_rightChild != Nul) q = q->_rightChild; p->_Val = q->_Val; p = q; } if (p->_leftChild != Nul) //被删除节点只有一个子树 q = p->_leftChild; else q = p->_rightChild; q->_parent = p->_parent; //将q节点挂到被删除的节点的父节点的子树上 if (q->_parent == Nul) // 被删除的是根节点 { t = q; t->_color = BLACK; delete p; return; } if (p == p->_parent->_leftChild) //父节点在对应的左树或者右树连接p的子树 p->_parent->_leftChild = q; else p->_parent->_rightChild = q; /*调整平衡*/ if (p->_color == BLACK) { if (q != Nul) //组合四: 直接互换颜色,删除p节点即可 q->_color = BLACK; else //组合二 Re_balance(t, q); } delete p; } template<class Type> void RBTree<Type>::Re_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m) { while (m != t) { RBTreeNode<Type>* b; if (m == m->_parent->_leftChild) //左分支 { b = m->_parent->_rightChild; /*——— 情形四 ———*/ if (b->_color == RED) { b->_color = BLACK; m->_parent->_color = RED; RotateL(t, m->_parent); b = m->_parent->_rightChild; } /*——— 情形三 ———*/ if (b->_leftChild->_color != RED && b->_rightChild->_color != RED) { b->_color = RED; if (m->_parent->_color == RED) { m->_parent->_color = BLACK; m = t; } else m = m->_parent; //向上回溯,继续判断 } else { /*——— 情形二 ———*/ if (b->_leftChild->_color == RED) { b->_color = RED; b->_leftChild->_color = BLACK; RotateR(t, b); b = b->_parent; } /*——— 情形一 ———*/ b->_color = m->_parent->_color; m->_parent->_color = BLACK; b->_rightChild->_color = BLACK; RotateL(t, m->_parent); m = t; } } else //右分支 { b = m->_parent->_leftChild; /*——— 情形四 ———*/ if (b->_color == RED) { b->_color = BLACK; m->_parent->_color = RED; RotateR(t, m->_parent); m = m->_parent; } /*——— 情形三 ———*/ if (b->_leftChild->_color != RED && b->_rightChild->_color != RED) { b->_color = RED; if (m->_parent->_color = RED) { m->_parent->_color = BLACK; m = t; } else m = m->_parent; } else { /*——— 情形二 ———*/ if (b->_rightChild->_color == RED) { b->_color = RED; b->_rightChild->_color = BLACK; RotateL(t, b); b = b->_parent; } /*——— 情形一 ———*/ b->_color = m->_parent->_color; m->_parent->_color = BLACK; b->_leftChild->_color = BLACK; RotateR(t, m->_parent); m = t; } } t->_color = BLACK; } }
如何寻找删除位置以及,被删除节点的子节点的处理,跟AVL树相同,都将其化成至多只有一个子树 或者 没有子树的情况,所以这里就不在多说,主要说一下,删除时,不同颜色,不同位置的节点,如何进行删除。
情况一:
删除节点为RED节点,并且为叶子节点,那么直接删除即可
情况二:
删除节点为RED节点,只有一个叶子节点
解释:
这种情况是不存在的,不然会导致其违背红黑树的性质——每条路径上的黑色节点数目相同;又或者违背红黑树的性质——红色节点不能相连
情况三:
删除节点为BLACK节点,只有一个叶子节点
解释:
该节点的叶子节点颜色只能为RED,如果是BLACK节点,还是会违背红黑树的性质——每条路径上的黑色节点数目相同,所以,只能是RED叶子节点,那么直接将叶子节点颜色改为BLACK,用叶子节点代替被删除节点的位置,即可达到平衡
情况四、五
被删除节点有两个节点,这里被删除节点可能为RED或者BLACK
解释:
这里的替换寻找都与AVL树相同,这里节点颜色不一定就是这个样子,只是举例而已,所以不在多说,替换之后,情况四、五将转化成情况三 或者 情况六
情况六
删除节点为BLACK节点,且没有子节点。
这种情况下又有四种情形:
情形一:
被删除节点的brother节点有一个于其方向相同的子节点
解释:
先将father节点和brother节点的颜色互换,然后对father节点进行一次左旋转,然后将mine节点删除,就可以达到平衡。
情形二:
被删除节点的brother节点有一个于其方向相反的子节点
解释:
首先,先将brother节点与son节点颜色互换,然后对brother节点进行一次右旋转,这时,就变成了情形一,再进行情形一的操作,就可以达到平衡
情形三
brother节点没有红色子节点
解释:
当father节点为红色时,先将brother颜色改为红色然后将father节点颜色改为黑色,最后将mine节点删除即可达到平衡
解释:
这里细心的小伙伴可以看到,father节点从圆形变成了黑色,这里叫做“双重黑色”,它是我们假定的黑色,它并不是真实存在的,而是我们自己主观的想象,这种情况的出现是mine节点将自己的黑色给了father节点,这样我们就当作它平衡了,它黑色减少了,但是father本来就是黑色,然后现在有多了一重,所以是双重黑色,那么理所当然,我们需要删掉这个多余的黑色,所以需要将brother节点颜色改为红色然后继续向上回溯,继续调整平衡。
情况四
brother节点为红色
解释:
先将father和brother节点的颜色进行调整,然后对father节点进行左旋,这时,新的brother节点就是son节点,这就转化成brother节点为BLACK的情况,这样就可以转化成上面其他几种情况来进行响应的调整。
#include<iostream> #include<stack> #include<vector> using namespace std; enum Color { BLACK = 0, RED = 1 }; //设置颜色 template<typename Type> //类的前向声明,不然因为编译器版本原因可能在声明友元类的时候出错 class RBTree; template<typename Type> class RBTreeNode { friend class RBTree<Type>; //成为友元类,可以访问节点私有成员 public: RBTreeNode(Type val = Type()) :_rightChild(nullptr), _leftChild(nullptr), _parent(nullptr), _Val(val), _color(RED) {} ~RBTreeNode() {} private: Type _Val; Color _color; RBTreeNode<Type>* _rightChild; RBTreeNode<Type>* _leftChild; RBTreeNode<Type>* _parent; }; template<typename Type> class RBTree { public: RBTree() :Nul(_BuyNode()), _root(Nul) { Nul->_leftChild = Nul->_rightChild = Nul->_parent = nullptr; Nul->_color = BLACK; } public: void Insert(Type val = Type()) { _Insert(_root, val); } void Remove(Type val = Type()) { _Remove(_root, val); } protected: void _Insert(RBTreeNode<Type>*& t,const Type val); void In_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m); void _Remove(RBTreeNode<Type>*& t, const Type val); void Re_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m); void RotateL(RBTreeNode<Type>*& t, RBTreeNode<Type>* p); void RotateR(RBTreeNode<Type>*& t, RBTreeNode<Type>* p); protected: RBTreeNode<Type>* _BuyNode(const Type val = Type()) { RBTreeNode<Type>* s = new RBTreeNode<Type>(val); s->_leftChild = s->_rightChild = Nul; return s; } private: RBTreeNode<Type>* Nul; RBTreeNode<Type>* _root; }; template<typename Type> void RBTree<Type>::RotateL(RBTreeNode<Type>*& t, RBTreeNode<Type>* p) { RBTreeNode<Type>* s = p->_rightChild; if (s->_leftChild != Nul) s->_leftChild->_parent = p; p->_rightChild = s->_leftChild; s->_parent = p->_parent; if (p->_parent == Nul) t = s; else if (p == p->_parent->_leftChild) p->_parent->_leftChild = s; else p->_parent->_rightChild = s; s->_leftChild = p; p->_parent = s; } template<typename Type> void RBTree<Type>::RotateR(RBTreeNode<Type>*& t, RBTreeNode<Type>* p) { RBTreeNode<Type>* s = p->_leftChild; if (s->_rightChild != Nul) s->_rightChild->_parent = p; p->_leftChild = s->_rightChild; s->_parent = p->_parent; if (p->_parent == Nul) t = s; else if (p == p->_parent->_leftChild) p->_parent->_leftChild = s; else p->_parent->_rightChild = s; s->_rightChild = p; p->_parent = s; } template<typename Type> void RBTree<Type>::_Insert(RBTreeNode<Type>* &t, const Type val) { RBTreeNode<Type>* p = t; RBTreeNode<Type>* pr = Nul; while (p != Nul) //寻找插入位置 { if (val == p->_Val) //不接受相同数据 return; pr = p; if (val > p->_Val) p = p->_rightChild; else p = p->_leftChild; } p = _BuyNode(val); if (pr == Nul) // 插入的是第一个根节点 { t = p; t->_parent = pr; } if (val > pr->_Val) pr->_rightChild = p; else pr->_leftChild = p; p->_parent = pr; /*调整平衡*/ In_balance(t, p); } template<typename Type> void RBTree<Type>::In_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m) { while (m->_parent->_color == RED) { RBTreeNode<Type>* u; //uncle节点 if (m->_parent == m->_parent->_parent->_leftChild) //左分支 { u = m->_parent->_parent->_rightChild; if (u->_color == RED) //状况三 uncle为红色节点 { m->_parent->_color = BLACK; m->_parent->_parent->_color = RED; u->_color = BLACK; m = m->_parent->_parent; } else //uncle为黑色节点 { if (m == m->_parent->_rightChild) //状况二 { m = m->_parent; RotateL(t, m); } m->_parent->_color = BLACK; //状况一 m->_parent->_parent->_color = RED; RotateR(t, m->_parent->_parent); } } else //右分支 { u = m->_parent->_parent->_leftChild; if (u->_color == RED) //uncle为红色节点 { //状况三 m->_parent->_color = BLACK; m->_parent->_parent->_color = RED; u->_color = BLACK; m = m->_parent->_parent; } else //uncle为黑色节点 { if (m == m->_parent->_leftChild) //状况二 { m = m->_parent; RotateR(t, m); } m->_parent->_color = BLACK; //状况一 m->_parent->_parent->_color = RED; RotateL(t, m->_parent->_parent); } } } t->_color = BLACK; } template<class Type> void RBTree<Type>::_Remove(RBTreeNode<Type>*& t, const Type val) { RBTreeNode<Type>* p = t; while (p != Nul) { if (p->_Val == val) break; if (val > p->_Val) p = p->_rightChild; else p = p->_leftChild; } RBTreeNode<Type>* q; if (p == Nul) //被删除节点不存在 return; if (p->_leftChild != Nul && p->_rightChild != Nul) //被删除节点有左右子树 { q = p->_leftChild; while (q->_rightChild != Nul) q = q->_rightChild; p->_Val = q->_Val; p = q; } if (p->_leftChild != Nul) //被删除节点只有一个子树 q = p->_leftChild; else q = p->_rightChild; q->_parent = p->_parent; //将q节点挂到被删除的节点的父节点的子树上 if (q->_parent == Nul) // 被删除的是根节点 { t = q; t->_color = BLACK; delete p; return; } if (p == p->_parent->_leftChild) //父节点在对应的左树或者右树连接p的子树 p->_parent->_leftChild = q; else p->_parent->_rightChild = q; /*调整平衡*/ if (p->_color == BLACK) { if (q != Nul) //组合四: 直接互换颜色,删除p节点即可 q->_color = BLACK; else //组合二 Re_balance(t, q); } delete p; } template<class Type> void RBTree<Type>::Re_balance(RBTreeNode<Type>*& t, RBTreeNode<Type>*& m) { while (m != t) { RBTreeNode<Type>* b; if (m == m->_parent->_leftChild) //左分支 { b = m->_parent->_rightChild; /*——— 情形四 ———*/ if (b->_color == RED) { b->_color = BLACK; m->_parent->_color = RED; RotateL(t, m->_parent); b = m->_parent->_rightChild; } /*——— 情形三 ———*/ if (b->_leftChild->_color != RED && b->_rightChild->_color != RED) { b->_color = RED; if (m->_parent->_color == RED) { m->_parent->_color = BLACK; m = t; } else m = m->_parent; //向上回溯,继续判断 } else { /*——— 情形二 ———*/ if (b->_leftChild->_color == RED) { b->_color = RED; b->_leftChild->_color = BLACK; RotateR(t, b); b = b->_parent; } /*——— 情形一 ———*/ b->_color = m->_parent->_color; m->_parent->_color = BLACK; b->_rightChild->_color = BLACK; RotateL(t, m->_parent); m = t; } } else //右分支 { b = m->_parent->_leftChild; //兄弟节点 /*——— 情形四 ———*/ if (b->_color == RED) { b->_color = BLACK; m->_parent->_color = RED; RotateR(t, m->_parent); m = m->_parent; } /*——— 情形三 ———*/ if (b->_leftChild->_color != RED && b->_rightChild->_color != RED) { b->_color = RED; if (m->_parent->_color = RED) { m->_parent->_color = BLACK; m = t; } else m = m->_parent; } else { /*——— 情形二 ———*/ if (b->_rightChild->_color == RED) { b->_color = RED; b->_rightChild->_color = BLACK; RotateL(t, b); b = b->_parent; } /*——— 情形一 ———*/ b->_color = m->_parent->_color; m->_parent->_color = BLACK; b->_leftChild->_color = BLACK; RotateR(t, m->_parent); m = t; } } t->_color = BLACK; } } int main() { RBTree<int> Rb; vector<int> iv = { 10, 7, 8, 15, 5, 6, 11, 13, 12 }; for (int i = 0; i < iv.size(); ++i) { Rb.Insert(iv[i]); } Rb.Remove(11); Rb.Remove(13); Rb.Remove(8); Rb.Remove(12); Rb.Remove(6); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。