标签:main span ble tostring div -- 不用 final dede
public class RBNodeDemo { public static void main(String[] args) { RBNode<Integer> node1 = new RBNode<>(1); RBNode<Integer> node2 = new RBNode<>(2); RBNode<Integer> node3 = new RBNode<>(3); RBNode<Integer> node4 = new RBNode<>(4); node1.insert(node2); node1.insert(node3); node1.insert(node4); RBNode<Integer> root = node1.root(); System.out.println(root); } } /** * 红黑树 */ class RBNode<T extends Comparable<T>> { boolean red = true; T data; RBNode<T> left; RBNode<T> right; RBNode<T> parent; public RBNode(boolean red, T data, RBNode<T> left, RBNode<T> right, RBNode<T> parent) { this.red = red; this.data = data; this.left = left; this.right = right; this.parent = parent; } public RBNode(T data) { this.data = data; } /** * 返回当前节点的root节点 * 该方法的时间复杂度应该是O(n) * * @return */ final RBNode<T> root() { for (RBNode<T> root = this, p; ; ) { if ((p = root.parent) == null) { // 如果当前节点的父节点为空,那说明当前节点就是根节点,直接返回当前节点 return root; } root = p; // 当前节点变成原节点的父节点 } } /* * 左旋示意图:对节点x进行左旋 * p p * / / * x y * / \ / *lx y -----> x ry * / \ / * ly ry lx ly * 左旋做了三件事: * 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时) * 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右) * 3. 将y的左子节点设为x,将x的父节点设为y * 注意: 在移动节点位置时,不要忘了双向指定 */ public void rotateLeft(RBNode<T> x) { RBNode<T> y, ly, p; if (x != null && (y = x.right) != null) { // 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时) // 做非空的判断的目的是: 如果y没有左子节点,都不用挂到x的右子节点上了 if ((ly = x.right = y.left) != null) { ly.parent = x; } //2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右) if ((p = y.parent = x.parent) == null) { y.parent = null;// y成了根节点,可以直接置为黑色 y.red = false; } else if (p.left == x) { // 如果x是p的左子节点,那么旋转后y也是p的左子节点 p.left = y; // 将y置为p的左子节点 } else { // x是p右子节点,那么旋转后y也是p的右子节点 p.right = y; // 将y置为p的右子节点 } // 3. 将y的左子节点设为x,将x的父节点设为y y.left = x; x.parent = y; } } /* * 右旋示意图:对节点y进行右旋 * p p * / / * y x * / \ / * x ry -----> lx y * / \ / * lx rx rx ry * 右旋做了三件事: * 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时) * 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右) * 3. 将x的右子节点设为y,将y的父节点设为x */ public void rotateRight(RBNode<T> y) { RBNode<T> x, rx, p; if (y != null && (x = y.left) != null) { // 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时) if ((rx = y.left = x.right) != null) rx.parent = y; // 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右) // 2. 简而言之, 就是挂左挂右的问题 if ((p = x.parent = y.parent) == null) { // 判断父是否为null x.parent = null; x.red = false; // 这句代码放这儿好吗? } else if (p.right == y) { // 判断是左... p.right = x; } else { // 否则就是右 p.left = x; } // 3. 将x的右子节点设为y,将y的父节点设为x x.right = y; y.parent = x; } } /** * 从root节点开始遍历比较 * * @param x */ public void insert(RBNode<T> x) { RBNode<T> root = root(); insert(root, x); // todo 重平衡... balanceInsertion(root, x); } /** * 有如下多种情况: * 1. 如果原树为空, root == x, 只需要把root置为黑色即可 * 2. 如果父节点是黑色,添加上去即可,啥都不需要做 * 3. 下面三种情况较为复杂,需要变色或者旋转 * (1).插入节点的父节点和其叔叔节点(祖父节点的另一个子节点)均为红色的; * (2).插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的右子节点; * (3).插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的左子节点。 * * @param root * @param x 8 ----> 11---->14----->13----->1---->2-----> 5----->9 ----> x= 4 */ private void balanceInsertion(RBNode<T> root, RBNode<T> x) { } private void insert(RBNode<T> root, RBNode<T> x) { if (root.data.compareTo(x.data) < 0) { if (root.right == null) { root.right = x; x.parent = root; } else { insert(root.right, x); } } else { if (root.left == null) { root.left = x; x.parent = root; } else { insert(root.left, x); } } } @Override public String toString() { return "red=" + (red ? "Red" : "Black") + ", data=" + data; } }
未完待续中......
标签:main span ble tostring div -- 不用 final dede
原文地址:https://www.cnblogs.com/z-qinfeng/p/12154339.html