博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
红黑树 -- 增删查改
阅读量:5039 次
发布时间:2019-06-12

本文共 6559 字,大约阅读时间需要 21 分钟。

1. 红黑树 -- 特性

  (1) 每个节点或者是黑色,或者是红色。

  (2) 根节点是黑色。
  (3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
  (4) 如果一个节点是红色的,则它的子节点必须是黑色的。
  (5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

2. Java -- 实现

package lime.xiaoniu;/** * @Author : LimeOracle * @Descri : * @Remark : * 红黑树的特性:(1)每个节点或者是黑色,或者是红色。(2)根节点是黑色。(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!](4)如果一个节点是红色的,则它的子节点必须是黑色的。(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。 *//** * @Author : LimeOracle * @Descri : * @Remark : * 注意:(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。 *//** * @Author : LimeOracle * @Descri : * @Remark : * 1.将红黑树当作一颗二叉查找树,将节点插入; * 2.将节点着色为红色; * 3.通过旋转和重新着色等方法来修正该树,使之重新成为一颗红黑树。        第二步中,将插入节点着色为"红色"之后,不会违背"特性(5)"。那它到底会违背哪些特性呢?        对于"特性(1)",显然不会违背了。因为我们已经将它涂成红色了。        对于"特性(2)",显然也不会违背。在第一步中,我们是将红黑树当作二叉查找树,然后执行的插入操作。而根据二叉查找数的特点,插入操作不会改变根节点。所以,根节点仍然是黑色。        对于"特性(3)",显然不会违背了。这里的叶子节点是指的空叶子节点,插入非空节点并不会对它们造成影响。        对于"特性(4)",是有可能违背的!        那接下来,想办法使之"满足特性(4)",就可以将树重新构造成红黑树了。 *//** * @Author : LimeOracle * @Descri : * @Remark : * 根据被插入节点的父节点的情况,可以将"当节点z被着色为红色节点,并插入二叉树"划分为三种情况来处理。    ① 情况说明:被插入的节点是根节点。    处理方法:直接把此节点涂为黑色。    ② 情况说明:被插入的节点的父节点是黑色。    处理方法:什么也不需要做。节点被插入后,仍然是红黑树。    ③ 情况说明:被插入的节点的父节点是红色。    处理方法:那么,该情况与红黑树的“特性(4)”相冲突。    这种情况下,被插入节点是一定存在非空祖父节点的;    进一步的讲,被插入节点也一定存在叔叔节点(即使叔叔节点为空,我们也视之为存在,空节点本身就是黑色节点)。    理解这点之后,我们依据"叔叔节点的情况",将这种情况进一步划分为3种情况(Case)。 */import com.sun.org.apache.regexp.internal.RE;import static lime.xiaoniu.RBTree.Color.BLACK;import static lime.xiaoniu.RBTree.Color.RED;/** * @Author : LimeOracle * @Descri : 依据"叔叔节点的情况",将这种情况进一步划分为3种情况(Case)。 * @Remark : * Case 1 *              B                        B *            /  \                     /  \ *          R      R        或       R     R *        /                                 \ *      CR                                  CR *  当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。 *      (01) 将“父节点”设为黑色。        (02) 将“叔叔节点”设为黑色。        (03) 将“祖父节点”设为“红色”。        (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。 * Case 2 *              B                       B *            /  \                    /  \ *          R     B         或       B    R *          \                            / *          CR                         CR * 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子 *      (01) 将“父节点”作为“新的当前节点”。        (02) 以“新的当前节点”为支点进行左旋。 * Case 3 *              B                      B *            /  \                   /  \ *          R     B         或      B    R *        /                               \ *      CR                                CR * 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子 *      (01) 将“父节点”设为“黑色”。        (02) 将“祖父节点”设为“红色”。        (03) 以“祖父节点”为支点进行右旋。 * * 上面三种情况(Case)处理问题的核心思路都是:将红色的节点移到根节点;然后,将根节点设为黑色。 */public class RBTree
> { private RBTNode
mRoot; enum Color{RED,BLACK} public class RBTNode
>{ Color color;//颜色 T key; //关键字(键值) RBTNode
left;//左孩子 RBTNode
right;//右孩子 RBTNode
parent;//父节点 public RBTNode(T key,Color color,RBTNode
parent,RBTNode
left,RBTNode
right){ this.key = key; this.color = color; this.parent = parent; this.left = left; this.right = right; } @Override public String toString() { return "RBTNode{" + "color=" + color + ", key=" + key + ", left=" + left + ", right=" + right + ", parent=" + parent + '}'; } } private void leftRotate(RBTNode
x){ RBTNode
y = x.right; x.right = y.left; if(null != y.left){ y.left.parent = x; } y.parent = x.parent; if(null == x.parent){ this.mRoot = y; }else{ if(x.parent.left == x){ x.parent.left = y; }else { x.parent.right = y; } } y.left = x; x.parent = y; } private void rightRotate(RBTNode x){ RBTNode y = x.left; x.left = y.right; if(null != y.right){ y.right.parent = x; } y.parent = x.parent; if(null == x.parent){ this.mRoot = y; }else{ if(x.parent.left == x){ x.parent.left = y; }else{ x.parent.right = y; } } y.right = x; x.parent = y; } private void insert(RBTNode
node){ int cmp; RBTNode
y = null; RBTNode
x = this.mRoot; // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。 while (x != null){ y = x; cmp = node.key.compareTo(x.key); if(cmp < 0){ x = x.left; }else{ x = x.right; } } node.parent = y; if(null != y){ cmp = node.key.compareTo(y.key); if(cmp < 0){ y.left = node; }else{ y.right = node; } }else{ this.mRoot = node; } // 2. 设置节点的颜色为红色 node.color = RED; // 3. 将它重新修正为一颗二叉查找树 insertFixUp(node); } public void insert(T key){ RBTNode
node = new RBTNode
(key,BLACK,null,null,null); if(null != node){ insert(node); } } /** * @Author : LimeOracle * @Descri : 红黑树插入修正函数 * @Remark : * 在向红黑树中插入节点之后(失去平衡),再调用该函数; * 目的是将它重新塑造成一颗红黑树。 */ private void insertFixUp(RBTNode
node){ RBTNode
parent,gparent; // 若“父节点存在,并且父节点的颜色是红色” while ((parent = node.parent) != null && RED == parent.color){ gparent = parent.parent; //若“父节点”是“祖父节点的左孩子” if(parent == gparent.left){ // Case 1条件:叔叔节点是红色// (01) 将“父节点”设为黑色。// (02) 将“叔叔节点”设为黑色。// (03) 将“祖父节点”设为“红色”。// (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。 RBTNode
uncle = gparent.right; if(uncle != null && RED == uncle.color){ parent.color = BLACK; uncle.color = BLACK; gparent.color = RED; node = gparent; continue; } // Case 2条件:叔叔是黑色,且当前节点是右孩子// (01) 将“父节点”作为“新的当前节点”。// (02) 以“新的当前节点”为支点进行左旋。 if(parent.right == node){ RBTNode
tmp; leftRotate(parent); tmp = parent;parent = node;node = tmp; } // Case 3条件:叔叔是黑色,且当前节点是左孩子。 if(parent.left == node){// (01) 将“父节点”设为“黑色”。// (02) 将“祖父节点”设为“红色”。// (03) 以“祖父节点”为支点进行右旋。 parent.color = BLACK; gparent.color = RED; rightRotate(gparent); } }else{ //若“z的父节点”是“z的祖父节点的右孩子” // Case 1条件:叔叔节点是红色 RBTNode
uncle = gparent.left; if(uncle.color == RED){ parent.color = BLACK; uncle.color = BLACK; gparent.color = RED; node = gparent; continue; } // Case 2条件:叔叔是黑色,且当前节点是左孩子 if(parent.left == node){ RBTNode
tmp; rightRotate(parent); tmp = parent;parent = node;node = parent; } // Case 3条件:叔叔是黑色,且当前节点是右孩子。 if(parent.right == node){ parent.color = BLACK; gparent.color = RED; leftRotate(gparent); } } } this.mRoot.color = BLACK; } public void inOrder(){ inOrder(this.mRoot); } private void inOrder(RBTNode
x){ if(null == x){ return; } inOrder(x.left); System.out.print(x.key + " "); inOrder(x.right); } public static void main(String[] args){ RBTree
root = new RBTree
(); root.insert(80); root.insert(40); root.insert(120); root.insert(20); root.insert(60); root.insert(100); root.insert(140); root.insert(10); root.insert(50); root.insert(90); root.insert(10); root.insert(30); root.inOrder(); }}

