喵星之旅-沉睡的猫咪-红黑树
Posted kittybunny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了喵星之旅-沉睡的猫咪-红黑树相关的知识,希望对你有一定的参考价值。
本文建立在两个基础之上:1、会基本的java编程;2、对二叉树是认识的
具体的分类情况分析参看最下方视频连接:初级算法部分
红黑树概念
当一颗二叉树符合了如下要求后,就称之为红黑树:
1、节点具有颜色,只有红色或者黑色,只能是唯一颜色
2、二叉树是有序的,即每一个节点的左节点存值都比当前节点值小,右节点值比当前节点值不小
3、根结点和叶子节点为黑色,叶子节点值的是树的末端没有子节点的节点下一层,是不存有值的,叶子节点是空节点
4、如果一个节点是红色的,父节点必须是黑色的,也就是不存在连续的双红
5、对于黑色节点完全平衡,即从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
红黑树java实现
1、前置工作
创建一个树类
public class RBTree{ private static final boolean RED = false; private static final boolean BLACK = true; private RBTreeNode root; }
创建节点类
private static class RBTreeNode { private int value; private RBTreeNode up; private RBTreeNode left; private RBTreeNode right; private boolean color; }
节点类中编写遍历方法,方便bug查询和结果展示
public void show(int count, String lor) { String s = ""; for (int i = 0; i < count; i++) { s += " "; } s += lor + "[value=" + value + ", color=" + color + "]"; System.out.println(s); if (left != null) { left.show(count + 1, "l"); } if (right != null) { right.show(count + 1, "r"); } }
2、插入,由于旋转操作是针对于一般化的二叉树操作,只是方便复用,不会造成效率提升(无论这里的编码还是执行),这里不再封装左右旋转方法,针对红黑树直接处理。
/** * 添加节点 * @param n */ public void add(int n) { // 创建红色节点 RBTreeNode node = new RBTreeNode(n); // 查找要插入的位置,并且插入 insert(node, n); // 调整双红问题 tobalance(node); }
private void insert(RBTreeNode node, int n) { RBTreeNode p = this.root; if (p == null) { this.root = node; return; } for (;;) { if (p.value > n) { if (p.left == null) { p.left = node; node.up = p; break; } else { p = p.left; continue; } } else { if (p.right == null) { p.right = node; node.up = p; break; } else { p = p.right; continue; } } } }
/** * 调整双红问题 * @param node */ private void tobalance(RBTreeNode node) { RBTreeNode now = node; RBTreeNode up = null; RBTreeNode upup = null; RBTreeNode top = null; RBTreeNode n1 = null; RBTreeNode n2 = null; RBTreeNode n3 = null; RBTreeNode n4 = null; // 获得分类情况 for (boolean flag = true; flag;) { int n = sortForInsert(now); switch (n) {//含义参看上面方法说明 case 1: now.color = RBTree.BLACK; flag = false; break; case 2: flag = false; break; case 3: up = now.up; upup = up.up; upup.color = RBTree.RED; upup.left.color = RBTree.BLACK; upup.right.color = RBTree.BLACK; now = upup; break; case 4: up = now.up; upup = up.up; upup.color = RBTree.RED; upup.left.color = RBTree.BLACK; upup.right.color = RBTree.BLACK; now = upup; break; case 5: up = now.up; upup = up.up; n1 = up.right; n2 = upup.right; top = upup.up; up.color = RBTree.BLACK; upup.color = RBTree.RED; up.right = upup; upup.up = up; upup.left = n1; if (n1 != null) { n1.up = upup; } upup.right = n2; if (n2 != null) { n2.up = upup; } if (top == null) { root = up; root.up = null; } else { up.up = top; if (top.left == upup) { top.left = up; } else { top.right = up; } } flag = false; break; case 6: up = now.up; upup = up.up; top = upup.up; n1 = up.left; n2 = now.left; n3 = now.right; n4 = upup.right; now.color = RBTree.BLACK; upup.color = RBTree.RED; up.right = n2; if (n2 !=null) { n2.up = up; } up.up = now; now.left = up; now.right = upup; upup.up = now; upup.left = n3; if (n3 != null) { n3.up = upup; } if (top == null) { root = now; root.up = null; } else { now.up = top; if (top.left == upup) { top.left = now; } else { top.right = now; } } flag = false; break; case 7: up = now.up; upup = up.up; top = upup.up; n2 = now.left; n3 = now.right; now.color = RBTree.BLACK; upup.color = RBTree.RED; upup.right = n2; if (n2 != null) { n2.up = upup; } upup.up = now; now.left = upup; up.up = now; now.right = up; up.left = n3; if (n3 != null) { n3.up = up; } if (top == null) { root = now; root.up = null; } else { now.up = top; if (top.left == upup) { top.left = now; } else { top.right = now; } } flag = false; break; case 8: up = now.up; upup = up.up; top = upup.up; n2 = up.left; up.color = RBTree.BLACK; upup.color = RBTree.RED; upup.right = n2; if (n2 != null) { n2.up = upup; } upup.up = up; up.left = upup; if (top == null) { root = up; root.up = null; } else { up.up = top; if (top.left == upup) { top.left = up; } else { top.right = up; } } flag = false; break; } } root.color = RBTree.BLACK; }
/** * 对于插入操作,判断分类情况 * @param node * @return 分类情况:1-根结点,2-父节点黑色, 3-叔叔节点红色,父节点红色,父节点是左节点,4-叔叔节点红色,父节点红色,父节点是右节点, * 5-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点左孩子,6-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点右孩子, * 7-叔叔节点不是红色,父节点红色,父节点是 右节点,当前节点是父节点左孩子,8-叔叔节点不是红色,父节点红色,父节点是 * 右节点,当前节点是父节点右孩子 */ private int sortForInsert(RBTreeNode node) { if (node.up == null) { return 1; } else if (node.up.color == RBTree.BLACK) { return 2; } else { RBTreeNode up = node.up; RBTreeNode upup = up.up; if (up == upup.left) {// 父节点是左节点 if (upup.right == null || upup.right.color == RBTree.BLACK) { if (up.left == node) { return 5; } else { return 6; } } else { return 3; } } else {// 父节点是右节点 if (upup.left == null || upup.left.color == RBTree.BLACK) { if (up.left == node) { return 7; } else { return 8; } } else { return 4; } } } }
3、删除
待续;
测试结果
package club.kittybunn.test; import club.kittybunny.RBTree; public class Test { public static void main(String[] args) { RBTree tree = new RBTree(); tree.add(1); tree.add(2); tree.add(3); tree.add(4); tree.add(5); tree.add(6); tree.add(7); tree.add(8); tree.add(9); tree.add(10); tree.show(0, ""); } }
[value=4, color=true] l[value=2, color=true] l[value=1, color=true] r[value=3, color=true] r[value=6, color=true] l[value=5, color=true] r[value=8, color=false] l[value=7, color=true] r[value=9, color=true] r[value=10, color=false]
最终完整代码
package club.kittybunny; import java.util.TreeMap; import javax.sound.sampled.ReverbType; /** * * @author bunny~~我是兔子我会喵,我叫喵星兔。 * */ public class RBTree { private static final boolean RED = false; private static final boolean BLACK = true; private RBTreeNode root; /** * 添加节点 * @param n */ public void add(int n) { // 创建红色节点 RBTreeNode node = new RBTreeNode(n); // 查找要插入的位置,并且插入 insert(node, n); // 调整双红问题 tobalance(node); } /** * 调整双红问题 * @param node */ private void tobalance(RBTreeNode node) { RBTreeNode now = node; RBTreeNode up = null; RBTreeNode upup = null; RBTreeNode top = null; RBTreeNode n1 = null; RBTreeNode n2 = null; RBTreeNode n3 = null; RBTreeNode n4 = null; // 获得分类情况 for (boolean flag = true; flag;) { int n = sortForInsert(now); switch (n) {//含义参看上面方法说明 case 1: now.color = RBTree.BLACK; flag = false; break; case 2: flag = false; break; case 3: up = now.up; upup = up.up; upup.color = RBTree.RED; upup.left.color = RBTree.BLACK; upup.right.color = RBTree.BLACK; now = upup; break; case 4: up = now.up; upup = up.up; upup.color = RBTree.RED; upup.left.color = RBTree.BLACK; upup.right.color = RBTree.BLACK; now = upup; break; case 5: up = now.up; upup = up.up; n1 = up.right; n2 = upup.right; top = upup.up; up.color = RBTree.BLACK; upup.color = RBTree.RED; up.right = upup; upup.up = up; upup.left = n1; if (n1 != null) { n1.up = upup; } upup.right = n2; if (n2 != null) { n2.up = upup; } if (top == null) { root = up; root.up = null; } else { up.up = top; if (top.left == upup) { top.left = up; } else { top.right = up; } } flag = false; break; case 6: up = now.up; upup = up.up; top = upup.up; n1 = up.left; n2 = now.left; n3 = now.right; n4 = upup.right; now.color = RBTree.BLACK; upup.color = RBTree.RED; up.right = n2; if (n2 !=null) { n2.up = up; } up.up = now; now.left = up; now.right = upup; upup.up = now; upup.left = n3; if (n3 != null) { n3.up = upup; } if (top == null) { root = now; root.up = null; } else { now.up = top; if (top.left == upup) { top.left = now; } else { top.right = now; } } flag = false; break; case 7: up = now.up; upup = up.up; top = upup.up; n2 = now.left; n3 = now.right; now.color = RBTree.BLACK; upup.color = RBTree.RED; upup.right = n2; if (n2 != null) { n2.up = upup; } upup.up = now; now.left = upup; up.up = now; now.right = up; up.left = n3; if (n3 != null) { n3.up = up; } if (top == null) { root = now; root.up = null; } else { now.up = top; if (top.left == upup) { top.left = now; } else { top.right = now; } } flag = false; break; case 8: up = now.up; upup = up.up; top = upup.up; n2 = up.left; up.color = RBTree.BLACK; upup.color = RBTree.RED; upup.right = n2; if (n2 != null) { n2.up = upup; } upup.up = up; up.left = upup; if (top == null) { root = up; root.up = null; } else { up.up = top; if (top.left == upup) { top.left = up; } else { top.right = up; } } flag = false; break; } } root.color = RBTree.BLACK; } /** * 对于插入操作,判断分类情况 * @param node * @return 分类情况:1-根结点,2-父节点黑色, 3-叔叔节点红色,父节点红色,父节点是左节点,4-叔叔节点红色,父节点红色,父节点是右节点, * 5-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点左孩子,6-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点右孩子, * 7-叔叔节点不是红色,父节点红色,父节点是 右节点,当前节点是父节点左孩子,8-叔叔节点不是红色,父节点红色,父节点是 * 右节点,当前节点是父节点右孩子 */ private int sortForInsert(RBTreeNode node) { if (node.up == null) { return 1; } else if (node.up.color == RBTree.BLACK) { return 2; } else { RBTreeNode up = node.up; RBTreeNode upup = up.up; if (up == upup.left) {// 父节点是左节点 if (upup.right == null || upup.right.color == RBTree.BLACK) { if (up.left == node) { return 5; } else { return 6; } } else { return 3; } } else {// 父节点是右节点 if (upup.left == null || upup.left.color == RBTree.BLACK) { if (up.left == node) { return 7; } else { return 8; } } else { return 4; } } } } private void insert(RBTreeNode node, int n) { RBTreeNode p = this.root; if (p == null) { this.root = node; return; } for (;;) { if (p.value > n) { if (p.left == null) { p.left = node; node.up = p; break; } else { p = p.left; continue; } } else { if (p.right == null) { p.right = node; node.up = p; break; } else { p = p.right; continue; } } } } private static class RBTreeNode { private int value; private RBTreeNode up; private RBTreeNode left; private RBTreeNode right; private boolean color; /** * 颜色默认红色 * * @param value 节点值 */ public RBTreeNode(int value) { super(); this.value = value; this.color = RBTree.RED; } /** * * @param count 树深度 * @param lor 是父节点的左还是右节点,l-左,r-右 */ public void show(int count, String lor) { String s = ""; for (int i = 0; i < count; i++) { s += " "; } s += lor + "[value=" + value + ", color=" + color + "]"; System.out.println(s); if (left != null) { left.show(count + 1, "l"); } if (right != null) { right.show(count + 1, "r"); } } } public void show(int i, String string) { root.show(0, ""); } }
!-- @page>!-- @page>!-- @page>!-- @page>!-- @page>!-- @page>!-- @page>!-- @page>
以上是关于喵星之旅-沉睡的猫咪-红黑树的主要内容,如果未能解决你的问题,请参考以下文章