红黑树跟AVL树同样,也是平衡二叉树,其查找、增长、删除效率为O(lgN),红黑树使用很是普遍,C++STL里面的map,set都是用红黑树实现的。html
如下就是一棵红黑树:算法
《算法导论》上定义红黑树需知足如下五个性质:spa
1.每一个结点是黑色或是红色。指针
2.根结点是黑色。code
3.全部叶子节点是黑色(也就是上面Nil结点)htm
4.若是一个节点是红色的,则它的两个子结点都是黑色的。(也就是说父子节点不能同时是红色节点)blog
5.对每一个节点,从该结点到到叶子节点的路径上,均包含相同数目的黑色节点。递归
须要说明一下的是,以上Nil结点是”哨兵节点“,将全部子节点为空的指针都以此Nil节点来代替,并且根节点的父节点也是Nil节点。对于第五条,任一节点到Nil节点的黑色结点个数(包含自己及Nil节点)都相同,也就是所谓的黑高相同。get
先来定义红黑树的节点,红黑树须要一个指示颜色的属性,用一个位bool值来表示就能够了,同时,红黑树还须要根据父节点的颜色来修复红黑树性质,所以须要指向父节点的指针。博客
1 struct RBTreeNode { 2 RBTreeNode* pParent; 3 RBTreeNode* pLeft; 4 RBTreeNode* pRight; 5 bool isRed; 6 int nData; 7 };
同时,定义红黑树的颜色值,以及Nil节点:
1 #define RBTreeNodeBlack false 2 #define RBTreeNodeRed true 3 #define RBTreeNodePtr RBTreeNode* 4 #define RBTreeNilNodePtr &RBTreeNilNode
本节讨论红黑树的插入,由于红黑树也是二叉搜索树,全部红黑树的插入也遵循二叉搜索树插入的过程,只是最后为了保证红黑树的性质,须要在插入后对树进行修正,就像对AVL树执行插入后再再平衡同样。
先来考虑一个问题,新插入一个节点时,这个新插入的节点是用红色的好仍是黑色好?根据红黑树性质5,每一个节点有相同黑高,若是将新插入节点的颜色设为黑色,则树会当即不知足红黑树性质,由于通过这个新插入节点的路径其黑高都会比其它路径多出一来,
因此,要将新插入的节点颜色设为红色,可是对于根节点是个例外。另外,当新插入一个红色节点时,红黑树性质的123均可以获得维持,只有可能破坏性质4和性质5,如下分几种状况来分别讨论新节点插入。
(如下节点当其左右节点为空时,都为Nil节点,而且Nil节点算在节点的黑高里面,此处为了画图简单并未将Nil节点画)
约定新插入节点为N,N的父节点为P,N的祖父节点为G,N的叔节点为U。
1、树为空
这是最简单的状况,直接将新插入节点标为黑色便可
2、父节点是黑色
这是最简单的状况,这个时候,由于父节点是黑色,而新插入节点是红色,全部新插入节点并无增长通过此节点的全部路径黑高,依然知足红黑树全部性质,无需作修正处理。
(N为右节点时也是同样的)
3、父节点是红色
当父节点是红色时,破坏了红黑树的性质4,父子节点不能同时为红色,也正由于性质4,因此祖父节点必定是黑色,否则在插入前不知足红黑树性质4.而叔节点颜色可红可黑对于叔节点颜色按照红和黑两种状况来分开 讨论
一、当叔节点颜色是红色时(N是左节点或右节点都适合此状况)
按上图所示,这个时候,须要将P,U和颜色和G的颜色交换,便可从局部上修正了性质4,并保持性质5,可是这个时候G的颜色由黑变红,可能G的父节点也是红色, 这个时候,就要把G节点按照处理N结点的状况再处理一次。也就是向上传递修复。
2.当U节点是黑色,且N是左节点时
此时,先对G节点执行右旋转操做(不熟悉旋转操做的请看个人上一篇博客AVL树,必定要很是熟悉旋转操做才能理解红黑树),而后交换P,G节点的颜色,便可完成修复,本子树根节点G修复前是黑色,修复后,新的子树根节点P仍然是黑色,至此,修复完毕,无需向上传递。
3.当U节点是黑色,且N是右节点时
由以上由与前一种状况相比,惟一的区别是N是右子节点,因此先对P节点执行左旋转,便可转化成前一种讨论过的状况,而后按前一种状况来处理便可。
好了,红黑树节点的全部状况都在上面了,总的来看并不复杂,树为空和父节点为黑色这两种状况很简单,无需多言,至于下面的几种状况,总结起来就是,如何处理取决于U节点颜色
为红时则交换PU和G的颜色,而后再对G处理。
为黑时分N为左右节点情,为左节点时右旋转G,而后交换P与G的颜色,为右子节点时先左旋转P,而后再按左节点状况进行处理。
红黑树插入代码以下:(代码中的状况一二三四五,以图中的(1)(2)(3)(4)(5)对照)
1 RBTreeNode* RBTreeInsert(RBTreeNode* pRoot, int nData) { 2 if (pRoot == RBTreeNilNodePtr) { 3 pRoot = MakeNewRBTreeNode(RBTreeNilNodePtr, nData); 4 pRoot->isRed = RBTreeNodeBlack; 5 return pRoot; 6 } 7 RBTreeNode* pCursor = pRoot; 8 RBTreeNode* pParent = pRoot->pParent; 9 while (pCursor != RBTreeNilNodePtr) { 10 pParent = pCursor; 11 if (nData > pCursor->nData) { 12 pCursor = pCursor->pRight; 13 } 14 else if (nData < pCursor->nData) { 15 pCursor = pCursor->pLeft; 16 } 17 else 18 break; 19 } 20 if (pCursor == RBTreeNilNodePtr && pParent != RBTreeNilNodePtr) { 21 RBTreeNode* pNode = MakeNewRBTreeNode(pParent, nData); 22 if (nData > pParent->nData) 23 pParent->pRight = pNode; 24 else 25 pParent->pLeft = pNode; 26 27 FixRBTreeNodeColor_Insert(&pRoot, pNode); 28 } 29 return pRoot; 30 } 31 32 void FixRBTreeNodeColor_Insert(RBTreeNode** pRoot, RBTreeNode* pNode) { 33 if (!pNode->isRed) 34 return; 35 36 RBTreeNode* pParent = pNode->pParent; 37 if (pParent == RBTreeNilNodePtr) { 38 //第一种状况 39 pNode->isRed = RBTreeNodeBlack; 40 return; 41 } 42 else if (!pParent->isRed || pParent->pParent == RBTreeNilNodePtr)//pParent->pParent == RBTreeNilNodePtr为第二种状况 43 return; 44 RBTreeNode* pGrandParent = pParent->pParent; 45 if (pParent == pGrandParent->pLeft) { 46 RBTreeNode* pUncle = pGrandParent->pRight; 47 if (pUncle != RBTreeNilNodePtr) { 48 if (pUncle->isRed) { 49 //状况3:不须要旋转操做,直接交换颜色,而后往上递归检查 50 pParent->isRed = pUncle->isRed = RBTreeNodeBlack; 51 pGrandParent->isRed = RBTreeNodeRed; 52 return FixRBTreeNodeColor_Insert(pRoot, pGrandParent); 53 } 54 } 55 if (pNode == pParent->pRight) { 56 //状况5,先左旋pParent转换成状况4 57 RBTreeLeftRotate(pRoot, pParent); 58 } 59 //状况4 60 pGrandParent = RBTreeRightRotate(pRoot, pGrandParent); 61 SwapRBTreeNodeColor(pGrandParent, pGrandParent->pRight); 62 } 63 else { 64 //上面if分支的镜像 65 RBTreeNode* pUncle = pGrandParent->pLeft; 66 if (pUncle != RBTreeNilNodePtr) { 67 if (pUncle->isRed) { 68 //状况3:不须要旋转操做,直接交换颜色,而后往上递归检查 69 pParent->isRed = pUncle->isRed = RBTreeNodeBlack; 70 pGrandParent->isRed = RBTreeNodeRed; 71 return FixRBTreeNodeColor_Insert(pRoot, pGrandParent); 72 } 73 } 74 if (pNode == pParent->pLeft) { 75 //状况5,先右旋pParent转换成状况4 76 RBTreeRightRotate(pRoot, pParent); 77 } 78 //状况4 79 pGrandParent = RBTreeLeftRotate(pRoot, pGrandParent); 80 SwapRBTreeNodeColor(pGrandParent, pGrandParent->pLeft); 81 } 82 }