红黑树(RBTree)的实现

来源:互联网 发布:轩辕剑符鬼突破数据 编辑:程序博客网 时间:2024/09/21 08:15

红黑树的特点:

1、任意一个结点要么是红色,要么是黑色
2、根结点是黑色
3、一条路径上不能出现两个连续的红色结点
4、从根节点到任一叶子节点的黑色结点个数相同
5、NUL结点默认为黑色结点(可忽略)


插入实现
注意:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
【情况一】cur为红,p为红,g为黑,u存在且为红则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

【情况二】cur为红,p为红,g为黑,u不存在/u为黑p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转p、g变色--p变黑,g变红

【情况三】cur为红,p为红,g为黑,u不存在/u为黑p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转则转换成了情况2

#pragma  once#include<iostream>using namespace std;enum Color{RED,BLACK};template<class K, class V>struct RBTreeNode{RBTreeNode(const K & key,const V & value,Color color = RED):_value(value),_key(key),_pLeft(NULL),_pRight(NULL),_pParent(NULL),_color(color){}K _key;V _value;RBTreeNode<K,V> * _pLeft;RBTreeNode<K,V> *_pRight;RBTreeNode<K,V> *_pParent;Color _color;  //节点的颜色。};//红黑树迭代器实现template<class K, class V, class Ref, class Ptr>class Iterator{public:typedef RBTreeNode<K,V>  Node;typedef Iterator<K,V,Ref,Ptr> Self;Iterator():_pNode(NULL) { }Iterator(Node *Root):_pNode(Root) { }Iterator(const Self & it):_pNode(it._pNode){ }Ref operator*(){return _pNode->_key;}Ptr operator->(){   return &(operator*() );}Self& operator++(){_pNode = Increment();return *this;}Self operator++(int){Self temp(*this);_pNode = Increment();return temp;}Self& operator--(){_pNode = Decrement();return *this;}Self operator--(int){Self temp(*this);_pNode = Decrement();return temp;}bool operator==(const Self & it){return _pNode == it._pNode;}bool operator != (const Self & it){return _pNode != it._pNode;}private:Node* Increment(){Node *pCur = _pNode;if (pCur->_pRight) //当右子树存在,当前节点的下一个节点就是右子树的最左节点。{Node *pRight = pCur->_pRight;while (pRight->_pLeft){pRight = pRight->_pLeft;}pCur = pRight;}else  //右子树不存在。{Node *pParent = pCur->_pParent;while (pParent->_pRight == pCur){pCur = pParent;pParent = pParent->_pParent;}if ( pCur->_pRight != pParent) //特殊情况,最后一个节点还能再++,++后指向end().{pCur =  pParent;}}return pCur;}Node* Decrement(){Node *pCur = _pNode;if (RED == pCur->_color && pCur->_pParent->_pParent == pNode)//特殊情况在end()的位置pCur = pCur->_pRight;else if (pCur->_pLeft) //当左子树存在,当前节点的下一个节点就是左子树的最右节点。{Node *pLeft = pCur->_pLeft;while (pRight->_pLeft){pRight = pRight->_pLeft;}pCur = pRight;}else  //左子树不存在。{Node *pParent = pCur->_pParent;while (pParent->_pLeft == pCur){pCur = pParent;pParent = pParent->_pParent;}pCur =  pParent;  //第一个节点不能再减了,如果减就是随机值}return pCur;}private:Node *_pNode;};template<class K, class V>class RBTree{typedef RBTreeNode<K, V> Node;typedef Iterator<K,V,K&,K*> Iterator;public:RBTree(): _pHead(NULL){_pHead = new Node(0,0);_pHead->_pLeft = _pHead;_pHead->_pRight = _pHead;}Iterator Begin(){return Iterator(_pHead->_pLeft);}Iterator End(){return  Iterator(_pHead);}Node *GetMaxNode(){Node *pCur = GetRoot();while (pCur->_pRight)//不需要判空  在insert中调用  不会为空pCur = pCur->_pRight;return pCur;}Node *GetMinNode(){Node *pCur = GetRoot();while (pCur->_pLeft)//不需要判空  在insert中调用  不会为空pCur = pCur->_pLeft;return pCur;}bool Insert(const K& key, const V& value){Node *& pRoot= GetRoot();if (pRoot == NULL){pRoot = new Node(key,value);pRoot->_color = BLACK;pRoot->_pParent = _pHead;return true;}Node *pCur = pRoot;Node *pParent = NULL;while (pCur){if (key < pCur->_key){pParent = pCur;pCur = pCur->_pLeft;}else if (key == pCur->_key){return false;}else{pParent = pCur;pCur = pCur->_pRight;}}pCur = new Node(key,value);if (key < pParent->_key){pParent->_pLeft = pCur;pCur->_pParent = pParent;}else{pParent->_pRight = pCur;pCur->_pParent = pParent;}//调整颜色。while (pCur != pRoot &&  pParent->_color == RED )  //根不需要调整,因为退了这个循环直接把根的颜色改成黑色。{Node *garndFather = pParent->_pParent;Node *uncle = NULL;if (pParent == garndFather->_pRight){uncle = garndFather->_pLeft;}elseuncle = garndFather->_pRight;if (uncle != NULL && uncle->_color == RED) //unclue存在且为红{pParent->_color = BLACK;uncle->_color = BLACK;garndFather->_color = RED;}else  //u不存在或者u为黑。{if (pParent == garndFather->_pLeft)  //父亲是爷爷的左孩子{if (pCur == pParent->_pRight){RotateLeft(pParent);swap(pParent,pCur);}if (pCur == pParent->_pLeft){RotateRight(garndFather);pParent->_color = BLACK;garndFather->_color = RED;}}else                        //父亲是爷爷的右孩子。{if (pCur == pParent->_pLeft){RotateRight(pParent);swap(pParent,pCur);}if (pCur == pParent->_pRight){RotateLeft(garndFather);pParent->_color = BLACK;garndFather->_color = RED;}}}pCur = garndFather;pParent = pCur->_pParent;}_pHead->_pLeft = GetMinNode();_pHead->_pRight = GetMaxNode();pRoot->_color = BLACK;return true;}void RotateLeft(Node* parent){Node *pparent = parent->_pParent;Node *subR = parent->_pRight;Node *subRL = subR->_pLeft;if(pparent == _pHead){Node *& pRoot = GetRoot();pRoot = subR;}else{if (parent == pparent->_pLeft){pparent->_pLeft = subR;}else{pparent->_pRight = subR;}}subR->_pParent = pparent;subR->_pLeft = parent;parent->_pParent = subR;parent->_pRight = subRL;if (subRL != NULL){subRL->_pParent = parent;}}void RotateRight(Node* parent){Node * subL = parent->_pLeft;Node *subLR = subL->_pRight;Node *pparent = parent->_pParent;if (pparent == _pHead){Node *& pRoot = GetRoot();pRoot = subL;}else{if (parent == pparent->_pLeft){pparent->_pLeft = subL;}else{pparent->_pRight = subL;}}subL->_pParent = pparent;subL->_pRight = parent;parent->_pParent = subL;parent->_pLeft = subLR;if (subLR != NULL){subLR->_pParent = parent;}}void InOrder(){Node *&pRoot = GetRoot();_InOrder(pRoot);}void _InOrder(Node* pRoot){if(pRoot){_InOrder(pRoot->_pLeft);cout<<pRoot->_key<<" ";_InOrder(pRoot->_pRight);}}//检查是不是红黑树bool CheckRBTree(){Node *&pRoot = GetRoot();if (pRoot == NULL){return true;}if (pRoot->_color == RED){return false;}//找到一条路径上黑色节点的个数size_t blackCount = 0;Node *pCur = pRoot;while (pCur){if (pCur->_color == BLACK){blackCount++;}pCur = pCur->_pLeft;}size_t k = 0;return _CheckRBTree(pRoot,blackCount,k);}//每一条路径上的黑色节点都要相等才是红黑树。bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k) //这个地方k一定是值的,假设一条路径 黑-红-黑-黑-红-黑-黑-红-黑  这条路径黑色节点个数为6,现在回溯{                                                                                           //                        △,假设回溯到这个节点,如果是引用的话,k还是6,        if (pRoot == NULL)                                                                                     //如果你想回溯一次减一,但是回溯的节点可能不是黑色节点,所以引用不行{                                                                                                 //值的话,现在就是4了,符号要求return true;}//当出现两个连续的红色节点的时候,可以确定不是红黑树if (pRoot->_pParent && pRoot->_color == RED && pRoot->_pParent->_color == RED){return false;}//如果是黑节点,k++if (pRoot->_color == BLACK){k++;}//如果是叶子节点的话,进行判断k和count是否相等if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL){if (k != blackCount){return false;}}return _CheckRBTree(pRoot->_pLeft,blackCount,k) && _CheckRBTree(pRoot->_pRight,blackCount,k);}private:Node* _pHead; //红黑树加上一个头节点进行迭代器操作(头节点的左孩子指向红黑树的最小值,右孩子指向最大值,parent域指向根节点)private:Node * & GetRoot()  {return _pHead->_pParent;}};



#include "RBTree.h"void Test(){//int a[] = {10, 8, 7, 15, 5, 6, 11, 13, 12};int a[] = {15,14,13,12,11,10,9,8,7,6,5,1,3,2,1,0};RBTree<int, int> bt;for (size_t idx = 0; idx < sizeof(a)/sizeof(a[0]); ++idx)bt.Insert(a[idx], a[idx]);//bt.InOrder();cout << endl; Iterator<int, int, int&, int *> it = bt.Begin(); //cout << "begin()" << *it <<endl; while (it != bt.End()) { cout << *it <<  " "; it++; } cout <<endl;//cout << bt.CheckRBTree() <<endl;}int main(){Test();system("pause");return 0;}


红黑树和AVL树的比较
红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是O(lg(N))红黑树的不追求完全平衡,保证最长路径不超过最短路径的2倍,相对而言,降低了旋转的要求,所以性能跟AVL树差不多,但是红黑树实现更简单,所以实际运用中红黑树更多。

原创粉丝点击