JAVA实践红黑树-小试牛刀
2016-08-24 20:42
197 查看
前言
第一感觉是和AVL树差别不是特别大,没有很直观的感受到效率的巨大提升,作为一个小小的强迫症患者,还是AVL树更好看。不过讲道理,平衡被破坏次数相同情况下,红黑树的确少了那么一些旋转。。。
因为插入节点后平衡被破坏时,红黑树的会选择旋转或变色。
AVL树则只有旋转。
另外我发现其他的大神写法,跟我的有点差距。。。有心人可以帮我瞄一眼,我是不是哪里错了,在此先谢过了~~
另外一个参考网站、博客、PDF:
红黑树的可视化,插入、删除节点都有动画效果哦~
神奇的讲义,略的比较多,但就胜在简略
一个大神的博客,思路清晰,详细,非常值得参考
实现功能
插入还有个伪删除。。。可以忽略,加个布尔变量的事。
不然咋叫小试牛刀呢(逃
参考
首先瞄一眼红黑树的性质再看看长啥样
关于插入的那些事
再次汇总
代码实现
public class RBTree<T extends Comparable<T>> { public static void main(String[] args) { ///* int[] testNum = new int[]{15, 1, 3, 6, 8, 20, 22, 43, 67}; RBTree<Integer> fuck = new RBTree<Integer>(); for (int i = 0; i < testNum.length; i++) { fuck.insertNode(testNum[i]); } System.out.println(fuck.root.data); //*/ /* RBTree<Character> fuck = new RBTree<Character>(); fuck.insertNode('F'); fuck.insertNode('G'); fuck.insertNode('D'); fuck.insertNode('B'); fuck.insertNode('C'); System.out.println(fuck.root.data); */ } private static final boolean RED = true; private static final boolean BLACK = false; private TreeNode<T> root; /** * 插入一个新的节点,插入完毕后符合红黑树性质 * * @param data 需要插入的数据 */ public void insertNode(T data) { TreeNode<T> curr; TreeNode<T> parent = toTargetParent(data); if (parent == null) { curr = root = new TreeNode<T>(data); } else { if (data.compareTo(parent.data) < 0) { curr = parent.left = new TreeNode<T>(data); curr.parent = parent; } else { curr = parent.right = new TreeNode<T>(data); curr.parent = parent; } } fixupTree(curr); } /** * 修复红黑树的不平衡状态 * * @param node 新增节点 */ private void fixupTree(TreeNode node) { TreeNode parent = null, grandParent = null; boolean parentColor = false, uncleColor = false; if (node != root) { parent = node.parent; grandParent = parent.parent; parentColor = parent.color; uncleColor = getUncleColor(node); } //父节点为空表示其为根节点 if (parent == null && node.color == RED) { node.color = BLACK; } else if (parentColor == RED && uncleColor == RED) { changeColor(grandParent); //再次判断根节点是否满足要求 fixupTree(grandParent); } else if (parentColor == RED && uncleColor == BLACK) { dispatchRotation(grandParent, parent, node); } } /** * 判断属于哪种四种情况,LL、LR、RR、RL,使用正确的旋转 * * @param grandParent 祖父节点 * @param parent 父节点 * @param child 新增节点 */ private void dispatchRotation(TreeNode grandParent, TreeNode parent, TreeNode child) { if (grandParent.left == parent) { if (parent.left == child) { rightRotation(grandParent); } else { leftRotation(parent); rightRotation(grandParent); } } else { if (parent.left == child) { rightRotation(parent); leftRotation(grandParent); } else { leftRotation(grandParent); } } } /** * 改变祖父节点以及两个子节点的颜色 * * @param grandParent 传入新增节点的祖父 */ private void changeColor(TreeNode grandParent) { grandParent.color = RED; if (grandParent.left != null) { grandParent.left.color = BLACK; } if (grandParent.right != null) { grandParent.right.color = BLACK; } } /** * 返回叔叔节点的颜色 * * @param node 一个节点 * @return 其叔叔节点的颜色 */ private boolean getUncleColor(TreeNode node) { TreeNode parent = node.parent; //如果当前结点的祖父是空的,说明是其父节点是根节点 return getBrotherColor(parent.parent == null ? node : parent); } /** * 返回兄弟节点的颜色 * * @param child 传入节点 * @return 返回兄弟节点的颜色 */ private boolean getBrotherColor(TreeNode child) { TreeNode parent = child.parent; if (parent.left == child && parent.right != null) { return parent.right.color; } else if (parent.right == child && parent.left != null) { return parent.left.color; } else { return BLACK; } } /** * 将传入的节点的右子节点提升为新的父节点,传入节点降为其右子节点 * 注意颜色、父节点需要处理,务必要清除传入节点的右子节点,因为其已经被提升了父节点了。 * @param curr 一个节点 */ private void leftRotation(TreeNode curr) { TreeNode tParent = curr.right; tParent.parent = curr.parent; tParent.color = BLACK; //新父节点的左子节点,放在传入节点的右边 curr.right = tParent.left; if (tParent.left != null) { tParent.left.parent = curr; } //降为子节点前的数据整理 curr.color = RED; curr.parent = tParent; tParent.left = curr; setChild(curr, tParent); } /** * 将传入的节点的左子节点提升为新的父节点,传入节点降为其右子节点 * 注意颜色、父节点需要处理,务必要清除传入节点的左子节点,因为其已经被提升了父节点了。 * @param curr 一个节点 */ private void rightRotation(TreeNode curr) { //新的父节点 TreeNode tParent = curr.left; tParent.parent = curr.parent; tParent.color = BLACK; //新父节点的右子节点,放在传入节点的左边 curr.left = tParent.right; if (tParent.right != null) { tParent.right.parent = curr; } //传入节点降为子节点前的数据整理 curr.color = RED; curr.parent = tParent; tParent.right = curr; setChild(curr, tParent); } /** * 使旋转在树中生效 * * @param roNode 被旋转的节点 * @param newParent 被旋转之后的父节点 */ private void setChild(TreeNode roNode, TreeNode newParent) { TreeNode roNodeParent = newParent.parent; if (roNodeParent == null) { root = newParent; } else if (roNodeParent.left == roNode) { roNodeParent.left = newParent; } else { roNodeParent.right = newParent; } } /** * 调到data存放位置的父节点处 * @param data 用于对比的数据 * @return data可存放处的父节点 */ private TreeNode<T> toTargetParent(T data) { TreeNode<T> curr = root; TreeNode<T> parent = root; while (curr != null) { parent = curr; if (data.compareTo(curr.data) < 0) { curr = curr.left; } else { curr = curr.right; } } return parent; } /** * 内部节点 */ static class TreeNode<T extends Comparable<T>> { T data; boolean color; //伪删除 boolean isDeleted; TreeNode<T> left; TreeNode<T> right; TreeNode<T> parent; TreeNode(T data, boolean color) { this.data = data; this.color = color; } TreeNode(T data) { this.data = data; this.color = RED; } } }
结果
8
经过验证,长这样!
END
相关文章推荐
- Java安全通信、数字证书及数字证书应用实践(zz)
- Java、XML与数据库编程实践(三)
- Java 理论和实践:那是您的最终答案吗?
- Java 理论与实践:并发在一定程度上使一切变得简单
- Java 理论与实践: 关于异常的争论 ***推荐***
- Java、XML与数据库编程实践
- Java 理论与实践:嗨,我的线程到哪里去了?
- Java 理论与实践: 哈希
- Java 理论与实践:并发集合类
- Java、XML与数据库编程实践(四)
- Java 理论与实践:哈希
- Java 理论与实践: Web 层的状态复制
- Java 理论与实践:变还是不变?
- Java 理论与实践:哈希
- Java、XML与数据库编程实践(二)
- Java、XML与数据库编程实践
- Java安全通信、数字证书及数字证书应用实践
- Java 理论和实践:我必须对那些内容进行文档编制吗?
- Java 理论与实践: 描绘线程安全性
- Sun Java Studio Enterprise 实践:创建一个 Web 应用程序