数据结构之红黑树
2014-04-24 14:37
260 查看
AVL树中任何节点的两个子树的高度最大差别为1,被称为高度平衡树。 红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求(任何不平衡都会在三次旋转之内解决),从而提高了性能。
1、概述
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由鲁道夫•贝尔发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。
2、性质
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根是黑色。
性质3. 所有叶子都是黑色(这里的叶子是指NULL节点)
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
3、操作
因为每一个红黑树也是一个特化的二叉查找树,因此红黑树上的只读操作与普通二叉查找树上的只读操作相同。然而,在红黑树上进行插入操作和删除操作会导致不再符合红黑树的性质。恢复红黑树的属性需要少量(O(log n))的颜色变更(实际是非常快速的)和不超过三次树旋转(对于插入操作是两次)。
插入:以二叉查找树的方法增加新节点,并标记为红色。这样只会破坏性质2和性质4,可通过颜色调换和旋转来调整。
情形1: 新节点N位于树的根上,没有父节点。在这种情形下,我们把它重绘为黑色以满足性质2
情形2: 如果父节点P和叔父节点U二者都是红色,(此时新插入节点N做为P的左子节点或右子节点都属于情形2,这里下图仅显示N做为P左子的情形)则我们可以将它们两个重绘为黑色并重绘祖父节点G为红色(用来保持性质4),然后递归向上调整
情形3: 父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的左子节点。在这种情形下,我们进行一次左旋转调换新节点和其父节点的角色; 接着,我们按情形4处理以前的父节点P以解决仍然失效的性质4
情形4:父节点P是红色而叔父节点U 是黑色或缺少,新节点N 是其父节点的左子节点,而父节点P又是其父节点G的左子节点。在这种情形下,我们进行针对祖父节点G 的一次右旋转
情形5和情形6与情形3和情形4相似,只是左右子树的差别。
删除:如果需要删除的节点有两个儿子,那么问题可以被转化成删除另一个只有一个儿子的节点的问题(这里所指的儿子,为非叶子节点的儿子)。在删除带有两个非叶子儿子的节点的时候,我们要么找到在它的左子树中的最大元素、要么找到在它的右子树中的最小元素,并把它的值转移到要删除的节点中。这就把问题简化为如何删除最多有一个儿子的节点的问题。接下来讨论删除最多有一个儿子的节点。
情形1:删除的节点是红色时(左右子树肯定为空),直接删除,不会改变红黑树的性质
情形2:删除的节点为黑色,且有一个孩子(孩子肯定为红色),用孩子节点的数据替换该节点,删除孩子节点
情形3:删除的节点为黑色,没有左右孩子。违反了性质5。根据以下情形来调节
情形4:如果被删节点的兄弟节点为红色,要在父节点上做一次旋转(左旋或右旋)
情形5:如果被删节点的兄弟节点为黑色,兄弟节点的父节点和儿子节点都为黑色;把兄弟节点变为红色(依然违反性质5),然后递归向上调节
情形6:如果被删节点的兄弟节点为黑色,兄弟节点的父节点为红色,兄弟节点的儿子节点都为黑色,则把父节点的颜色和兄弟节点颜色调换,恢复红黑树的性质
情形7:如果被删节点的兄弟节点为黑色,假设兄弟节点为父节点的右孩子,兄弟节点的左孩子为红色,右孩子为黑色。要在兄弟节点上做右旋转,再按情形8处理
情形8:如果被删节点的兄弟节点为黑色,假设兄弟节点为父节点的右孩子,兄弟节点的右孩子为红色。需要在父节点上做左旋转,再把右孩子的颜色改为黑色。
4、代码实现
通过VS2010编译并粗劣的测试,建立含1千万个节点的红黑树(树高度为44),需要6秒;而建立含1千万个节点的AVL树(树高度为24),需要20秒。
1、概述
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由鲁道夫•贝尔发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。
2、性质
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根是黑色。
性质3. 所有叶子都是黑色(这里的叶子是指NULL节点)
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
3、操作
因为每一个红黑树也是一个特化的二叉查找树,因此红黑树上的只读操作与普通二叉查找树上的只读操作相同。然而,在红黑树上进行插入操作和删除操作会导致不再符合红黑树的性质。恢复红黑树的属性需要少量(O(log n))的颜色变更(实际是非常快速的)和不超过三次树旋转(对于插入操作是两次)。
插入:以二叉查找树的方法增加新节点,并标记为红色。这样只会破坏性质2和性质4,可通过颜色调换和旋转来调整。
情形1: 新节点N位于树的根上,没有父节点。在这种情形下,我们把它重绘为黑色以满足性质2
情形2: 如果父节点P和叔父节点U二者都是红色,(此时新插入节点N做为P的左子节点或右子节点都属于情形2,这里下图仅显示N做为P左子的情形)则我们可以将它们两个重绘为黑色并重绘祖父节点G为红色(用来保持性质4),然后递归向上调整
情形3: 父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的左子节点。在这种情形下,我们进行一次左旋转调换新节点和其父节点的角色; 接着,我们按情形4处理以前的父节点P以解决仍然失效的性质4
情形4:父节点P是红色而叔父节点U 是黑色或缺少,新节点N 是其父节点的左子节点,而父节点P又是其父节点G的左子节点。在这种情形下,我们进行针对祖父节点G 的一次右旋转
情形5和情形6与情形3和情形4相似,只是左右子树的差别。
删除:如果需要删除的节点有两个儿子,那么问题可以被转化成删除另一个只有一个儿子的节点的问题(这里所指的儿子,为非叶子节点的儿子)。在删除带有两个非叶子儿子的节点的时候,我们要么找到在它的左子树中的最大元素、要么找到在它的右子树中的最小元素,并把它的值转移到要删除的节点中。这就把问题简化为如何删除最多有一个儿子的节点的问题。接下来讨论删除最多有一个儿子的节点。
情形1:删除的节点是红色时(左右子树肯定为空),直接删除,不会改变红黑树的性质
情形2:删除的节点为黑色,且有一个孩子(孩子肯定为红色),用孩子节点的数据替换该节点,删除孩子节点
情形3:删除的节点为黑色,没有左右孩子。违反了性质5。根据以下情形来调节
情形4:如果被删节点的兄弟节点为红色,要在父节点上做一次旋转(左旋或右旋)
情形5:如果被删节点的兄弟节点为黑色,兄弟节点的父节点和儿子节点都为黑色;把兄弟节点变为红色(依然违反性质5),然后递归向上调节
情形6:如果被删节点的兄弟节点为黑色,兄弟节点的父节点为红色,兄弟节点的儿子节点都为黑色,则把父节点的颜色和兄弟节点颜色调换,恢复红黑树的性质
情形7:如果被删节点的兄弟节点为黑色,假设兄弟节点为父节点的右孩子,兄弟节点的左孩子为红色,右孩子为黑色。要在兄弟节点上做右旋转,再按情形8处理
情形8:如果被删节点的兄弟节点为黑色,假设兄弟节点为父节点的右孩子,兄弟节点的右孩子为红色。需要在父节点上做左旋转,再把右孩子的颜色改为黑色。
4、代码实现
通过VS2010编译并粗劣的测试,建立含1千万个节点的红黑树(树高度为44),需要6秒;而建立含1千万个节点的AVL树(树高度为24),需要20秒。
#ifndef RED_BLACK_TREE_H #define RED_BLACK_TREE_H namespace redblacktree { enum Color{red,black}; template <typename Element> class TreeNode { public: Element data; Color color; TreeNode<Element> *parent; TreeNode<Element> *lchild; TreeNode<Element> *rchild; TreeNode(Element data):data(data),color(red), lchild(NULL),rchild(NULL),parent(NULL){}; ~TreeNode() { lchild = NULL; rchild = NULL; parent = NULL; }; }; template <typename Element> class RedBlackTree { private: TreeNode<Element>* root; int n; public: RedBlackTree(){root=NULL;n=0;}; ~RedBlackTree(){DestroyTree();}; int SumOfTreeNode(){return n;}; bool InsertTreeNode(Element data); void SearchNode(Element data); void InorderTravelTree(); void DestroyTree(); int DepthOfTree(); void RightRotate(TreeNode<Element>** t); void LeftRotate(TreeNode<Element>** t); void LeftRightRotate(TreeNode<Element>** t); void RightLeftRotate(TreeNode<Element>** t); void InsertTreeNode(TreeNode<Element>** t,TreeNode<Element>* node); void DealRedNode(TreeNode<Element>* node); TreeNode<Element>** GrandFather(TreeNode<Element>* node); TreeNode<Element>* Search(TreeNode<Element>* t, Element data, TreeNode<Element>**pre); void Inorder(TreeNode<Element> *t); bool RemoveTreeNode(Element data); TreeNode<Element>** NodeStoreLocation(TreeNode<Element>* node); void DealBlackNode(TreeNode<Element>* node); TreeNode<Element>* BrotherNode(TreeNode<Element>* node); void DestroyTree(TreeNode<Element>* t); Element RootData(); int DepthOfTree(TreeNode<Element>* t); }; template <typename Element> void RedBlackTree<Element>::RightRotate(TreeNode<Element>** t) { if((t==NULL)||(*t==NULL)||((*t)->lchild==NULL)) return; TreeNode<Element>* p1 = *t; TreeNode<Element>* p2 = (*t)->lchild; *t = p2; p1->lchild = p2->rchild; p2->rchild = p1; p2->parent = p1->parent; p1->parent = p2; if(p1->lchild!=NULL) p1->lchild->parent = p1; if(p1->color!=p2->color) { Color tem = p1->color; p1->color = p2->color; p2->color = tem; } } template <typename Element> void RedBlackTree<Element>::LeftRotate(TreeNode<Element>** t) { if((t==NULL)||(*t==NULL)||((*t)->rchild==NULL)) return; TreeNode<Element>* p1 = *t; TreeNode<Element>* p2 = (*t)->rchild; *t = p2; p1->rchild = p2->lchild; p2->lchild = p1; p2->parent = p1->parent; p1->parent = p2; if(p1->rchild!=NULL) p1->rchild->parent = p1; if(p1->color!=p2->color) { Color tem = p1->color; p1->color = p2->color; p2->color = tem; } } template <typename Element> void RedBlackTree<Element>::LeftRightRotate(TreeNode<Element>** t) { if((t==NULL)||(*t==NULL)||((*t)->lchild==NULL)) return; LeftRotate(&((*t)->lchild)); RightRotate(t); } template <typename Element> void RedBlackTree<Element>::RightLeftRotate(TreeNode<Element>** t) { if((t==NULL)||(*t==NULL)||((*t)->rchild==NULL)) return; RightRotate(&((*t)->rchild)); LeftRotate(t); } template <typename Element> void RedBlackTree<Element>::InsertTreeNode(TreeNode<Element>** t,TreeNode<Element>* node) { if((t==NULL)||(node==NULL)) return; if(*t==NULL)//情形1 { node->parent = NULL; node->color = black; *t = node; return; } TreeNode<Element>* p1 = *t; TreeNode<Element>* p2 = *t; while(p2!=NULL) { p1 = p2; if(node->data<p2->data) p2 = p2->lchild; else p2 = p2->rchild; } if(node->data<p1->data) p1->lchild = node; else p1->rchild = node; node->parent = p1; DealRedNode(node);//处理插入的红色节点 } template <typename Element>//当插入红色节点时,调用此函数处理 void RedBlackTree<Element>::DealRedNode(TreeNode<Element>* node) { if((node==NULL)||(node->color==black)||(node->parent==NULL)||(node->parent->parent==NULL)) return; TreeNode<Element>* head = node->parent->parent; while(head!=NULL) {//当节点为红色和节点的父节点为红色时,需要调整 if((node->color==red)&&(node->parent->color==red)) { if(head->lchild==node->parent) { if((head->rchild==NULL)||(head->rchild->color==black)) { if(node->parent->lchild==node)//情形4 RightRotate(GrandFather(node)); else LeftRightRotate(GrandFather(node));//情形3 return; } else//情形2 { head->lchild->color = black; head->rchild->color = black; head->color = red; node = head; if(head->parent==NULL) { head->color = black; head = NULL; } else head = head->parent->parent; } } else if(head->rchild==node->parent) { if((head->lchild==NULL)||(head->lchild->color==black)) { if(node->parent->rchild==node) LeftRotate(GrandFather(node)); else RightLeftRotate(GrandFather(node)); return; } else { head->lchild->color = black; head->rchild->color = black; head->color = red; node = head; if(head->parent==NULL) { head->color = black; head = NULL; } else head = head->parent->parent; } } } else return; } } template <typename Element>//返回祖父节点的存储位置 TreeNode<Element>** RedBlackTree<Element>::GrandFather(TreeNode<Element>* node) { if((node==NULL)||(node->parent==NULL)||(node->parent->parent==NULL)) return NULL; if(node->parent->parent==root) return &root; TreeNode<Element>* t1 = node->parent->parent; TreeNode<Element>* t = t1->parent; if(t->lchild==t1) return &(t->lchild); else return &(t->rchild); } template <typename Element>//搜索二叉排序树,返回对应的节点,并取得节点的双亲节点 TreeNode<Element>* RedBlackTree<Element>::Search(TreeNode<Element>* t, Element data, TreeNode<Element>**pre) { if(pre != NULL) *pre = t; while(t!=NULL) { if(t->data == data) return t; else if(t->data > data) { if(pre != NULL) *pre = t; t = t->lchild; } else { if(pre != NULL) *pre = t; t = t->rchild; } } if(pre != NULL) *pre = NULL; return NULL; } template <typename Element> void RedBlackTree<Element>::SearchNode(Element data) { TreeNode<Element> *pre; TreeNode<Element> *node; cout<<"================"<<endl; if(node=Search(root,data,&pre)) { if(pre!=node) cout<<"The parent of "<<data<<" is: "<<pre->data<<endl; else cout<<data<<" is root node"<<endl; if(node->lchild!=NULL) cout<<"The left child of "<<data<<" is: "<<node->lchild->data<<endl; else cout<<"The left child of "<<data<<" is: NULL"<<endl; if(node->rchild!=NULL) cout<<"The right child of "<<data<<" is: "<<node->rchild->data<<endl; else cout<<"The right child of "<<data<<" is: NULL"<<endl; } else cout<<data<<" isn't in the tree"<<endl; cout<<"================"<<endl; } template <typename Element>//中序遍历二叉排序树,从小到大输出节点值 void RedBlackTree<Element>::Inorder(TreeNode<Element> *t) { if(t!=NULL) { Inorder(t->lchild); if(t==root) cout<<" "; if(t->color==red) cout<<t->data<<"(r)"<<" "; else cout<<t->data<<"(b)"<<" "; if(t==root) cout<<" "; Inorder(t->rchild); } } template <typename Element> void RedBlackTree<Element>::InorderTravelTree() { Inorder(root); cout<<endl; } template <typename Element> bool RedBlackTree<Element>::InsertTreeNode(Element data) { TreeNode<Element> *node = new TreeNode<Element>(data); if(node==NULL) return false; n++; InsertTreeNode(&root,node); return true; } template <typename Element> bool RedBlackTree<Element>::RemoveTreeNode(Element data) { TreeNode<Element> *node = Search(root, data, NULL); if(node == NULL) return false; n--; TreeNode<Element>** location=NodeStoreLocation(node); //=======当删除的节点最多只有一个儿子节点时============ if(node==root||node->color==red) { if(node->rchild==NULL&&node->lchild==NULL) { delete node; *location = NULL; return true; } if(node->lchild==NULL) { root = node->rchild; root->color = black; root->parent = NULL; delete node; return true; } if(node->rchild==NULL) { root = node->lchild; root->color = black; root->parent = NULL; delete node; return true; } } if(node!=root&&node->color==black) { if(node->lchild==NULL&&node->rchild==NULL) { DealBlackNode(node); location=NodeStoreLocation(node); delete node; *location = NULL; return true; } if(node->rchild==NULL) { node->data = node->lchild->data; delete node->lchild; node->lchild=NULL; return true; } if(node->lchild==NULL) { node->data = node->rchild->data; delete node->rchild; node->rchild=NULL; return true; } } //=========================================== //当删除的节点有两个儿子节点时,转化为删除只有一个节点的问题 TreeNode<Element> *realdelnode=node->rchild; while(realdelnode->lchild!=NULL) realdelnode = realdelnode->lchild; location = NodeStoreLocation(realdelnode); if(realdelnode->color==red) { node->data=realdelnode->data; delete realdelnode; *location = NULL; return true; } if(realdelnode->rchild!=NULL)//右孩子不为NULL,则右孩子的颜色一定是红色,且 { //不会有孩子节点 node->data=realdelnode->data; realdelnode->data=realdelnode->rchild->data; delete realdelnode->rchild; realdelnode->rchild=NULL; return true; } node->data=realdelnode->data; DealBlackNode(realdelnode);//当要删除的节点为黑色,且左右孩子为NULL时,先调 location=NodeStoreLocation(realdelnode);//整红黑树,再删除该节点 delete realdelnode; *location = NULL; return true; } template <typename Element>//返回节点的存储位置 TreeNode<Element>** RedBlackTree<Element>::NodeStoreLocation(TreeNode<Element>* node) { if(node == NULL) return NULL; if(node->parent==NULL) return &root; if(node->parent->lchild==node) return &(node->parent->lchild); if(node->parent->rchild==node) return &(node->parent->rchild); return NULL; } template <typename Element> void RedBlackTree<Element>::DealBlackNode(TreeNode<Element>* node) {//当删除的节点为黑色节点,且节点左右孩子为NULL时,需调用该函数处理 if(node==NULL) return; TreeNode<Element>* brothernode; while(node->parent!=NULL) { brothernode = BrotherNode(node); if(brothernode->color==red)//情形4 { if(node->parent->lchild==node) LeftRotate(NodeStoreLocation(node->parent)); else RightRotate(NodeStoreLocation(node->parent)); } if(node->parent->color==black) { brothernode = BrotherNode(node); if(brothernode->color==black&& (brothernode->lchild==NULL||brothernode->lchild->color==black)&& (brothernode->rchild==NULL||brothernode->rchild->color==black)) {//情形5 brothernode->color = red; node = node->parent; continue; } } brothernode = BrotherNode(node); if(brothernode->color==black&&node->parent->color==red&& (brothernode->lchild==NULL||brothernode->lchild->color==black)&& (brothernode->rchild==NULL||brothernode->rchild->color==black)) {//情形6 node->parent->color = black; brothernode->color = red; return; } if(node->parent->lchild==node) { if(brothernode->color==black&& (brothernode->lchild!=NULL&&brothernode->lchild->color==red)&& (brothernode->rchild==NULL||brothernode->rchild->color==black)) {//情形7 RightRotate(NodeStoreLocation(brothernode)); } brothernode = BrotherNode(node); if(brothernode->color==black&& (brothernode->rchild!=NULL&&brothernode->rchild->color==red)) {//情形8 LeftRotate(NodeStoreLocation(node->parent)); brothernode->rchild->color = black; return; } } else { if(brothernode->color==black&& (brothernode->rchild!=NULL&&brothernode->rchild->color==red)&& (brothernode->lchild==NULL||brothernode->lchild->color==black)) { LeftRotate(NodeStoreLocation(brothernode)); } brothernode = BrotherNode(node); if(brothernode->color==black&& (brothernode->lchild!=NULL&&brothernode->lchild->color==red)) { RightRotate(NodeStoreLocation(node->parent)); brothernode->lchild->color = black; return; } } } } template <typename Element> TreeNode<Element>* RedBlackTree<Element>::BrotherNode(TreeNode<Element>* node) { if(node==NULL||node==root) return NULL; if(node->parent->lchild==node) return node->parent->rchild; if(node->parent->rchild==node) return node->parent->lchild; } template <typename Element>//销毁树 void RedBlackTree<Element>::DestroyTree(TreeNode<Element>*t) { if(t!=NULL) { DestroyTree(t->lchild); DestroyTree(t->rchild); delete t; } } template <typename Element> void RedBlackTree<Element>::DestroyTree() { DestroyTree(root); root=NULL; n = 0; } template <typename Element> Element RedBlackTree<Element>::RootData() { if(root!=NULL) return root->data; return -1; } template <typename Element> int RedBlackTree<Element>::DepthOfTree() { return DepthOfTree(root); } template <typename Element>//返回树的深度 int RedBlackTree<Element>::DepthOfTree(TreeNode<Element>* t) { if(t==NULL) return 0; int lh = DepthOfTree(t->lchild); int rh = DepthOfTree(t->rchild); return 1+(lh>rh?lh:rh); } } #endif
相关文章推荐
- 【转】数据结构之红黑树
- 数据结构与算法:红黑树的原理分析
- 数据结构之红黑树(二)——插入操作
- Java数据结构与算法解析(十一)——红黑树
- 数据结构之红黑树详解
- 经典数据结构-红黑树详解(转)
- 数据结构之红黑树(二)——插入操作
- 数据结构之红黑树
- map在insert数据后红黑树结构变化
- 数据结构 — 浅析红黑树原理以及实现
- 数据结构之红黑树
- 算法学习之数据结构之红黑树(一)
- 数据结构之红黑树(三)——删除操作
- 数据结构基础(24) --红黑树的设计与实现(下)
- Java数据结构与算法解析(十一)——红黑树
- 数据结构之(红黑树)
- 数据结构之红黑树(三)——删除操作
- 数据结构之红黑树
- 数据结构——红黑树扩展
- 红黑树 数据结构说解