3. 鸣谢:

  

  

啦啦啦

转载于:https://www.cnblogs.com/ClassNotFoundException/p/7929154.html

你可能感兴趣的文章
bootstrap-Table服务端分页,获取到的数据怎么再页面的表格里显示
查看>>
进程间通信系列 之 socket套接字及其实例
查看>>
天气预报插件
查看>>
Unity 游戏框架搭建 (十三) 无需继承的单例的模板
查看>>
模块与包
查看>>
mysql忘记root密码
查看>>
apache服务器中设置目录不可访问
查看>>
嵌入式Linux驱动学习之路(十)字符设备驱动-my_led
查看>>
【NOIP模拟】密码
查看>>
java容器---------手工实现Linkedlist 链表
查看>>
three.js 性能优化的几种方法
查看>>
《梦断代码》读书笔记(三)
查看>>
FreeMarker解析json数据
查看>>
Java8 Lambda表达应用 -- 单线程游戏server+异步数据库操作
查看>>
次序+“选择不重复的记录”(3)——最大记录
查看>>
Codeforces 450 C. Jzzhu and Chocolate
查看>>
[Unity3D]Unity3D游戏开发MatchTarget的作用攀登效果实现
查看>>
ACdream 1115 Salmon And Cat (找规律&amp;&amp;打表)
查看>>
JSON、JSONP、Ajax的区别
查看>>
AngularJS学习篇(一)
查看>>