红黑树(Red Black Tree)是一种特殊的二叉查找树(Binary Search Tree),满则如下红黑性质的二叉树是红黑树:
1.每个节点或是红的,或是黑的
2.根节点是黑的
3.每个叶节点(NIL)是黑的
4.如果一个节点是红的,则它的两个儿子都是黑的
5.对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑节点。
由于以上的性质,红黑树的效率能保证在log级别,而不会像普通的BST一样退化为线性的O(n)。
从红黑树的定义可以看出:
1.红黑树是一棵BST,满足BST的所有性质:左子树所有节点的值都不超过根节点,右子树所有节点的值都不小于根节点;中序遍历是升序的;...
2.若某节点是红色的,则必有黑父(黑色的父节点,下文中“红父”“黑叔”“红叔”等类推),且其两个子节点必为黑色(包括子节点为哨兵NIL的情况)
3.不存在两个连续的红色节点相连接,但连续两个黑节点可以存在;
...
在Linux中,不少地方使用了红黑树(C语言实现),在sourceforge等网站上可以参考其代码。
用C++实现红黑树,网上不少代码都参考了《算法导论》一书,其insert操作的讲解都正确无误,但删除操作总是含混不清,我认为原因在于不少讲解中都忽略了以下几点:
1.叶子节点(NIL)是哨兵,不是NULL,两者不应混淆
2.叶节点不应该被忽略(例如“人”子型的树,不是红黑树)
ok,明确以上两点过后,实现一棵红黑树应该不会太难了,下面贴出从罗索实验室找到的代码,链接的地址是http://www.rosoo.net/a/201207/16151.html
#pragma once #ifdef MY_DEBUG #include #include "assert.h" #endif //MY_DEBUG namespace ScanbuyLib{ enum rg_color { black, red } ; enum e_balance { left_higher, equal_height, right_higher }; enum e_return { e_success, e_fail, e_empty, e_duplicate, e_not_found }; enum e_order { e_preorder, e_inorder, e_postorder }; template class RBTreeNode { public: RBTreeNode(rg_color color = black); RBTreeNode(const K& key, const V& value, rg_color color= black); public: RBTreeNode* m_pRChild; RBTreeNode* m_pLChild; RBTreeNode* m_pParent; K key; V value; rg_color color; }; template RBTreeNode::RBTreeNode(rg_color color) { m_pRChild = NULL; m_pLChild = NULL; m_pParent = NULL; // key = K(0); // value = V(0); this->color = color; } templateRBTreeNode::RBTreeNode(const K& key, const V& value, rg_color color) { m_pRChild = NULL; m_pLChild = NULL; m_pParent = NULL; this->key = key; this->value = value; this->color = color; } template class RedBlackTree { public: RedBlackTree(); ~RedBlackTree(); e_return insert(const K& key, const V& value); e_return remove(const K& key); e_return search(const K& key, V& value); // value as output private: void destroy(RBTreeNode* pNode); // make copy constructor and = operator private currently. RedBlackTree(const RedBlackTree&); RedBlackTree& operator = (const RedBlackTree& other); RBTreeNode* getGrandParent(RBTreeNode* pNode); RBTreeNode* getUncle(RBTreeNode* pNode); RBTreeNode* getSibling(RBTreeNode* pNode); #ifdef MY_DEBUG bool checkCorrectNess(); #endif //MY_DEBUG void insertFixup(RBTreeNode* pNode); void removeFixup(RBTreeNode* pNode); void rotateLeft (RBTreeNode* pNode); void rotateRight(RBTreeNode* pNode); RBTreeNode* m_pRoot; RBTreeNode* m_pSentinel; }; template RedBlackTree::RedBlackTree() { // first instantiate the sentinel node, then make it root as sentinel m_pSentinel = new RBTreeNode(); m_pSentinel->m_pLChild = NULL; m_pSentinel->m_pRChild = NULL; m_pSentinel->m_pParent = NULL; m_pSentinel->color = black; m_pRoot = m_pSentinel; } template RedBlackTree::~RedBlackTree() { // TODO, need to add it once really use it!!!! destroy(m_pRoot); if (m_pSentinel) { delete m_pSentinel; m_pSentinel = NULL; } } template void RedBlackTree::destroy(RBTreeNode* pNode) { if (pNode != NULL && pNode != m_pSentinel) { destroy(pNode->m_pLChild); destroy(pNode->m_pRChild); delete pNode; pNode = NULL; } } template RBTreeNode* RedBlackTree::getGrandParent(RBTreeNode* pNode) { if (pNode && pNode->m_pParent) return pNode->m_pParent->m_pParent; else return NULL; } template RBTreeNode* RedBlackTree::getUncle(RBTreeNode* pNode) { RBTreeNode* pTemp = getGrandParent(pNode); if (pTemp == NULL) return NULL; // No grandparent means no uncle if (pNode->m_pParent == pTemp->m_pLChild) return pTemp->m_pRChild; else return pTemp->m_pLChild; } template RBTreeNode* RedBlackTree::getSibling(RBTreeNode* pNode) { if (pNode == NULL || pNode->m_pParent == NULL) return NULL; if (pNode == pNode->m_pParent->m_pLChild) return pNode->m_pParent->m_pRChild; else return pNode->m_pParent->m_pLChild; } template void RedBlackTree::rotateLeft(RBTreeNode* pNode) { if (pNode == NULL || pNode->m_pRChild == NULL) return; else { RBTreeNode* pTemp = pNode->m_pRChild; pNode->m_pRChild = pTemp->m_pLChild; if (pTemp->m_pLChild) pTemp->m_pLChild->m_pParent = pNode; if (pNode == m_pRoot) { m_pRoot = pTemp; pTemp->m_pParent = NULL; } else { pTemp->m_pParent= pNode->m_pParent; if (pNode == pNode->m_pParent->m_pLChild) { pNode->m_pParent->m_pLChild = pTemp; } else { pNode->m_pParent->m_pRChild = pTemp; } } pTemp->m_pLChild = pNode; pNode->m_pParent = pTemp; } } template void RedBlackTree::rotateRight(RBTreeNode* pNode) { if (pNode == NULL || pNode->m_pLChild == NULL) return; else { RBTreeNode* pTemp = pNode->m_pLChild; pNode->m_pLChild = pTemp->m_pRChild; if (pTemp->m_pRChild) pTemp->m_pRChild->m_pParent = pNode; if (pNode == m_pRoot) { m_pRoot = pTemp; pTemp->m_pParent = NULL; } else { //update the parent pTemp->m_pParent= pNode->m_pParent; if (pNode == pNode->m_pParent->m_pLChild) { pNode->m_pParent->m_pLChild = pTemp; } else { pNode->m_pParent->m_pRChild = pTemp; } } pTemp->m_pRChild = pNode; pNode->m_pParent = pTemp; } } template e_return RedBlackTree::insert(const K& key, const V& value) { RBTreeNode* pTemp = m_pRoot; RBTreeNode* pParent = NULL; // init the new node here RBTreeNode* pNew = new RBTreeNode(key, value); pNew->color = red; pNew->m_pLChild = m_pSentinel; pNew->m_pRChild = m_pSentinel; // find the insert point while (pTemp != m_pSentinel) { pParent = pTemp; if (pTemp->key == key) { delete pNew; return e_duplicate; } pTemp = pTemp->key > key ? pTemp->m_pLChild: pTemp->m_pRChild; } if (m_pRoot == m_pSentinel) { m_pRoot = pNew; m_pRoot->m_pParent = NULL; } else { pNew->m_pParent = pParent; if ( pParent->key > key ) { pParent->m_pLChild= pNew; } else { pParent->m_pRChild= pNew; } } insertFixup(pNew); // insertCase1(pNew); #ifdef MY_DEBUG assert(checkCorrectNess()); #endif//MY_DEBUG return e_success; } template void RedBlackTree::insertFixup(RBTreeNode* pNode) { if (pNode == NULL) return; // impossible actually. RBTreeNode* pUncle = m_pSentinel; RBTreeNode* pGrandParent = NULL; while (pNode != m_pRoot && red == pNode->m_pParent->color) { pUncle = getUncle(pNode); pGrandParent = getGrandParent(pNode); if (pUncle != m_pSentinel && pUncle->color == red) { pNode->m_pParent->color = black; pUncle->color = black; pGrandParent->color = red; pNode = pGrandParent; } else { if (pNode->m_pParent == pGrandParent->m_pLChild) { if (pNode == pNode->m_pParent->m_pRChild) { pNode = pNode->m_pParent; rotateLeft(pNode); } pNode->m_pParent->color = black; pGrandParent->color = red; rotateRight(pGrandParent); } else { if (pNode == pNode->m_pParent->m_pLChild) { pNode = pNode->m_pParent; rotateRight(pNode); } pNode->m_pParent->color = black; pGrandParent->color = red; rotateLeft(pGrandParent); } } } m_pRoot->color = black; } template e_return RedBlackTree::remove(const K& key) { // currently we won't use the if (!m_pRoot) return e_empty; RBTreeNode* pd = m_pRoot; // pd means pointer to the node deleted (with the same data with param:data) while (pd != m_pSentinel) { if (pd->key > key) pd = pd->m_pLChild; else if (pd->key < key) pd = pd->m_pRChild; else break; // equal so we find it!!! } if (pd == m_pSentinel) //haven't find it return e_not_found; // delete is not the real node to delete, but find a sub to replace and remove the sub RBTreeNode* pSub = NULL; // pSub is the really node to be sub // we can either find the max left child or min right child to sub // let's choose max left child here if (pd->m_pLChild == m_pSentinel && pd->m_pRChild == m_pSentinel) pSub = pd; else if (pd->m_pLChild == m_pSentinel) pSub = pd->m_pRChild; else if (pd->m_pRChild == m_pSentinel) pSub = pd->m_pLChild; else { pSub = pd->m_pLChild; // let's find the max left child while (pSub->m_pRChild != m_pSentinel) { pSub = pSub->m_pRChild; } } // replace the pd data with pSub's if (pd != pSub) { pd->key = pSub->key; pd->value = pSub->value; } // then find the child of sub and replace with sub RBTreeNode* pSubChild = pSub->m_pRChild != m_pSentinel ? pSub->m_pRChild: pSub->m_pLChild; if (pSub->m_pParent) { if (pSub == pSub->m_pParent->m_pLChild) pSub->m_pParent->m_pLChild = pSubChild; else pSub->m_pParent->m_pRChild = pSubChild; } else { m_pRoot = pSubChild; } //this may change the sentinel's parent to not-null value, will change to NULL later pSubChild->m_pParent = pSub->m_pParent; if (pSub->color == black) removeFixup(pSubChild); if (pSub) { delete pSub; pSub = NULL; } // rollback sentinel's parent to NULL; m_pSentinel->m_pParent = NULL; #ifdef MY_DEBUG assert(checkCorrectNess()); #endif //MY_DEBUG return e_success; } template void RedBlackTree::removeFixup(RBTreeNode* pNode) { RBTreeNode* pSibling = NULL; while ((pNode != m_pRoot) && (pNode->color == black)) { pSibling = getSibling(pNode); if (pNode == pNode->m_pParent->m_pLChild) // left child node { if (pSibling->color == red) { // case 1, can change to case 2, 3, 4 pNode->m_pParent->color = red; pSibling->color = black; rotateLeft(pNode->m_pParent); // change to new sibling, pSibling = pNode->m_pParent->m_pRChild; } // case 2; if ((black == pSibling->m_pLChild->color) && (black == pSibling->m_pRChild->color)) { pSibling->color = red; pNode = pNode->m_pParent; } else { if (black == pSibling->m_pRChild->color) { pSibling->color = red; pSibling->m_pLChild->color = black; rotateRight(pSibling); pSibling = pNode->m_pParent->m_pRChild; } pSibling->color = pNode->m_pParent->color; pNode->m_pParent->color = black; pSibling->m_pRChild->color = black; rotateLeft(pNode->m_pParent); break; } } else { if (pSibling->color == red) { // case 1, can change to case 2, 3, 4 pNode->m_pParent->color = red; pSibling->color = black; rotateRight(pNode->m_pParent); // change to new sibling, pSibling = pNode->m_pParent->m_pLChild; } // case 2; if ((black == pSibling->m_pLChild->color) && (black == pSibling->m_pRChild->color)) { pSibling->color = red; pNode = pNode->m_pParent; } else { if (black == pSibling->m_pLChild->color) { pSibling->color = red; pSibling->m_pRChild->color = black; rotateLeft(pSibling); pSibling = pNode->m_pParent->m_pLChild; } pSibling->color = pNode->m_pParent->color; pNode->m_pParent->color = black; pSibling->m_pLChild->color = black; rotateRight(pNode->m_pParent); break; } } } pNode->color = black; } template e_return RedBlackTree::search(const K& key, V& value) // value as output { if (!m_pRoot) return e_empty; RBTreeNode* pTemp = m_pRoot; while (pTemp != m_pSentinel) { if (pTemp->key < key) pTemp = pTemp->m_pRChild; else if (pTemp->key > key) pTemp = pTemp->m_pLChild; else break; } if (pTemp != m_pSentinel) { //find it now! value = pTemp->value; return e_success; } else { return e_not_found; } } #ifdef MY_DEBUG template bool RedBlackTree::checkCorrectNess() { if (!m_pRoot) return true; bool bRet = true; // check if the root color is black if (m_pRoot && m_pRoot->color == red) bRet = false; // check red node with black child std::queue< RBTreeNode* > oQueue; oQueue.push( m_pRoot ); int nCurLevelCount = 1; int length = -1; while (true) { int nNextLevelCount = 0; while (nCurLevelCount) { RBTreeNode* pNode = oQueue.front(); nCurLevelCount -- ; if(pNode->color == red) { // child color is black if ((pNode->m_pLChild && pNode->m_pLChild->color == red) || (pNode->m_pRChild && pNode->m_pRChild->color == red)) { bRet = false; break; } } if ( !pNode->m_pLChild && !pNode->m_pRChild) { // this is the leaf node, check the path root int len = 0; RBTreeNode* pTemp = pNode; while (pTemp->m_pParent) { if (pTemp->color == black) len ++ ; pTemp = pTemp->m_pParent; } if (length == -1) length = len; else { if (len != length) { bRet = false; break; } } } if (pNode->m_pLChild) { oQueue.push( pNode->m_pLChild ); nNextLevelCount++; } if (pNode->m_pRChild) { oQueue.push( pNode->m_pRChild ); nNextLevelCount++; } oQueue.pop(); } if (!bRet) break; nCurLevelCount = nNextLevelCount; if (!nCurLevelCount) break; } return bRet; } #endif //MY_DEBUG }
当然,网上还是有很多其他人的博客可以参考的,这里简单列举:
http://blog.csdn.net/v_july_v/article/details/6105630 July的博客
http://saturnman.blog.163.com/
saturman的博客
http://www.cppblog.com/converse/archive/2012/11/27/66530.html#195744 那谁的博客
http://lxr.linux.no/#linux+v3.7.1/lib/rbtree.c linux的rbtree代码
此外,读者可以参考
《算法导论》(建议看一下英文版的)
http://zh.wikipedia.org/wiki/红黑树
http://en.wikipedia.org/wiki/Red–black_tree
个人推荐*英文的讲解,分case讲解很清晰,而且求节点的grandfather等的操作也很安全。