红黑树(附代码) - O兴~ - 歪酷博客 Ycool Blog
红黑树的代码实现
//by svking//2012.5#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAXSIZE 1000typedef int ElemType;#define RED 0#define BLACK 1typedef struct RBTNode{char color;ElemType data;struct RBTNode * p;struct RBTNode * left;struct RBTNode * right;}RBTNode, * PRBTNode;typedef struct RBTree{PRBTNode root;PRBTNode nil; //统一的空节点,该节点是黑的}RBTree, * PRBTree;int leftRotate (PRBTree tree, PRBTNode t);int rightRotate (PRBTree tree, PRBTNode t);PRBTNode insertRB (PRBTree tree, ElemType d);int insertRB_fixup (PRBTree tree, PRBTNode t);int createRBTree (PRBTree tree, ElemType d[], int n); int initRB (PRBTree tree);PRBTNode maximum (PRBTree tree, PRBTNode t); PRBTNode minimum (PRBTree tree, PRBTNode t); PRBTNode next (PRBTree tree, PRBTNode t);PRBTNode precursor (PRBTree tree, PRBTNode t);int walkNext (PRBTree tree);int inOrderWalk (PRBTree tree, PRBTNode t);int deleteRB_fixup (PRBTree tree, PRBTNode c); PRBTNode deleteRB (PRBTree tree, PRBTNode t);int main (){PRBTNode p;int d[MAXSIZE];int n = 0;int i;RBTree tree;initRB(&tree);/*insertRB(&tree, 11);insertRB(&tree, 2);insertRB(&tree, 14);insertRB(&tree, 1);insertRB(&tree, 7);insertRB(&tree, 15);insertRB(&tree, 5);insertRB(&tree, 8);insertRB(&tree, 4);*/p= insertRB(&tree, 26);insertRB(&tree, 17);insertRB(&tree, 41);insertRB(&tree, 14);insertRB(&tree, 21);insertRB(&tree, 30);insertRB(&tree, 47);insertRB(&tree, 10);insertRB(&tree, 16);insertRB(&tree, 19);insertRB(&tree, 23);insertRB(&tree, 28);insertRB(&tree, 38);insertRB(&tree, 7);insertRB(&tree, 12);insertRB(&tree, 15);insertRB(&tree, 20);insertRB(&tree, 3);insertRB(&tree, 35);insertRB(&tree, 39);srand(time(NULL));/*puts("请输入数据的个数:");scanf("%d",&n);printf("随机生成的%d个数据是:\n",n); for (i = 0; i < n; i++){d[i] = rand()%1000;printf("%d ",d[i]);}puts("");puts("建树开始");createRBTree(&tree, d, n);*/inOrderWalk(&tree,tree.root);puts("");printf("根是%d \n",tree.root->data);printf("删除%d后:",p->data);deleteRB(&tree, p);inOrderWalk(&tree,tree.root);puts("");printf("根是%d \n",tree.root->data);return0;}PRBTNode insertRB (PRBTree tree, ElemType d){//插入元素//!!!记得插入的元素的初始化,p指向为父母节点,left和right赋值为NULL。
12.红黑树
• 先分析一下,插入操作可能会破坏哪些 RB性质呢? • 性质①和性质③,当然继续成立。因为插 入的结点z的子女都是哨兵NIL。 • 性质⑤也是成立的,因为将z着为红色。 • 那么:插入操作可能破坏的就只剩性质② 和④了,这都可以通过RB-insert-fixup辅 助程序来进行修复的。
• 性质②,可能被破坏的原因是:z被着为红 色,而如果z是根的话。即对一颗空树作插 入操作时。 • 性质④,可能被破坏的原因是:如果z的父 结点是红色的。 • 如果有RB性质被破坏,则至多只有一个被 破坏,要么是性质②,要么是性质④。如果 违反性质②,则发生的原因是z是根而且是 红的。如果违反性质④,则发生的原因是z 和z.p都是红色的。
y=x.right; x.right=y.left; if(y.left!=NIL) (y.left).p=x; y.p=x.p; if(x.p==NIL) root[t]=y; else if(x==(x.p).left) (x.p).left=y; else (x.p).right=y; y.left=x; x.p=y;
2 旋转(左旋和右旋)
• 在含有n个结点的RB树上,运行二叉查找树 操作tree-insert()和tree-delete()的时间为 O(lgn)。 • 由于这两种操作对树做了修改,结果就可能 会违反RB性质。为了保持RB性质,就需要 改变树中某些结点的颜色以及指针结构。 • 指针结构的修改是通过旋转来完成的,这是 一种能保持二叉查找树性质的局部操作。
1 红黑树的性质
• 红黑树是一种二叉查找树,但是在每个结 点上增加一个存储位表示结点的颜色,可 以用red或black。 • 通过对任何一条从根到叶子的路径上各个 结点着色方式的限制,红黑树确保没有一 条路径会比其他路径长出两倍,因而是接 近平衡的。
数据结构与算法(8):红黑树
// 前提:这里里里假设x的右孩子子为y。下面面开始正式操作 // 将 “y的左孩子子” 设为 “x的右孩子子”,即 将β设为x的右孩子子 // 将 “x” 设为 “y的左孩子子的父父亲”,即 将β的父父亲设为x // 将 “x的父父亲” 设为 “y的父父亲”
05 if p[x] = nil[T] 06 then root[T] ← y
的右孩子子”
10 left[y] ← x
// 将 “x” 设为 “y的左孩子子”
11 p[x] ← y
// 将 “x的父父节点” 设为 “y”
理理解左旋之后,看看下面面更更鲜明的例例子子。
2.2 右旋
对Y进行行行右旋,意味着“将Y变成一一个右节点”
右旋的伪代码《算法导论》:参考上面面的示意图和下面面的伪代码,理理解“红黑黑树T的节点y进行行行右 旋”是如何进行行行的。
1.2 红广泛,主要是用用它来存储有序的数据,它的时间复杂度是O(lgn),效率非非常之
高高。
例例如,Java集合中的TreeSet和TreeMap,C++的STL中的Set、Map,以及Linux虚拟内存的管
理理,都是通过红黑黑树去实现的。
二二、红黑黑树的基本操作:左旋和右旋
数据结构与算法(8):红黑黑树
红黑黑树,即R-B Tree,本文文的主要内容包括:红黑黑树的特性、红黑黑树的时间复杂度和它的证明, 红黑黑树的时间复杂度和它的证明,红黑黑树的左旋、右旋、插入入、删除等操作
一一、红黑黑树的定义
1.1 红黑黑树的定义
R-B Tree,全称是Red-black Tree,又又称为“红黑黑树”,它是一一种特殊的二二叉查找树。红黑黑树的每 个节点上都有存储位表示节点的颜色色,可以是红(Red)或黑黑(Black)
c语言红黑树遍历序算法
c语言红黑树遍历序算法红黑树是一种自平衡的二叉查找树,它具有良好的平衡性能,能够保持在较低的高度范围内。
在C语言中,我们可以使用递归或者非递归的方式来实现红黑树的遍历。
下面我将分别介绍中序遍历、前序遍历和后序遍历的算法。
1. 中序遍历算法:中序遍历的顺序是先遍历左子树,然后访问根节点,最后遍历右子树。
在C语言中,我们可以使用递归实现中序遍历:c.void inOrderTraversal(struct Node root) {。
if (root != NULL) {。
inOrderTraversal(root->left);printf("%d ", root->data);inOrderTraversal(root->right);}。
}。
2. 前序遍历算法:前序遍历的顺序是先访问根节点,然后遍历左子树,最后遍历右子树。
同样可以使用递归实现前序遍历:c.void preOrderTraversal(struct Node root) {。
if (root != NULL) {。
printf("%d ", root->data);preOrderTraversal(root->left);preOrderTraversal(root->right);}。
}。
3. 后序遍历算法:后序遍历的顺序是先遍历左子树,然后遍历右子树,最后访问根节点。
同样可以使用递归实现后序遍历:c.void postOrderTraversal(struct Node root) {。
if (root != NULL) {。
postOrderTraversal(root->left);postOrderTraversal(root->right);printf("%d ", root->data);}。
}。
另外,以上是使用递归实现的遍历算法,也可以使用非递归的方式来实现,利用栈来辅助实现遍历。
红黑树-C++代码实现
红⿊树-C++代码实现红⿊树的介绍红⿊树(Red-Black Tree,简称R-B Tree),它⼀种特殊的⼆叉查找树。
红⿊树是特殊的⼆叉查找树,意味着它满⾜⼆叉查找树的特征:任意⼀个节点所包含的键值,⼤于等于左孩⼦的键值,⼩于等于右孩⼦的键值。
除了具备该特性之外,红⿊树还包括许多额外的信息。
红⿊树的每个节点上都有存储位表⽰节点的颜⾊,颜⾊是红(Red)或⿊(Black)。
红⿊树的特性:(1) 每个节点或者是⿊⾊,或者是红⾊。
(2) 根节点是⿊⾊。
(3) 每个叶⼦节点是⿊⾊。
[注意:这⾥叶⼦节点,是指为空的叶⼦节点!](4) 如果⼀个节点是红⾊的,则它的⼦节点必须是⿊⾊的。
(5) 从⼀个节点到该节点的⼦孙节点的所有路径上包含相同数⽬的⿊节点。
关于它的特性,需要注意的是:第⼀,特性(3)中的叶⼦节点,是只为空(NIL或null)的节点。
第⼆,特性(5),确保没有⼀条路径会⽐其他路径长出俩倍。
因⽽,红⿊树是相对是接近平衡的⼆叉树。
红⿊树⽰意图如下:红⿊树的C++实现(代码说明)红⿊树的基本操作是添加、删除和旋转。
在对红⿊树进⾏添加或删除后,会⽤到旋转⽅法。
为什么呢?道理很简单,添加或删除红⿊树中的节点之后,红⿊树就发⽣了变化,可能不满⾜红⿊树的5条性质,也就不再是⼀颗红⿊树了,⽽是⼀颗普通的树。
⽽通过旋转,可以使这颗树重新成为红⿊树。
简单点说,旋转的⽬的是让树保持红⿊树的特性。
旋转包括两种:左旋和右旋。
下⾯分别对红⿊树的基本操作进⾏介绍1. 基本定义enum RBTColor{RED, BLACK};template <class T>class RBTNode{public:RBTColor color; // 颜⾊T key; // 关键字(键值)RBTNode *left; // 左孩⼦RBTNode *right; // 右孩⼦RBTNode *parent; // ⽗结点RBTNode(T value, RBTColor c, RBTNode *p, RBTNode *l, RBTNode *r):key(value),color(c),parent(),left(l),right(r) {}};template <class T>class RBTree {private:RBTNode<T> *mRoot; // 根结点public:RBTree();~RBTree();// 前序遍历"红⿊树"void preOrder();// 中序遍历"红⿊树"void inOrder();// 后序遍历"红⿊树"void postOrder();// (递归实现)查找"红⿊树"中键值为key的节点RBTNode<T>* search(T key);// (⾮递归实现)查找"红⿊树"中键值为key的节点RBTNode<T>* iterativeSearch(T key);// 查找最⼩结点:返回最⼩结点的键值。
搜索算法—红黑树
搜索算法—红⿊树1.什么是红⿊树(Red-BlackBalancedSearchTree) 红⿊树本质上是⼆叉搜索树的改良版,因此,对⼆叉搜索树不了解的,建议先去看⼀下。
⼆叉搜索树有个严重的缺陷:树本⾝并不平衡,很容易造成部分分⽀过长,⽽部分分⽀过短的情况,从⽽影响到了搜索速度。
⼆叉搜索树的⼀个极端例⼦: 如果把⼀个递增的数组按顺序放进⼆叉搜索树,就会出现上图的情况,要搜索某个值就得查N次。
红⿊树就可以解决这个问题,且能保证在⼤部分情况下,树都是平衡的。
(红⿊树图中的空节点只是为了表⽰另⼀个节点是左节点还是右节点。
) 要深⼊理解红⿊树的含义,就需要先了解2-3搜索树。
2.2-3搜索树 2-3搜索树也是⼆叉搜索树改良版,也能保证树的平衡。
这⾥只介绍2-3搜索树,不⽤代码实现它。
如上图,2-3搜索树有两种节点:有两个分⽀的节点和有三个分⽀的节点。
有两个分⽀的节点中,左⼦节点⽐⽗节点⼩,右⼦节点⽐⽗节点⼤。
有三个分⽀的节点中,左⼦节点⽐⽗节点⾥的所有数⼩,右⼦节点⽐⽗节点所有数⼤,中⼦节点介于⽗节点的两个数之间,如下图: c<a<d<b<e插⼊数值 从例⼦介绍思路: 现有2-3搜索树如下图。
如果要插⼊值13,⾸先从根节点开始⽐较,13<15,故13⾛向左节点。
13>10,但由于左节点没有右⼦节点,因此10和13成为有三个分⽀的节点。
如下图。
如果再插⼊值14,⾸先从根节点开始⽐较,14<15,故14⾛向左节点。
14>13,但由于此节点没有右⼦节点,因此10,13,14成为新节点,但这个含有3个值的节点只是临时的,会经历下⼀段变化。
含有3个值的节点A中,处于中间值的13会移到此节点的⽗节点中。
即根节点变成含有13,15的新节点。
节点A分裂成两个只含1个值的节点。
如下图: 如果再插⼊值25,⾸先从根节点开始⽐较,25>15,故25⾛向右节点。
一篇不错的红黑树代码
一篇不错的红黑树代码一篇不错的红黑树代码总想有一个简单的RBTree类,又不想自己实现,找来找去找到这篇好文,除了讲解的清楚简明外,代码也不错,无递归的迭代,而且很容易“拿来”做成模板,如果你也不想"再发明一次轮子"的话...正文如下:红黑树(附标准代码)(阅读本文之前请先了解二叉搜索树)红黑树(Red-Black Tree)是二叉搜索树(Binary Search Tree)的一种改进。
我们知道二叉搜索树在最坏的情况下可能会变成一个链表(当所有节点按从小到大的顺序依次插入后)。
而红黑树在每一次插入或删除节点之后都会花O(log N)的时间来对树的结构作修改,以保持树的平衡。
也就是说,红黑树的查找方法与二叉搜索树完全一样;插入和删除节点的的方法前半部分节与二叉搜索树完全一样,而后半部分添加了一些修改树的结构的操作。
红黑树的每个节点上的属性除了有一个key、3个指针:parent、lchild、rchild以外,还多了一个属性:color。
它只能是两种颜色:红或黑。
而红黑树除了具有二叉搜索树的所有性质之外,还具有以下4点性质:1. 根节点是黑色的。
2. 空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild、rchild都不指向NULL,而是指向一个定义好的空节点)。
3. 红色节点的父、左子、右子节点都是黑色。
4. 在任何一棵子树中,每一条从根节点向下走到空节点的路径上包含的黑色节点数量都相同。
如下图就是一棵红黑树:有了这几条规则,就可以保证整棵树的平衡,也就等于保证了搜索的时间为O(log N)。
但是在插入、删除节点后,就有可能破坏了红黑树的性质。
所以我们要做一些操作来把整棵树修补好。
下面我就来介绍一下。
首先有一个预备知识,那就是节点的Left-Rotate和Right-Rotate操作。
所谓Left-Rotate(x)就是把节点x 向左下方向移动一格,然后让x原来的右子节点代替它的位置。
红黑树算法原理与实现
红黑树算法原理与实现红黑树是一种自平衡二叉查找树,它能够保证查找、插入和删除操作最坏情况下的时间复杂度都为O(log n),是一种十分高效的数据结构。
本文将对红黑树算法的原理和实现进行介绍,帮助读者深入了解红黑树的运作流程和应用场景。
一、红黑树的定义和性质红黑树和其他的自平衡二叉查找树(如AVL树)一样,能够自动调整树的结构以保证平衡,并且能够保持树中每个节点的黑高相等。
下面是红黑树的具体定义:(1)每个节点要么是红色,要么是黑色。
(2)根节点是黑色。
(3)每个叶子节点(NIL节点,空节点)都是黑色的。
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)任意一个节点到每个叶子节点所经过的黑色节点数都相同。
这些性质确保了红黑树的平衡,在插入和删除节点时能够自动平衡而不需要人工干预,从而保证了树的性能。
二、红黑树的基本操作红黑树的插入和删除操作是它最为关键和难点的部分,下面我们将针对这两个操作进行介绍。
(1)插入操作插入节点时,首先按照二叉查找树的方式将新节点插入到树中。
接下来需要进行的操作是将节点的颜色进行调整,保证该节点符合红黑树的五大性质。
如果插入的节点不满足性质(4),需要执行进行一系列颜色调整和旋转操作,使得节点重新满足红黑树性质。
一般情况下,情况分为两种:(a)情况1:插入的节点为根节点此时只需要将节点的颜色设置为黑色即可。
(b)情况2:插入的节点的父节点为红色此时需要进行一系列的旋转和颜色调整操作。
可以分为以下三种情况:①插入节点的叔叔节点是红色的,此时需要进行颜色调整和旋转。
②插入节点的叔叔节点是黑色的,并且插入节点为父节点的右子节点,此时需要进行左旋操作。
③插入节点的叔叔节点是黑色的,并且插入节点为父节点的左子节点,此时需要进行颜色调整、右旋操作。
(2)删除操作删除节点时,首先按照二叉查找树的方式删除节点。
接着需要对树进行自平衡操作,使之重新满足红黑树性质。
与插入操作相比,删除操作需要考虑更多的情况。
红黑树的代码实现
红⿊树的代码实现红⿊树满⾜⼀下规则1. 每个节点不是红⾊就是⿊⾊2.根节点为⿊⾊3.如果节点为红,其⼦节点必须为⿊4.任⼀节点⾄nil的任何路径,所包含的⿊节点数必须相同。
5.叶⼦节点nil为⿊⾊当破坏了平衡时,在调整的时候需要⽤到左旋和右旋左旋:右旋:代码实现:1void rb_tree::__rb_tree_rotate_left(link_type x) {2 link_type y = x->right;3 x->right = y->left;4if(y->left != nil) {5 y->left->parent = x;6 }7 y->parent = x->parent;8if(x == root) {9 root = y;10 } else if(x == x->parent->left) {11 x->parent->left = y;12 } else {13 x->parent->right = y;14 }15 x->parent = y;16 y->left = x;17 }左旋转1void rb_tree::__rb_tree_rotate_right(link_type x) {2 link_type y = x->left;3 x->left = y->right;4if(x->left != nil) {5 x->left->parent = x;6 }7 y->parent = x->parent;8if(x == root) {9 root = y;10 } else if(x->parent->left == x) {11 x->parent->left = y;12 } else {13 x->parent->right = y;14 }1516 x->parent = y;17 y->right = x;18 }右旋转插⼊节点时,可能会破坏红⿊树的结构,如下图,在插⼊3,8,35,75的时候,就破坏了树的结构:设定如下⽤语:新节点为X,其⽗节点为P,组⽗节点为G,伯⽗节点为S,曾祖⽗节点GG。
红黑树
红黑树(Red Black Tree)介绍今天我们来介绍另一种平衡二叉树:红黑树(Red Black Tree),红黑树由Rudolf Bayer于1972年发明,当时被称为平衡二叉B树(symmetric binary B-trees),1978年被Leonidas J. Guibas 和 Robert Sedgewick改成一个比较摩登的名字:红黑树。
红黑树和之前所讲的AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
自从红黑树出来后,AVL树就被放到了博物馆里,据说是红黑树有更好的效率,更高的统计性能。
不过在我了解了红黑树的实现原理后,并不相信这是真的,关于这一点我们会在后面进行讨论。
红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是AVL树中的非常严格的平衡。
之前我们在讲解AVL树时,已经领教过AVL树的复杂,但AVL树的复杂比起红黑树来说简直是小巫见大巫。
红黑树是真正的变态级数据结构。
首先来一个Silverlight做的红黑树的动画,它有助于帮你理解什么是红黑树。
这里需要注意,必须安装Silverlight 2.0 RTW 才能正常运行游戏,下载地址:/silverlight/resources/install.aspx?v=2.0使用注意事项:●结点只接收整数,如果在添加和删除操作中输入非法字串,则会随机添加或删除一个0~99之间的整数。
●可以不在编辑框中输入数字,直接单击添加和删除按钮进行添加和删除操作。
●可以拖动拖动条控制动画速度。
红黑树的平衡红黑树首先是一棵二叉查找树,它每个结点都被标上了颜色(红色或黑色),红黑树满足以下5个性质:1、每个结点的颜色只能是红色或黑色。
2、根结点是黑色的。
3、每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。
红黑树 predecessor 代码
红黑树 predecessor 代码红黑树是一种自平衡的二叉搜索树,每个节点都用一个颜色属性表示,是红色或黑色。
红黑树的自平衡性能使得它在插入、删除等操作时具有较高的效率。
在红黑树中,与每个节点相连的叶节点是 NIL 节点,也就是空节点。
本文将介绍红黑树的 predecessor 算法,并给出其代码实现。
Predecessor 算法Predecessor 算法旨在找到某个节点的前驱节点,即前一个较小的节点。
具体来说,对于一个节点 x,其前驱节点是在整个红黑树中所有值小于 x 值的节点中,值最大的那个节点。
我们可以使用某种方式遍历整棵红黑树,查找前驱节点。
在这里,我们使用了中序遍历算法。
中序遍历算法按照从小到大的顺序遍历整棵树,当遍历到某个节点时,比较其值与目标节点值的大小,如果当前节点值小于目标节点值,就将其标记为前驱节点。
当遍历完整棵树时,返回前驱节点即可。
需要注意的是,在进行中序遍历时,我们需要不断回溯到当前子树的根节点,这样才能找到包含左子树中所有节点的整个子树。
因此,在算法中,我们要判断从哪个方向来到当前节点,以便正确地回溯到根节点。
代码实现下面是红黑树 predecessor 算法的代码实现。
代码中,函数 find_predecessor 返回目标节点的前驱节点。
```python def find_predecessor(node): # 判断是否存在左子树 if node.left: # 进入左子树 node = node.left # 找到左子树中的最右节点 while node.right:node = node.right # 返回前驱节点return node else: parent = node.parent while parent and node == parent.left:node = parent parent = parent.parent # 返回前驱节点 return parent ```在这个代码中,我们首先判断当前节点是否存在左子树。
什么是红黑树
什么是红黑树
红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B 树(symmetric binary B-trees)。
后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的:它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),因此,红黑树在很多地方都有应用。
在C++ STL中,很多部分(包括set, multiset,map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。
其他平衡树还有:AVL,SBT,伸展树,TREAP 等等。
红黑树(平衡操作详解)
红⿊树(平衡操作详解)摘⾃ https:///qq_26323323/article/details/796432161.红⿊树红⿊树本⾝也是⼀种⼆叉树,只不过是⼀种⽐较特殊的⼆叉树⼆叉树如果插⼊的数值是有序时,⼆叉树就是⾮平衡的,基本跟链表类似了(时间复杂度O(N))针对这种情况,就产⽣了红⿊树,这种树在插⼊的过程中,会通过⼀系列的⽅式来保持树的平衡,使其时间复杂度⼀直维持在O(logN) 2.红⿊树规则* 每⼀个节点不是⿊⾊就是红⾊* 根节点总是⿊⾊的* 如果节点是红⾊的,则它的⼦节点必须是⿊⾊的(反之则不⼀定)* 从根到叶节点的每条路径,包含的⿊⾊节点数⽬必须相同3.红⿊树修正违规操作简介红⿊树之所以能够保持平衡,是因为严格遵守了上述规则在插⼊的过程中,如果某节点违反了以上规则,则需要进⾏修正,修正的⽅式包括:改变颜⾊、旋转1)术语为了平衡⼀棵树,需要对某些节点进⾏重新排列,将⼀些节点上升,将⼀些节点下降,以此来帮助树平衡。
切记:在树平衡操作的过程中不能破坏⼆叉树的特点(⼀个节点的左⼦节点的关键字值⼩于这个节点,右⼦节点的关键字值⼤于或等于这个⽗节点)旋转之前先了解⼀些基本概念:* 外侧⼦孙12在18的左侧,18在25的左侧,它们的相对⽗节点位置相同,则称新插⼊的节点12为外侧⼦孙节点38在35的右侧,35在25的右侧,它们的相对⽗节点位置相同,则称新插⼊的节点38为外侧⼦孙节点* 内侧⼦孙22在18的右侧,18在25的左侧,它们的相对⽗节点位置不同,则称新插⼊的节点22为内侧⼦孙节点30在35的左侧,35在25的右侧,它们的相对⽗节点位置不同,则称新插⼊的节点30为内侧⼦孙节点可以看到,在插⼊新节点之前的树都是平衡的,但是插⼊新节点之后就会违反规则3,故需要对这些树进⾏修正(看到⼦节点和⽗节点都是红⾊的,就要想到使⽤旋转来保持树的平衡)* 右旋转当以35为顶端元素进⾏右旋转时,需要注意:该顶端元素必须有⼀个左⼦元素右旋结果如下:35下移,30上移到35的位置,20位置不变,依旧是30的左⼦元素* 左旋转当以30为顶端元素进⾏左旋转时,需要注意:该顶端元素必须有⼀个右⼦节点左旋结果如下:30下移到左侧,35上移到30的位置,45位置不变,依旧是35的右⼦节点2)颜⾊变换场景:当在插⼊的过程中遇到⼀个⿊⾊节点下有两个红⾊节点,则需要进⾏颜⾊变换⽰例:当前场景下,是符合红⿊树规则的,如果此时再插⼊⼀个节点,按照规则3,则新节点只能是⿊⾊的,但是这样就会违反规则4,所以对现有节点进⾏变⾊* 把25、75两个⼦节点变⾊为⿊⾊* 再新插⼊节点为红⾊即可操作完成之后的树为3)外侧⼦孙的旋转平衡术针对上述这种情况,找到新插⼊节点12的祖⽗节点25,然后以25为顶端,进⾏右旋转上述这种情况,找到新插⼊节点38的祖⽗节点25,以25为顶端,进⾏左旋转4)内侧⼦孙的旋转平衡术上述这种情况,找到新插⼊节点22的⽗节点18,然后以18位顶端,进⾏左旋转,旋转后结果如下然后以22的⽗节点25进⾏右旋转,旋转结果如下再修改22和18、25节点的颜⾊,即保持树的正确总结:外侧⼦孙和内侧⼦孙的平衡都是需要进⾏旋转,不同的是外侧⼦孙只需要进⾏⼀次旋转即可,⽽内侧⼦孙则需要进⾏两次旋转,第⼀次旋转后变成外侧⼦孙的模式,再根据外侧⼦孙的⽅式来进⾏平衡即可3.插⼊新节点红⿊树插⼊新节点的过程中,会遇到违背红⿊树规则的情况,为了保持树的平衡,则需要使⽤以上的⼏种⽅式来保持树平衡下⾯介绍下以下⼏种插⼊新节点过程中遇到的问题及其解决⽅案:1)在下⾏过程中发现⿊⾊节点下有两个红⾊⼦节点为什么这种情况是会违背红⿊树规则呢?因为根据规则3,红⾊节点下的⼦节点必须为⿊⾊节点,那么插⼊⿊⾊⼦节点后就会违背规则4,所以碰到这种情况,需要对这三个节点进⾏颜⾊变换当再插⼊12节点时,就会与18节点产⽣颜⾊冲突,所以需要对18 25 30三个节点进⾏颜⾊变换,变换成如下,再插⼊12节点即可2)插⼊节点后发⽣颜⾊冲突接着上个树来继续添加节点6发现6节点和12节点都是红⾊,违背规则3,则根据上述外侧⼦孙节点处理⽅案对6的祖⽗节点18进⾏右转此时12和25节点都是红⾊,同样违背规则3,对12的祖⽗节点50节点进⾏右转再对上述节点颜⾊错误的进⾏颜⾊变换,25、12、6节点都变成⿊⾊,即变成⼀颗复合规则的红⿊树3)插⼊过程中发⽣颜⾊冲突以上节点属于平衡状态,此时如果再插⼊节点3,则需要对12、6、18节点进⾏颜⾊变换操作此时12和25节点⼜发⽣了颜⾊冲突,则需要找到12节点的祖⽗节点50,然后以50节点进⾏右旋转再改变25和12的颜⾊为⿊⾊,以符合规则2和4此时已经平衡,再插⼊节点3即可,结果如下总结:针对于红红冲突,需要找到合适的祖⽗节点,然后进⾏旋转,再进⾏节点颜⾊变换,则就可以保持树的平衡⾄于代码实现,可以参考TreeMap参考:Java数据结构和算法(第⼆版)。
红黑树
红黑树(摘自)满足下面几个条件的二叉搜索树,称为红黑树:1. 任何一个节点都被着色――红色或是黑色。
2. 根节点是黑色的。
3. 所有的NIL节点都看成黑色(NIL节点是就是一个假想的或是无实在意义的节点,所有应该指向NULL的指针,都看成指向了NIL节点。
包括叶节点的子节点指针或是根节点的父指针)。
4. 如果一个节点是红色的,那么它的子节点一定是黑色的。
5. 对于任何一个节点而言,从该节点到它的子孙节点中的NIL节点路径中,所包含的黑节点个数相同。
黑高度的定义:从任何一个节点,向下到底部的路径中,包含的黑节点的个数,称为这个节点的黑高度。
从红黑树的第5条性质可以看出,黑高度是唯一的、确定的。
只要同时满足红黑树的这些条件,就一定会有“红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍”这个平衡的性质。
我们可以假设,如果存在两条路径L和S,L比S长两倍以上(S路径上有n个节点,L上有大于2n个节点)。
可知,S的黑高度最大只可能是n,那么根据第5条性质,L的黑高度也大也只可能是n,也就是,L路径上一定有超过n个红色节点(因为节点不是黑的就必定是红的)。
所以,肯定会有两个以上的红色节点是相邻的。
这就与第4个条件矛盾了。
所以,红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍。
红黑树的高度h<2lg(n+1)(这个在《算法导论》节中有证明)。
也就是说,红黑树的操作的时间复杂度是O(lgn)的。
二叉搜索树的操作时间复杂度,取决于树高h,因此,我们当然就希望h尽量地小以提高操作的效率。
从直观上就可以发现,二叉搜索树各子树的规模越平均,它的高度就会越小。
所以在应用中,一般都会将二叉搜索树实现成一种平衡树,以保证最差时间复杂度为O(lgn)。
红黑树就是其中的一种,应用得很广泛(SGI STL的set和map就是基于红黑树来实现,Linux内核中也用到这个数据结构)红黑树是二叉搜索树的一种。
红黑树详解——精选推荐
红⿊树详解前⾔红⿊树的起源,⾃然是⼆叉查找树了,这种树结构从根节点开始,左⼦节点⼩于它,右⼦节点⼤于它。
每个节点都符合这个特性,所以易于查找,是⼀种很好的数据结构。
但是它有⼀个问题,就是容易偏向某⼀侧,这样就像⼀个链表结构了,失去了树结构的优点,查找时间会变坏。
所以我们都希望树结构都是矮矮胖胖的,像这样:⽽不是像这样:在这种需求下,平衡树(AVL)的概念就应运⽽⽣了。
红⿊树就是⼀种平衡树,它可以保证⼆叉树基本符合矮矮胖胖的结构,但是理解红⿊树之前,必须先了解另⼀种树,叫2-3树,红⿊树背后的逻辑就是它。
好吧来看2-3树吧。
2-3树是⼆叉查找树的变种,树中的2和3代表两种节点,以下表⽰为2-节点和3-节点。
2-节点即普通节点:包含⼀个元素,两条⼦链接。
3-节点则是扩充版,包含2个元素和三条链接:两个元素A、B,左边的链接指向⼩于A的节点,中间的链接指向介于A、B值之间的节点,右边的链接指向⼤于B的节点 2-节点: 3-节点:在这两种节点的配合下,2-3树可以保证在插⼊值过程中,任意叶⼦节点到根节点的距离都是相同的。
完全实现了矮胖矮胖的⽬标。
怎么配合的呢,下⾯来看2-3树的构造过程。
所谓构造,就是从零开始⼀个节点⼀个节点的插⼊。
在⼆叉查找树中,插⼊过程从根节点开始⽐较,⼩于节点值往右继续与左⼦节点⽐,⼤于则继续与右⼦节点⽐,直到某节点左或右⼦节点为空,把值插⼊进去。
这样⽆法避免偏向问题。
在2-3树中,插⼊的过程是这样的。
如果将值插⼊⼀个2-节点,则将2-节点扩充为⼀个3-节点。
如果将值插⼊⼀个3-节点,分为以下⼏种情况。
(1).3-节点没有⽗节点,即整棵树就只有它⼀个三节点。
此时,将3-节点扩充为⼀个4-节点,即包含三个元素的节点,然后将其分解,变成⼀棵⼆叉树。
此时⼆叉树依然保持平衡。
(2).3-节点有⼀个2-节点的⽗节点,此时的操作是,3-节点扩充为4-节点,然后分解4-节点,然后将分解后的新树的⽗节点融⼊到2-节点的⽗节点中去。
红黑树(洛谷P3369【模板】普通平衡树)
红⿊树(洛⾕P3369【模板】普通平衡树)(以前学习的红⿊树,在今天写算法⼤作业的时候⽤到了,哈哈,即使研究⽣也要继续学习算法呀)红⿊树的五条性质:1) 节点颜⾊为红⾊或⿊⾊2) 根节点为⿊⾊3) 每⼀个叶⼦节点两个NIL节点也为⿊⾊4) 红⾊节点后继为⿊⾊5) 从根节点到叶⼦节点简单路径⿊⾼相同红⿊树是⼀颗⾃平衡的⼆叉查找树, 查询,插⼊,删除的时间复杂度都为O(logn)红⿊树简直就是⼀棵神奇的数据结构~~~~~~~~,我很想知道他们的灵感从哪⾥来的.据说红⿊树是2-3树的变形, RNtree的插⼊操作类⽐2-3树我还可以理解.但BRtree那个删除操作真的好简洁于奇妙~~向这些科学家致敬!!总结⼀下:(1) 插⼊节点z默认时红⾊, 可能违反的性质:1) z的parent节点颜⾊是红⾊2) 根节点是红⾊插⼊时关键要看叔叔节点(2) 删除节点y,并且⽤x节点代替,可能违反的性质1) 经过x的路径,⿊⾼减12) x的为红⾊,x的parent也是红3) x为根节点,颜⾊为红⾊删除时要看兄弟节点代码的逻辑时根据算法导论的逻辑写出, 并且经过洛⾕P3369习题验证(这是我提交过的最长代码.....1 #include <bits/stdc++.h>2using namespace std;3#define RED 14#define BLACK 05#define RBnode node<T> *67 template <class T>8struct node {9 T key;10int sum; //sum⼦树节点数11bool color;12 node *p, *left, *right;13 node() {14 sum = 0; color = BLACK;15 }16 node(T key, int sum, int color, node *p, node *left, node *right) :17 key(key), sum(sum), color(color), p(p), left(left), right(right) {}18void up() {19 sum = 1 + left->sum + right->sum; // nil节点不更新20 }21 };2223 template <class T>24class RBtree {25private:26 RBnode rt;27 RBnode nil;28public:29 RBtree() {30 nil = new node<T>();31 nil->p = nil->left = nil->right = nil;32 rt = nil;33 }38 cout << "key: " << x->key << " color:" << x->color << " sum: " << x->sum << endl;39 mid_print(x->right);40 }4142void my_print() {43 mid_print(rt);44 }4546void insert(T key) {47 RBnode z = new node<T>(key, 1, RED, nil, nil, nil);48 RBnode y = nil; // y: x的parent;49 RBnode x = rt;50while (x != nil) {51 y = x;52if (z->key <= x->key)53 x = x->left;54else55 x = x->right;56 }57 z->p = y; // 特别的根节点⽗节点是nil58if (y == nil)59 rt = z;60else if (z->key <= y->key)61 y->left = z;62else63 y->right = z;64// sum的改变65while (y != nil) {66 y->up();67 y = y->p;68 }69 insert_fixup(z);70 }7172// 可能违反的性质:73// 1)z的parent节点颜⾊是红⾊74// 2)根节点是红⾊75void insert_fixup(RBnode z) { // 插⼊看叔叔节点76while (z->p->color == RED) {77if (z->p == z->p->p->left) {78 RBnode uncle = z->p->p->right;79if (uncle->color == RED) { // case1 叔叔节点是红⾊; 叔叔和⽗亲加⼀层⿊⾊,祖⽗层变⿊(⿊⾊上移)80 z->p->color = BLACK;81 uncle->color = BLACK;82 z->p->p->color = RED;83 z = z->p->p;84 }85else {86if (z->p->right == z) { // case2 叔叔是⿊⾊, 祖孙三代不在⼀条直线, 调整到case387 z = z->p;88 left_rotate(z);89 }90 z->p->color = BLACK; // case3 调整过后,冲突解决91 z->p->p->color = RED;92 right_rotate(z->p->p);93 }94 }95else {96 RBnode uncle = z->p->p->left;97if (uncle->color == RED) { // case198 z->p->color = BLACK;99 uncle->color = BLACK;100 z->p->p->color = RED;101 z=z->p->p;102 }103else {104if (z->p->left == z) { // case 2105 z = z->p;106 right_rotate(z);107 }108 z->p->color = BLACK; // case 3109 z->p->p->color = RED;110 left_rotate(z->p->p);111 }112 }113 }114 rt->color = BLACK;115 }116117// 旋转的性质: 左旋或右旋后,交换两节点的颜⾊不改变⿊⾼(⾃我总结)118void left_rotate(RBnode x) {122 y->left->p = x;123 y->p = x->p;124if (x->p == nil)125 rt = y;126else if (x->p->left == x)127 x->p->left = y;128else129 x->p->right = y;130 y->left = x;131 x->p = y;132if (x!=nil) x->up(); // 先调整x,再调整y133if (y!=nil) y->up();134 }135136void right_rotate(RBnode x) {137 RBnode y = x->left;138 x->left = y->right;139 y->p = x->p;140if (y->right != nil)141 y->right->p = x;142if (x->p == nil)143 rt = y;144else if (x->p->left == x)145 x->p->left = y;146else147 x->p->right = y;148 y->right = x;149 x->p = y;150if (x!=nil) x->up();151if (x!=nil) y->up();152 }153154 RBnode min_mum(RBnode x) {155while (x->left != nil)156 x = x->left;157return x;158 }159160 RBnode max_mum(RBnode x) {161while (x->right != nil)162 x = x->right;163return x;164 }165166 RBnode low_find(int k) { // 寻找⽐k⼩且最⼤的节点167return _low(k,rt);168 }169170 RBnode _low (int k, RBnode x) {171if (x==nil) return x;172if (k<=x->key) return _low(k,x->left);173else {174 RBnode ans=_low(k,x->right);175if (ans!=nil) return ans;176else return x;177 }178 }179180 RBnode upp_find(T k) { // 寻找⽐k⼤且最⼩的节点181return _upp(k,rt);182 }183184 RBnode _upp (T k, RBnode x) {185if (x==nil) return x;186if (k>=x->key) return _upp(k,x->right);187else {188 RBnode ans=_upp(k,x->left);189if (ans!=nil) return ans;190else return x;191 }192 }193194 RBnode rfind(T key) { // 相等元素的最后⼀个节点195 RBnode x = rt;196while (x != nil) {197if (key<x->key)198 x = x->left;199else if (key>x->key)200 x = x->right;201else202return x;204return x;205 }206207 RBnode find(T key) { // 相等元素第⼀个节点208return my_find(key, rt);209 }210211 RBnode my_find(T key, RBnode x) {212if (x == nil) return nil;213if (key<x->key) return my_find(key, x->left);214if (key == x->key) {215 RBnode ans = my_find(key, x->left);216if (ans == nil) return x;217else return ans;218 }219return my_find(key, x->right);220 }221222 RBnode find_kth(int k) { // 排名第k的元素, 相等的元素具有不同的排名223 RBnode x = rt;224if (rt->sum<k) return nil;225while (k != x->left->sum + 1) {226if (k <= x->left->sum)227 x = x->left;228else {229 k -= x->left->sum + 1;230 x = x->right;231 }232 }233return x;234 }235236int get_rank(RBnode x) { // 寻找节点x的排名237 RBnode t=rt; int k=0;238while (t!=x) {239if (x->key<=t->key)240 t=t->left;241else {242 k+=t->left->sum+1;243 t=t->right;244 }245 }246return k+t->left->sum+1;247 }248249void transplate(RBnode y, RBnode x) { // 以节点x代替y,但不对y的⼦节点经⾏替换250if (y->p == nil)251 rt = x;252else if (y->p->left == y)253 y->p->left = x;254else255 y->p->right = x;256 x->p = y->p;257 }258259void remove(RBnode z) { // y: 要删除的节点 x: 代替的节点260 RBnode y = z;261 RBnode x;262int ycolor = y->color;263if (y->left == nil) {264 x = y->right;265 transplate(y, x);266 }267else if (y->right == nil) {268 x = y->left;269 transplate(y, x);270 }271else {272 y = min_mum(y->right);273 ycolor = y->color;274 x = y->right;275if (y->p == z)276 x->p = y; // x可能是nil节点,因此需要记录其⽗亲277else {278 transplate(y, x);279 y->right = z->right;280 z->right->p = y;281 }282 transplate(z,y);283 y->left = z->left;284 z->left->p = y;285 y->color = z->color; // y代替z,但颜⾊不改变286 y = z; // y指向废弃节点288if (ycolor == BLACK)289 remove_fixup(x);290 RBnode t=x->p; // 最后调整sum291while (t!=nil) {292 t->up();293 t=t->p;294 }295delete y;296 }297298// 可能有冲突:299// 1)经过x的路径,⿊⾼减1300// 2)x的为红⾊,x的parent也是红301// 3)x为根节点,颜⾊为红⾊302void remove_fixup(RBnode x) { // 看兄弟节点 // 减少x多的⼀重⿊⾊303while (x != rt&&x->color == BLACK) {304if (x == x->p->left) {305 RBnode bro = x->p->right;306if (bro->color == RED) { // case1 兄弟节点为红⾊,转化为情况234307 bro->color = BLACK;308 bro->p->color = RED;309 left_rotate(x->p);310 bro = x->p->right;311 }312if (bro->left->color == BLACK&&bro->right->color == BLACK) { // case2 兄弟节点及其⼉⼦节点都为⿊⾊313 bro->color = RED;314 x = x->p;315 }316else {317if (bro->right->color == BLACK) { // case3 兄弟右节点不为红⾊318 bro->color = RED;319 bro->left->color = BLACK;320 right_rotate(bro);321 bro = x->p->right;322 }323 bro->right->color = BLACK; //case4 兄弟右孩⼦节点为红⾊,调整之后结束循环324 bro->color = bro->p->color;325 bro->p->color = BLACK;326 left_rotate(x->p);327 x = rt; // 终⽌递归328 }329 }330else {331 RBnode bro = x->p->left;332if (bro->color == RED) { // case 1333 bro->color = BLACK;334 bro->p->color = RED;335 right_rotate(x->p);336 bro = x->p->left;337 }338if (bro->left->color == BLACK&&bro->right->color == BLACK) { // case 2339 bro->color = RED;340 x = x->p;341 }342else {343if (bro->left->color == BLACK) { // case 3344 bro->color = RED;345 bro->right->color = BLACK;346 left_rotate(bro);347 bro = x->p->left;348 }349 bro->left->color = BLACK; // case 4350 bro->color = bro->p->color;351 bro->p->color = BLACK;352 right_rotate(x->p);353 x = rt;354 }355 }356 }357 x->color = BLACK;358 }359360 RBnode successor(RBnode x) { // 后继节点361if (x->right != nil)362return min_mum(x->right);363 RBnode y = x->p;364while (y != nil && y->right == x) {365 x = y;366 y = y->p;367 }368return y;369 }370372if (x->left != nil)373return max_mum(x->left);374 RBnode y = x->p;375while (y != nil && y->left == x) {376 x = y;377 y = y->p;378 }379return y;380 }381382 };383384int main()385 {386387 RBtree<int> tree;388int n; scanf("%d",&n);389while (n--) {390int op,x; scanf("%d %d",&op,&x);391if (op==1) tree.insert(x);392else if(op==2) {393 node<int>* nd=tree.rfind(x);394 tree.remove(nd);395 }396else if(op==3) {397 node<int>* nd=tree.find(x);398 printf("%d\n",tree.get_rank(nd));399 }400else if (op==4) printf("%d\n",tree.find_kth(x)->key); 401else if (op==5) printf("%d\n",tree.low_find(x)->key); 402else printf("%d\n",tree.upp_find(x)->key); 403 }404return0;405 }。
java算法实现红黑树完整代码示例
java算法实现红⿊树完整代码⽰例红⿊树定义红⿊树(英语:Red–black tree)是⼀种⾃平衡⼆叉查找树,是在计算机科学中⽤到的⼀种数据结构,典型的⽤途是实现关联数组。
红⿊树的另⼀种定义是含有红⿊链接并满⾜下列条件的⼆叉查找树:红链接均为左链接;没有任何⼀个结点同时和两条红链接相连;该树是完美⿊⾊平衡的,即任意空链接到根结点的路径上的⿊链接数量相同。
满⾜这样定义的红⿊树和相应的2-3树是⼀⼀对应的。
旋转旋转⼜分为左旋和右旋。
通常左旋操作⽤于将⼀个向右倾斜的红⾊链接旋转为向左链接。
对⽐操作前后,可以看出,该操作实际上是将红线链接的两个节点中的⼀个较⼤的节点移动到根节点上。
左旋操作如下图:右旋旋操作如下图:即:复杂度红⿊树的平均⾼度⼤约为lgN。
下图是红⿊树在各种情况下的时间复杂度,可以看出红⿊树是2-3查找树的⼀种实现,他能保证最坏情况下仍然具有对数的时间复杂度。
Java代码import java.util.NoSuchElementException;import java.util.Scanner;public class RedBlackBST<key extends="" key="">, Value> {private static final boolean RED = true;private static final boolean BLACK = false;private Node root; //root of the BSTprivate class Node {private Key key; //keyprivate Value val; //associated dataprivate Node left, right; //links to left and right subtreesprivate boolean color; //color of parent linkprivate int size; //subtree countpublic Node(Key key, Value val, boolean color, int size) {this.key = key;this.val = val;this.color = color;this.size = size;}}//is node x red?private boolean isRed(Node x) {if(x == null) {return false;}return x.color == RED;}//number of node in subtree rooted at x; 0 if x is nullprivate int size(Node x) {if(x == null) {return 0;}return x.size;}/*** return the number of key-value pairs in this symbol table* @return the number of key-value pairs in this symbol table*/public int size() {return size(root);}/*** is this symbol table empty?* @return true if this symbol table is empty and false otherwise*/public boolean isEmpty() {return root == null;}/*** return the value associated with the given key* @param key the key* @return the value associated with the given key if the key is in the symbol table, and null if it is not. */public Value get(Key key) {if(key == null) {throw new NullPointerException("argument to get() is null");}return get(root, key);}//value associated with the given key in subtree rooted at x; null if no such keyprivate Value get(Node x, Key key) {while(x != null) {int cmp = pareTo(x.key);if(cmp < 0) {x = x.left;}else if(cmp > 0) {x = x.right;}else {return x.val;}}return null;}/*** does this symbol table contain the given key?* @param key the key* @return true if this symbol table contains key and false otherwise*/public boolean contains(Key key) {return get(key) != null;}/**************************************************************************** Red-black tree insertion.***************************************************************************//*** Inserts the specified key-value pair into the symbol table, overwriting the old* value with the new value if the symbol table already contains the specified key.* Deletes the specified key (and its associated value) from this symbol table* if the specified value is null.** @param key the key* @param val the value* @throws NullPointerException if key is null*/public void put(Key key, Value val) {if (key == null) {throw new NullPointerException("first argument to put() is null");}if (val == null) {delete(key);return;}root = put(root, key, val);root.color = BLACK;}// insert the key-value pair in the subtree rooted at hprivate Node put(Node h, Key key, Value val) {if(h == null) {return new Node(key, val, RED, 1);}int cmp = pareTo(h.key);if(cmp < 0) {h.left = put(h.left, key, val);}else if(cmp > 0) {h.right = put(h.right, key, val);}else {h.val = val;}if(isRed(h.right) && !isRed(h.left)) {h = rotateLeft(h);}if(isRed(h.left) && isRed(h.left.left)) {h = rotateRight(h);}if(isRed(h.left) && isRed(h.right)) {flipColors(h);}h.size = size(h.left) + size(h.right) + 1;return h;}/**************************************************************************** Red-black tree deletion.***************************************************************************//*** Removes the smallest key and associated value from the symbol table. * @throws NoSuchElementException if the symbol table is empty*/public void deleteMin() {if (isEmpty()) {throw new NoSuchElementException("BST underflow");}// if both children of root are black, set root to redif (!isRed(root.left) && !isRed(root.right))root.color = RED;root = deleteMin(root);if (!isEmpty()) root.color = BLACK;// assert check();}// delete the key-value pair with the minimum key rooted at h// delete the key-value pair with the minimum key rooted at hprivate Node deleteMin(Node h) {if (h.left == null){return null;}if (!isRed(h.left) && !isRed(h.left.left)) {h = moveRedLeft(h);}h.left = deleteMin(h.left);return balance(h);}/*** Removes the largest key and associated value from the symbol table. * @throws NoSuchElementException if the symbol table is empty*/public void deleteMax() {if (isEmpty()) {throw new NoSuchElementException("BST underflow");}// if both children of root are black, set root to redif (!isRed(root.left) && !isRed(root.right))root.color = RED;root = deleteMax(root);if (!isEmpty()) root.color = BLACK;// assert check();}// delete the key-value pair with the maximum key rooted at h// delete the key-value pair with the maximum key rooted at hprivate Node deleteMax(Node h) {if (isRed(h.left))h = rotateRight(h);if (h.right == null)return null;if (!isRed(h.right) && !isRed(h.right.left))h = moveRedRight(h);h.right = deleteMax(h.right);return balance(h);}/*** remove the specified key and its associated value from this symbol table * (if the key is in this symbol table).** @param key the key* @throws NullPointerException if key is null*/public void delete(Key key) {if (key == null) {throw new NullPointerException("argument to delete() is null");}if (!contains(key)) {return;}//if both children of root are black, set root to redif(!isRed(root.left) && !isRed(root.right)) {root.color = RED;}root = delete(root, key);if(!isEmpty()) {root.color = BLACK;}}// delete the key-value pair with the given key rooted at h// delete the key-value pair with the given key rooted at hprivate Node delete(Node h, Key key) {if(pareTo(h.key) < 0) {if(!isRed(h.left) && !isRed(h.left.left)) {h = moveRedLeft(h);}h.left = delete(h.left, key);}else {if(isRed(h.left)) {h = rotateRight(h);}if (pareTo(h.key) == 0 && (h.right == null)) {return null;}if (!isRed(h.right) && !isRed(h.right.left)) {h = moveRedRight(h);}if (pareTo(h.key) == 0) {Node x = min(h.right);h.key = x.key;h.val = x.val;h.right = deleteMin(h.right);}else {h.right = delete(h.right, key);}}return balance(h);}/**************************************************************************** Red-black tree helper functions.***************************************************************************/// make a left-leaning link lean to the right// make a left-leaning link lean to the rightprivate Node rotateRight(Node h) {// assert (h != null) && isRed(h.left);Node x = h.left;h.left = x.right;x.right = h;x.color = x.right.color;x.right.color = RED;x.size = h.size;h.size = size(h.left) + size(h.right) + 1;return x;}// make a right-leaning link lean to the left// make a right-leaning link lean to the leftprivate Node rotateLeft(Node h) {// assert (h != null) && isRed(h.right);Node x = h.right;h.right = x.left;x.left = h;x.color = x.left.color;x.left.color = RED;x.size = h.size;h.size = size(h.left) + size(h.right) + 1;return x;}// flip the colors of a node and its two children// flip the colors of a node and its two childrenprivate void flipColors(Node h) {// h must have opposite color of its two children// assert (h != null) && (h.left != null) && (h.right != null);// assert (!isRed(h) && isRed(h.left) && isRed(h.right))// || (isRed(h) && !isRed(h.left) && !isRed(h.right));h.color = !h.color;h.left.color = !h.left.color;h.right.color = !h.right.color;}// Assuming that h is red and both h.left and h.left.left// are black, make h.left or one of its children red.// Assuming that h is red and both h.left and h.left.left// are black, make h.left or one of its children red.private Node moveRedLeft(Node h) {// assert (h != null);// assert isRed(h) && !isRed(h.left) && !isRed(h.left.left);flipColors(h);if (isRed(h.right.left)) {h.right = rotateRight(h.right);h = rotateLeft(h);flipColors(h);}return h;}// Assuming that h is red and both h.right and h.right.left// are black, make h.right or one of its children red.// Assuming that h is red and both h.right and h.right.left// are black, make h.right or one of its children red.private Node moveRedRight(Node h) {// assert (h != null);// assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);flipColors(h);if (isRed(h.left.left)) {h = rotateRight(h);flipColors(h);}return h;}// restore red-black tree invariant// restore red-black tree invariantprivate Node balance(Node h) {// assert (h != null);if (isRed(h.right)) {h = rotateLeft(h);}if (isRed(h.left) && isRed(h.left.left)) {h = rotateRight(h);}if (isRed(h.left) && isRed(h.right)) {flipColors(h);}h.size = size(h.left) + size(h.right) + 1;return h;}/*************************************************************************** * Utility functions.***************************************************************************//*** Returns the height of the BST (for debugging).* @return the height of the BST (a 1-node tree has height 0)*/public int height() {return height(root);}private int height(Node x) {if (x == null) {return -1;}return 1 + Math.max(height(x.left), height(x.right));}/**************************************************************************** Ordered symbol table methods.***************************************************************************//*** Returns the smallest key in the symbol table.* @return the smallest key in the symbol table* @throws NoSuchElementException if the symbol table is empty*/public Key min() {if (isEmpty()) {throw new NoSuchElementException("called min() with empty symbol table"); }return min(root).key;}// the smallest key in subtree rooted at x; null if no such keyprivate Node min(Node x) {// assert x != null;if (x.left == null) {return x;}else {return min(x.left);}}/*** Returns the largest key in the symbol table.* @return the largest key in the symbol table* @throws NoSuchElementException if the symbol table is empty*/public Key max() {if (isEmpty()) {throw new NoSuchElementException("called max() with empty symbol table"); }return max(root).key;}// the largest key in the subtree rooted at x; null if no such keyprivate Node max(Node x) {// assert x != null;if (x.right == null) {return x;}else {return max(x.right);}}/*** Returns the largest key in the symbol table less than or equal to key.* @param key the key* @return the largest key in the symbol table less than or equal to key* @throws NoSuchElementException if there is no such key* @throws NullPointerException if key is null*/public Key floor(Key key) {if (key == null) {throw new NullPointerException("argument to floor() is null");}if (isEmpty()) {throw new NoSuchElementException("called floor() with empty symbol table"); }Node x = floor(root, key);if (x == null) {return null;}else {return x.key;}}// the largest key in the subtree rooted at x less than or equal to the given keyprivate Node floor(Node x, Key key) {if (x == null) {return null;}int cmp = pareTo(x.key);if (cmp == 0) {return x;}if (cmp < 0) {return floor(x.left, key);}Node t = floor(x.right, key);if (t != null) {return t;}else {return x;}}/*** Returns the smallest key in the symbol table greater than or equal to key.* @param key the key* @return the smallest key in the symbol table greater than or equal to key* @throws NoSuchElementException if there is no such key* @throws NullPointerException if key is null*/public Key ceiling(Key key) {if (key == null) {throw new NullPointerException("argument to ceiling() is null");}if (isEmpty()) {throw new NoSuchElementException("called ceiling() with empty symbol table"); }Node x = ceiling(root, key);if (x == null) {return null;}else {return x.key;}}// the smallest key in the subtree rooted at x greater than or equal to the given key private Node ceiling(Node x, Key key) {if (x == null) {return null;}int cmp = pareTo(x.key);if (cmp == 0) {return x;}if (cmp > 0) {return ceiling(x.right, key);}Node t = ceiling(x.left, key);if (t != null) {return t;}else {return x;}}/*** Return the kth smallest key in the symbol table.* @param k the order statistic* @return the kth smallest key in the symbol table* @throws IllegalArgumentException unless k is between 0 and* <em>N</em> − 1*/public Key select(int k) {if (k < 0 || k >= size()) {throw new IllegalArgumentException();Node x = select(root, k);return x.key;}// the key of rank k in the subtree rooted at xprivate Node select(Node x, int k) {// assert x != null;// assert k >= 0 && k < size(x);int t = size(x.left);if (t > k) {return select(x.left, k);}else if (t < k) {return select(x.right, k-t-1);}else {return x;}}/*** Return the number of keys in the symbol table strictly less than key. * @param key the key* @return the number of keys in the symbol table strictly less than key * @throws NullPointerException if key is null*/public int rank(Key key) {if (key == null) {throw new NullPointerException("argument to rank() is null");}return rank(key, root);}// number of keys less than key in the subtree rooted at xprivate int rank(Key key, Node x) {if (x == null) {return 0;}int cmp = pareTo(x.key);if (cmp < 0) {return rank(key, x.left);}else if (cmp > 0) {return 1 + size(x.left) + rank(key, x.right);}else {return size(x.left);}}/**************************************************************************** Range count and range search.***************************************************************************//*** Returns all keys in the symbol table as an Iterable.* To iterate over all of the keys in the symbol table named st,* use the foreach notation: for (Key key : st.keys()).* @return all keys in the symbol table as an Iterable*/public Iterable<key> keys() {if (isEmpty()) {return new Queue<key>();}return keys(min(), max());}/*** Returns all keys in the symbol table in the given range,* as an Iterable.* @return all keys in the symbol table between lo* (inclusive) and hi (exclusive) as an Iterable* @throws NullPointerException if either lo or hi* is null*/public Iterable<key> keys(Key lo, Key hi) {if (lo == null) {throw new NullPointerException("first argument to keys() is null");}if (hi == null) {throw new NullPointerException("second argument to keys() is null");Queue<key> queue = new Queue<key>();// if (isEmpty() || pareTo(hi) > 0) return queue;keys(root, queue, lo, hi);return queue;}// add the keys between lo and hi in the subtree rooted at x// to the queueprivate void keys(Node x, Queue<key> queue, Key lo, Key hi) {if (x == null) {return;}int cmplo = pareTo(x.key);int cmphi = pareTo(x.key);if (cmplo < 0) {keys(x.left, queue, lo, hi);}if (cmplo <= 0 && cmphi >= 0) {queue.enqueue(x.key);}if (cmphi > 0) {keys(x.right, queue, lo, hi);}}/*** Returns the number of keys in the symbol table in the given range.* @return the number of keys in the symbol table between lo* (inclusive) and hi (exclusive)* @throws NullPointerException if either lo or hi* is null*/public int size(Key lo, Key hi) {if (lo == null) {throw new NullPointerException("first argument to size() is null");}if (hi == null) {throw new NullPointerException("second argument to size() is null");}if (pareTo(hi) > 0) {return 0;}if (contains(hi)) {return rank(hi) - rank(lo) + 1;}else {return rank(hi) - rank(lo);}}/**************************************************************************** Check integrity of red-black tree data structure.***************************************************************************/private boolean check() {if (!isBST()) System.out.println("Not in symmetric order");if (!isSizeConsistent()) System.out.println("Subtree counts not consistent");if (!isRankConsistent()) System.out.println("Ranks not consistent");if (!is23()) System.out.println("Not a 2-3 tree");if (!isBalanced()) System.out.println("Not balanced");return isBST() && isSizeConsistent() && isRankConsistent() && is23() && isBalanced(); }// does this binary tree satisfy symmetric order?// Note: this test also ensures that data structure is a binary tree since order is strictprivate boolean isBST() {return isBST(root, null, null);}// is the tree rooted at x a BST with all keys strictly between min and max// (if min or max is null, treat as empty constraint)// Credit: Bob Dondero's elegant solutionprivate boolean isBST(Node x, Key min, Key max) {if (x == null) {return true;}if (min != null && pareTo(min) <= 0) {return false;}if (max != null && pareTo(max) >= 0) {return false;return isBST(x.left, min, x.key) && isBST(x.right, x.key, max);}// are the size fields correct?private boolean isSizeConsistent() {return isSizeConsistent(root);}private boolean isSizeConsistent(Node x) {if (x == null) {return true;}if (x.size != size(x.left) + size(x.right) + 1) {return false;}return isSizeConsistent(x.left) && isSizeConsistent(x.right);}// check that ranks are consistentprivate boolean isRankConsistent() {for (int i = 0; i < size(); i++) {if (i != rank(select(i))) {return false;}}for (Key key : keys()) {if (pareTo(select(rank(key))) != 0) {return false;}}return true;}// Does the tree have no red right links, and at most one (left)// red links in a row on any path?private boolean is23() {return is23(root);}private boolean is23(Node x) {if (x == null) {return true;}if (isRed(x.right)) {return false;}if (x != root && isRed(x) && isRed(x.left)){return false;}return is23(x.left) && is23(x.right);}// do all paths from root to leaf have same number of black edges?private boolean isBalanced() {int black = 0; // number of black links on path from root to minNode x = root;while (x != null) {if (!isRed(x)) black++;x = x.left;}return isBalanced(root, black);}// does every path from the root to a leaf have the given number of black links? private boolean isBalanced(Node x, int black) {if (x == null) {return black == 0;}if (!isRed(x)) {black--;}return isBalanced(x.left, black) && isBalanced(x.right, black);}/*** Unit tests the RedBlackBST data type.*/public static void main(String[] args) {RedBlackBST<string, integer=""> st = new RedBlackBST<string, integer="">(); String data = "a b c d e f g h m n o p";Scanner sc = new Scanner(data);int i = 0;while (sc.hasNext()) {String key = sc.next();st.put(key, i);i++;}sc.close();for (String s : st.keys())System.out.println(s + " " + st.get(s));System.out.println();boolean result = st.check();System.out.println("check: " + result);}}输出:<code>a 0b 1c 2d 3e 4f 5g 6h 7m 8n 9o 10p 11check: true</code>总结以上就是本⽂关于java算法实现红⿊树完整代码⽰例的全部内容,希望对⼤家有所帮助。
红黑树
红黑树之前看了很多写红黑树的博客,但是感觉都讲的不太清楚!没说这样操作如何使他保持平衡的,于是疑惑重重,就看不下去了,一次不经意看到一个人说维基百科的红黑树讲的好,我就随便点了一下一看——这下疯了~,怎么讲的这么好!可以说是把一个复杂的问题,讲得简单化!这太幸福了!于是我就慢慢学会了!强烈推荐维基的这个讲解,再也找不到比这还好的讲解了!不知道它上边其它的怎么样,反正这个很好!!既然学会了,走过来了,我也要留下脚印!下面将是我对红黑树的总结,里面的性感的图片都是维基百科红黑树上的^_^!我讨论的红黑树需建立在会平衡二叉树的基础上去学,即若不懂“旋转”操作,请看平衡二叉树的旋转操作。
红黑树(RBT)的定义:它或者是一颗空树,或者是具有一下性质的二叉查找树:1.节点非红即黑。
2.根节点是黑色。
3.所有NULL结点称为叶子节点,且认为颜色为黑。
4.所有红节点的子节点都为黑色。
5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。
看完红黑树的定义是不是可晕?怎么这么多要求!!这怎么约束啊?我刚看到这5条约束,直接无语了,1-3、4还好说,第5点是怎么回事啊?怎么约束?整这么复杂的条件好干啥啊?我来简单说说呵:第3条,显然这里的叶子节点不是平常我们所说的叶子节点,如图标有NIL的为叶子节点,为什么不按常规出牌,因为按一般的叶子节点也行,但会使算法更复杂;第4条,即该树上决不允许存在两个连续的红节点;第5条,比如图中红8到1左边的叶子节点的路径包含2个黑节点,到6下的叶子节点的路径也包含2个黑节点。
所有性质1-5合起来约束了该树的平衡性能--即该树上的最长路径不可能会大于2倍最短路径。
为什么?因为第1条该树上的节点非红即黑,由于第4条该树上不允许存在两个连续的红节点,那么对于从一个节点到其叶子节点的一条最长的路径一定是红黑交错的,那么最短路径一定是纯黑色的节点;而又第5条从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点,这么来说最长路径上的黑节点的数目和最短路径上的黑节点的数目相等!而又第2条根结点为黑、第3条叶子节点是黑,那么可知:最长路径<=2*最短路径。
第13章-红黑树
第13章红黑树第12章我们讨论了在高度为h的二叉查找树能够在O(h)时间完成任何动态集操作,比如查找(SEARCH),前躯(PREDECESSOR),后继(SUCCESSOR),最小值(MINIMUM),最大值(MAXIMUM),插入(INSERT)和删除(DELETE)操作。
因此,如果树高矮的时候这些动态集的操作是很快的。
如果树高很高的话,那么这些动态集的操作就没有链表快了。
红黑树是众多“均衡”查找树中的一种,它可以保证基本的动态集操作在最坏的情况下运行时间为O(lg n)。
13.1 红黑树的性质红黑树是一棵二叉查找树,并且每个结点都附加一个额外的存储位:结点颜色,它的值可以是红色或者黑色。
通过对根到叶子路径上结点图色的限制,红色黑保证没有哪一条路径是其它路径的二倍长,所以这棵树大致上是平衡的。
现在每个结点都包含属性color,key,left,right和p。
如果结点没有孩子或者双亲结点不存在(译者著:根结点没有双亲结点,普通的叶子结点没有孩子),那么该结点的这些属性(译者著:孩子或者双亲指针)值是NIL。
我们把这些NIL当作二叉树中指向叶子(外部结点)的指针,正常包含key的结点为树的内部结点。
红黑树是一种二叉查找树,并且还满足下面的红黑性质:1.每个结点不是红色就是黑色。
2.根结点是黑色的。
3.每个叶子结点(NIL)都是黑色的。
4.如果一个结点是红色的,那么它所有的孩子都是黑色的。
5.对于每一个结点,从当前结点到后代的叶子的路径上包含黑色结点的数量是相同的。
图13.1(a)展示了一棵红黑树的例子。
为了方便处理边界条件,在实现红黑树的代码里,我们使用了一个哨兵结点也替换NIL(查看第238页)。
对于一棵红黑树T,哨兵T.nil是跟树中普通结点有同样属性的一个对象。
它的颜色是黑色,它的其它属性-p,left,right和key-可以是任意值。
如图13.1(b)所示,所有NIL指针都替换成指向哨兵结点T.nil.我们使用哨兵结点是为了我们可以把x结点的NIL孩子看成是x的一个普通的孩子。
红黑树
25 * @return 最大元素, 没有返回 null
26 */
27public T max(Node<T> n) {
28 Node<T> max = maxN(n);
29 return max == NIL ? null : max.value;
30}
31
32/**
33 * 获取某节点为根的树的最大节点
20 } else { //若 n 为父亲的右孩子
21
n.parent.right = rightChild;
22 }
23
24 //3.
25 rightChild.left = n;
26 n.parent = rightChild;
27}
28
29/**
30 * 右旋以 n 节点为根的子树:
31 * 1.将 leftChild 的右子树作为 n 的左子树
12
root = n;
13
inserted = true;
14
} else if (pareTo(pointer.value) > 0){ //向右子树找
15
if (pointer.right == NIL){ //插入右边
16
n.parent = pointer;
17
pointer.right = n;
9 if (n.parent == gp.left){ //若其父节点在其祖父节点左边
10
return gp.right;
11 } else {
12
return gp.left;
13 }
14}
15
16/**
17 * 获取祖父节点
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Case 2. uncle是黑色,并且z是z>parent的右子节点 这时我们只要把z指向z>parent,然后做一次Left Rotate(z) 就可以把情况转化成Case 3
Case 3. uncle是黑色,并且z是z>parent的左子节点 到了这一步,我们就剩最后一步了 只要把z >parent设成黑色,把grandfather设成红色,再做一次RightRotate(grandfather),整棵树就修补完毕 了 可以思考一下,这样一次操作之后,确实满足了所有红黑树的性质 Case 2和Case 3如下图:
如下图就是一棵红黑树:
28 浏览全部网志
网志分类
∙ 所有网志 ∙ program ∙ 未分类
站内搜索
搜索
友情链接
∙ 歪酷博客 ∙ 管理我的Blog ∙ jamie ∙ feemi ∙ lyrist ∙ tata ∙ allen ∙ richard
0170214
有了这几条规则,就可以保证整棵树的平衡,也就等于保证了搜索的时间为O(log N) 但是在插入 删除节点后,就有可能破坏了红黑树的性质 所以我们要做一些操作来把整棵树修补好 下面我就来介绍一下 首先有一个预备知识,那就是节点的LeftRotate和RightRotate操作 所谓LeftRotate(x)就是把节点x向 左下方向移动一格,然后让x原来的右子节点代替它的位置 而RightRotate当然就是把LeftRotate左 右互反一下 如下图:
反复进行迭代,直到某一次迭代开始时z>parent为黑色而告终,也就是当遇到Case 3后,做完它而告 终 二 删除 让我们来回顾一下二叉搜索树的删除节点z的过程:如果z没有子节点,那么直接删除即可;如果z只有一 个子节点,那么让这个子节点来代替z的位置,然后把z删除即可;如果z有两个子节点,那么找到z在中序 遍历中的后继节点s (也就是从z>rchild开始向左下方一直走到底的那一个节点),把s 的key赋值给z的 key,然后删除s
一 插入
插入首先是按部就班二叉搜索树的插入步骤,把新节点z插入到某一个叶节点的位置上 接下来把z的颜色设成红色 为什么?还记得红黑树的性质吗,从根节点向下到空节点的每一条路径上的 黑色节点数要相同 如果新插入的是黑色节点,那么它所在的路径上就多出了一个黑色的节点了 所以 新插入的节点一定要设成红色 但是这样可能又有一个矛盾,如果z的父节点也是红色,怎么办,前面说 过红色节点的子节点必须是黑色 因此我们要执行下面一个迭代的过程,称为InsertFixup,来修补这棵 红黑树
//一个节点在中序遍列中的前一个节点 关键词RB/TTaNgosd:ea*cmtr数ee据P结re构(RuBvTaN红od黑e*树node) {
RBTNode* result; 相关文章: if (node>lchild != m_null) {
result = treeMax(node>rchild); » ACM退役宣言 » 不e给ls力e_{Halo@杭州 » S1. Loroeksautldtata=sntroudcetur>epsaisretontF;ocus on theire strengths and weeknesses » 小遗憾R_BHTaNlood@ej*aktaertmap = node; » 惊天逆w转hi_lHealo(@re成su都lt != m_null && temp == result>lchild) {
在InsertFixup中,每一次迭代的开始,指针z一定都指向一个红色的节点 如果z>parent是黑色,那我 们就大功告成了;如果z>parent是红色,显然这就违返了红黑的树性质,那么我们要想办法把z或者z >parent变成黑色,但这要建立在不破坏红黑树的其他性质的基础上
这里再引入两个指针:grandfather,指向z>parent>parent,也就是z的爷爷(显然由于z>parent为红 色,grandfather一定是黑色);uncle,指向grandfather除了z>parent之外的另一个子节点,也就是z的 父亲的兄弟,所以叫uncle
红黑树的每个节点上的属性除了有一 个key 3个指针:parent lchild rchild以外,还多了一个属性: color 它只能是两种颜色:红或黑 而红黑树除了具有二叉搜索树的所有 性质之外,还具有以下4点性质:
1. 根节点是黑色的 2. 空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild rchild都不指向NULL,而是指向 一个定义好的空节点) 3. 红色节点的父 左子 右子节点都是黑色 4. 在任何一棵子树中,每一条从根节点向下走到空节点的路径上包含的黑色节点数量都相同
然而,如果x是黑色的,那我们就要假想x上背负了2个单位的黑色 那么红黑树的性质也同样不破坏,但 是我们要找到某一个红色的节点,把x上 超载 的这1个单位的黑色丢给它,这样才算完成 DeleteFixup 做的就是这个工作
DeleteFixup同样是一个循环迭代的过程 每一次迭代开始时,如果指针x指向一个红色节点,那么大功 告成,把它设成黑色即告终 相反如果x黑色,那么我们就会面对以下4种情况
else { result = node>parent; RBTNode* temp = node; while (result != m_null && temp == result>rchild) { temp = result; result = result>parent;
return result;
/post.1104022.html
2/6
3/28/12
-O
-
Ycool Blog
在红黑树中,删除一个节点z的方法也是首先按部就班以上的过程(当然,前面说的 如果 z 没有子节 点 等类似的判别条件,在红黑树中,要加上 除了空节点之外 这个前提) 如果删除的节点是黑色的,那么显然它所在的路径上就少一个黑色节点,那么红黑树的性质就被破坏 了 这时我们就要执行一个称为DeleteFixup的过程,来修补这棵树 下面我就来讲解一下
这里引入另一个指针w,指向x的兄弟 这里我们都默认x是x>parent的左子节点,则w是x>parent的右子 节点 (如果实际遇到相反的情况,只要把所有操作中的左 右互反一下就可以了 )
பைடு நூலகம்
Case 1. w是红色 这时我们根据红黑树的性质可以肯定x>parent是黑色 w>lchild是黑色 我们把x >parent与w的颜色互换,然后做一次LeftRotate(x>parent) 做完之后x就有了一个新的兄弟:原w >lchild,前面说过它一定是黑色的 那么我们就在不破坏红黑树性质的前提下,把Case 1转换成了 Case2 3 4中的一个,也就是w是黑色的情况 思考一下,这样做不会改变每条路径上黑色节点的个 数,如下图:
3/28/12
-O
-
O興
Ycool Blog
« 上一篇: 最优二叉搜索树
红黑树(附代码)
我很懒的 @ 20060216 19:02
下一篇: 单条路径的最大流 »
日历
三月 日一二 三 四五六
(阅读本文之前请先了解二叉搜索 树) 红黑树(RedBlack Tree)是二叉搜 索树(Binary Search Tree)的一种 改进 我们知道二叉搜索树在最坏的 情况下可能会变成一个链表(当所有 节点按从小到大的顺序依次插入 后) 而红黑树在每一次插入或删除 节点之后都会花O(log N)的时间来 对树的结构作修改,以保持树的平 衡 也就是说,红黑树的查找方法与 二叉搜索树完全一样;插入和删除节 点的的方法前半部分节与二叉搜索树 完全一样,而后半部分添加了一些修 改树的结构的操作
/post.1104022.html
3/6
3/28/12
p = treeNext(p);
-O
-
Ycool Blog
//一个节点在中序遍列中的下一个节点 RBTNode* treeNext(RBTNode* node) { 以下是我的R红BT黑N树od代e*码r,e其su中lt的;所有函数都不包含递归(当然,由于树的层数不会很大,要写成递归也 可 #1以09)09(可hi以tftp用:/(/o它nrnoe来ldsineu解el>t决jurdUc=ghVeitA.lru#dev5ae4.!Me4=is(n/pm(h/_nvtt1nop0ud:/9/leo/l1n)>0lirn9{ce0h9jiu.hldtdmg)el;).uva.es /p/v5/544.htm l)和UVA
Case 3. w是黑色,并且w的两个子节点左红右黑 这时我们把w与w>lchild的颜色互换,然后做Right Rotate(w) 思考一下,这样做之后不会破坏红黑树的性质 这时x的新的兄弟就是原w>lchild 而Case 3被转化成了Case 4
Case 4. w是黑色,并且w的右子节点是红色 一但遇到Case 4,就胜利在望了 我看下面一张图 先把 w与x>parent的颜色互换,再做LeftRotate(x>parent) 这时图中节点E(也就是原w>rchild)所在的路 径就肯定少了一个黑色,而x所在的路径则多了一个黑色 那么我们就把x上多余的1个单位的黑色丢给E 就可以了 至此,DeleteFixup就顺利完成了
temp = result; 阅读全文(10761) / 评r论es/ u扔l小t纸=条re/ s给u我lt很>懒pa的r留en言t;/ 文件夹: program