diff --git a/src/main/java/com/lin/App.java b/src/main/java/com/lin/App.java index 0b491be7cf3e609fa4a1613120264013456f1190..a0e9c12722dff1b6b9f1778f597ec61cb03a092c 100644 --- a/src/main/java/com/lin/App.java +++ b/src/main/java/com/lin/App.java @@ -1,14 +1,17 @@ package com.lin; + +import org.apache.commons.codec.binary.StringUtils; + +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** * Hello Utils! */ public class App { - public static void main(String[] args) { - } -} +} \ No newline at end of file diff --git a/src/main/java/com/lin/tree/nome/BSTree.java b/src/main/java/com/lin/tree/nome/BSTree.java new file mode 100644 index 0000000000000000000000000000000000000000..362584caf6232366c777a3ae5da5baabc8afb703 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/BSTree.java @@ -0,0 +1,312 @@ +package com.lin.tree.nome; + +import lombok.Data; + +/** + * 二叉搜索树 + * + * @param + */ +public class BSTree> { + + + private BSTNode mRoot; + + + @Data + public class BSTNode> { + T key; + BSTNode left; + BSTNode right; + BSTNode parent; + + public BSTNode() { + super(); + } + + public BSTNode(T key, BSTNode left, BSTNode right, BSTNode parent) { + this.key = key; + this.left = left; + this.right = right; + this.parent = parent; + } + } + + /** + * 二叉搜索树递归查找 + * + * @param x + * @param key + * @return + */ + private BSTNode search(BSTNode x, T key) { + if (x == null) + return x; + + int cmp = key.compareTo(x.key); + if (cmp < 0) + return search(x.left, key); + else if (cmp > 0) + return search(x.right, key); + else + return x; + } + + public BSTNode search(T key) { + return search(mRoot, key); + } + + /** + * 二叉搜索树非递归查找 + * + * @param x + * @param key + * @return + */ + private BSTNode iterativeSearch(BSTNode x, T key) { + while (x != null) { + int cmp = key.compareTo(x.key); + + if (cmp < 0) + x = x.left; + else if (cmp > 0) + x = x.right; + else + return x; + } + + return x; + } + + public BSTNode iterativeSearch(T key) { + return iterativeSearch(mRoot, key); + } + + /** + * 查找最大节点 + * + * @param tree + * @return + */ + private BSTNode maximum(BSTNode tree) { + if (tree == null) + return null; + + while (tree.right != null) + tree = tree.right; + return tree; + } + + public T maximum() { + BSTNode p = maximum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找最小节点 + * + * @param tree + * @return + */ + private BSTNode minimum(BSTNode tree) { + if (tree == null) + return null; + + while (tree.left != null) + tree = tree.left; + return tree; + } + + public T minimum() { + BSTNode p = minimum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找前驱节点 + * + * @param x + * @return + */ + public BSTNode predecessor(BSTNode x) { + // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。 + if (x.left != null) + return maximum(x.left); + + // 如果x没有左孩子。则x有以下两种可能: + // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。 + // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。 + BSTNode y = x.parent; + while ((y != null) && (x == y.left)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 查找后继节点 + * + * @param x + * @return + */ + public BSTNode successor(BSTNode x) { + // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。 + if (x.right != null) + return minimum(x.right); + + // 如果x没有右孩子。则x有以下两种可能: + // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。 + // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。 + BSTNode y = x.parent; + while ((y != null) && (x == y.right)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 将节点插入二叉树 + * + * @param bst + * @param z + */ + private void insert(BSTree bst, BSTNode z) { + int cmp; + BSTNode y = null; + BSTNode x = bst.mRoot; + + // 查找z的插入位置 + while (x != null) { + y = x; + cmp = z.key.compareTo(x.key); + if (cmp < 0) + x = x.left; + else + x = x.right; + } + + z.parent = y; + if (y == null) + bst.mRoot = z; + else { + cmp = z.key.compareTo(y.key); + if (cmp < 0) + y.left = z; + else + y.right = z; + } + } + + public void insert(T key) { + BSTNode z = new BSTNode(key, null, null, null); + + // 如果新建结点失败,则返回。 + if (z != null) + insert(this, z); + } + + /** + * 删除节点并返回 + * + * @param bst + * @param z + * @return + */ + private BSTNode remove(BSTree bst, BSTNode z) { + BSTNode x = null; + BSTNode y = null; + + if ((z.left == null) || (z.right == null)) + y = z; + else + y = successor(z); + + if (y.left != null) + x = y.left; + else + x = y.right; + + if (x != null) + x.parent = y.parent; + + if (y.parent == null) + bst.mRoot = x; + else if (y == y.parent.left) + y.parent.left = x; + else + y.parent.right = x; + + if (y != z) + z.key = y.key; + + return y; + } + + public void remove(T key) { + BSTNode z, node; + + if ((z = search(mRoot, key)) != null) + if ((node = remove(this, z)) != null) + node = null; + } + + /** + * 打印二叉搜索树 + * + * @param tree + * @param key + * @param direction + */ + private void print(BSTNode tree, T key, int direction) { + + if (tree != null) { + + if (direction == 0) // tree是根节点 + System.out.printf("%2d is root\n", tree.key); + else // tree是分支节点 + System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction == 1 ? "right" : "left"); + + print(tree.left, tree.key, -1); + print(tree.right, tree.key, 1); + } + } + + public void print() { + if (mRoot != null) + print(mRoot, mRoot.key, 0); + } + + + /** + * 销毁二叉树 + * + * @param tree + */ + private void destroy(BSTNode tree) { + if (tree == null) + return; + + if (tree.left != null) + destroy(tree.left); + if (tree.right != null) + destroy(tree.right); + + tree = null; + } + + public void clear() { + destroy(mRoot); + mRoot = null; + } + +} diff --git a/src/main/java/com/lin/tree/nome/Tree.java b/src/main/java/com/lin/tree/nome/Tree.java new file mode 100644 index 0000000000000000000000000000000000000000..91694a48ba2fa75eea4a4a2bad42b7a5354e1eac --- /dev/null +++ b/src/main/java/com/lin/tree/nome/Tree.java @@ -0,0 +1,186 @@ +package com.lin.tree.nome; + + +import lombok.Data; + +import java.util.Queue; +import java.util.Stack; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * 普通二叉树 + */ +public class Tree { + + /** + * 递归实现前序遍历 + * + * @param node + */ + public void preOrderTraverse(Node node) { + if (node != null) { + System.out.println(node.getValue()); + preOrderTraverse(node.getLeft()); + preOrderTraverse(node.getRight()); + } + } + + /** + * 非递归实现的前序遍历 + * + * @param root + */ + public void nrPreOrderTraverse(Node root) { + //借助栈实现 + Stack> stack = new Stack>(); + Node node = root; + while (node != null || !stack.isEmpty()) { + + while (node != null) { + System.out.println(node.getValue()); + stack.push(node); + node = node.getLeft(); + } + node = stack.pop(); + node = node.getRight(); + } + + } + + /** + * 递归实现的中序遍历 + * + * @param node + */ + public void inOrderTraverse(Node node) { + if (node != null) { + inOrderTraverse(node.getLeft()); + System.out.println(node.getValue()); + inOrderTraverse(node.getRight()); + } + } + + /** + * 非递归实现的中序遍历 + * + * @param root + */ + public void nrInOrderTraverse(Node root) { + Stack> stack = new Stack>(); + Node node = root; + while (node != null || !stack.isEmpty()) { + while (node != null) { + stack.push(node); + node = node.getLeft(); + } + node = stack.pop(); + System.out.println(node.getValue()); + node = node.getRight(); + } + } + + /** + * 递归实现的后续遍历 + * + * @param node + */ + public void postOrderTraverse(Node node) { + if (node != null) { + postOrderTraverse(node.getLeft()); + postOrderTraverse(node.getRight()); + System.out.println(node.getValue()); + } + } + + /** + * 非递归实现的后续遍历 + * + * @param root + */ + public void nrPostOrderTraverse(Node root) { + + Stack> stack = new Stack>(); + Node node = root; + Node preNode = null;//表示最近一次访问的节点 + + while (node != null || !stack.isEmpty()) { + while (node != null) { + stack.push(node); + node = node.getLeft(); + } + + node = stack.peek(); + + if (node.getRight() == null || node.getRight() == preNode) { + System.out.println(node.getValue()); + node = stack.pop(); + preNode = node; + node = null; + } else { + node = node.getRight(); + } + } + } + + /** + * 借助队列实现的层序遍历 + * + * @param node + */ + public void levelTraverse(Node node) { + //借助队列实现 + Queue> queue = new LinkedBlockingQueue>(); + queue.add(node); + while (!queue.isEmpty()) { + + Node temp = queue.poll(); + if (temp != null) { + System.out.println(temp.getValue()); + queue.add(temp.getLeft()); + queue.add(temp.getRight()); + } + } + } + + /** + * 获取树的深度 + * + * @param node + * @return + */ + private Integer getHeight(Node node) { + if (node == null) + return 0; + else { + int left = getHeight(node.getLeft()); + int right = getHeight(node.getRight()); + return left > right ? left + 1 : right + 1;//左子树 右子树最深的,再加上父节点本身深度1 + } + } + + /** + * 获取节点数量 + * + * @param node + * @return + */ + private Integer getSize(Node node) { + if (node == null) + return 0; + else { + int leftSize = getSize(node.getLeft()); + int rightSize = getSize(node.getRight()); + return leftSize + rightSize + 1; + } + } + + + @Data + public class Node { + Node left; + Node right; + T value; + } + + +} diff --git a/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java b/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java new file mode 100644 index 0000000000000000000000000000000000000000..4a13540a9e710f21e2608a16646e8d6d2467387e --- /dev/null +++ b/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java @@ -0,0 +1,297 @@ +package com.lin.tree.nome.avltree; + +import java.util.Comparator; + +public class AVLTree1 { + + private static class Node { + int h; + E element; + Node left; + Node right; + //由于java中不像C语言那样有二级指针的概念,所以添加一个父类的引用,方便程序编写 + Node parent; + + public Node(E element, int h, Node left, Node right, Node parent) { + this.element = element; + this.h = h; + this.left = left; + this.right = right; + this.parent = parent; + } + } + + private Node root;//指向伪根节点的引用 + private int size = 0;//节点个数 + Comparator cmp;//节点大小的比较器 + + //如果调用了不带参数的构造函数,则使用该内部类作为比较器, + //但此时泛型E需要继承Comparable接口,否则运行时会抛出异常 + private static class Cmp implements Comparator { + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public int compare(T e1, T e2) { + return ((Comparable) e1).compareTo(e2); + } + + } + + //带比较器的构造函数 + public AVLTree1(Comparator cmp) { + if (cmp == null) { + throw new IllegalArgumentException(); + } + this.cmp = cmp; + //创建一个伪根节点,该节点的右子支才是真正的AVL树的根 + //使用伪根节点节点的目的是,对插入和删除操作递归的形式能够统一 + root = new Node(null, -1, null, null, null); + } + + //不带比较器的构造函数 + public AVLTree1() { + this.cmp = new Cmp(); + root = new Node(null, -1, null, null, null); + } + + //如果树中节点有变动,从底向上逐级调用该函数,可以更新节点的高度 + private int getHight(Node x) { + if (x == null) { + return 0; + } else { + return x.h; + } + } + + //求某个节点作为根时,该子树的最小值 + private E treeMin(Node x) { + while (x.left != null) { + x = x.left; + } + return x.element; + } + + public int size() { + return size; + } + + //先根遍历,调试时使用 + public void preorderTraverse() { + if (root != null) { + preorderTraverse0(root.right); + } + } + + private void preorderTraverse0(Node x) { + if (x != null) { + System.out.print(x.element + " "); + if (x.left != null) { + System.out.print(x.left.element + " "); + } else { + System.out.print("null "); + } + + if (x.right != null) { + System.out.print(x.right.element + " "); + } else { + System.out.print("null "); + } + System.out.println(); + preorderTraverse0(x.left); + preorderTraverse0(x.right); + } + } + + //逆时针旋转(左旋),参数表示轴节点 + private void antiClockwiseRotate(Node X) { + Node P = X.parent; + Node XR = X.right; + if (P.left == X) { + P.left = XR; + } else { + P.right = XR; + } + XR.parent = P; + + X.right = XR.left; + if (XR.left != null) { + XR.left.parent = X; + } + + XR.left = X; + X.parent = XR; + + //旋转后要更新这两个节点的高度 + X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; + XR.h = Math.max(getHight(XR.left), getHight(XR.right)) + 1; + } + + //顺时针旋转(右旋),参数表示轴节点 + private void clockwistRotate(Node X) { + Node P = X.parent; + Node XL = X.left; + if (P.left == X) { + P.left = XL; + } else { + P.right = XL; + } + XL.parent = P; + + X.left = XL.right; + if (XL.right != null) { + XL.right.parent = X; + } + + XL.right = X; + X.parent = XL; + + //旋转后要更新这两个节点的高度 + X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; + XL.h = Math.max(getHight(XL.left), getHight(XL.right)) + 1; + } + + // + public void insert(E e) { + insert0(root.right, e); + } + + private void insert0(Node x, E e) { + if (x == null) { + root.right = new Node(e, 1, null, null, root);//根节点 + size++; + return; + } + + if (cmp.compare(e, x.element) > 0) { + if (x.right != null) { + insert0(x.right, e); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (rh - lh == 2) { + if (cmp.compare(e, x.right.element) > 0) { + antiClockwiseRotate(x); + } else { + clockwistRotate(x.right); + antiClockwiseRotate(x); + } + } + } else { + size++; + x.right = new Node(e, 1, null, null, x); + } + } else if (cmp.compare(e, x.element) < 0) { + if (x.left != null) { + insert0(x.left, e); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (cmp.compare(e, x.left.element) < 0) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } else { + size++; + x.left = new Node(e, 1, null, null, x); + } + } else { + //元素已存在,我们用新的元素更新旧, + //compare返回值等于0,并不表示两个对象完全相等 + x.element = e; + } + x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; + } + + public boolean delete(E e) { + return delete0(root.right, e); + } + + //返回值表示是否删除成功 + private boolean delete0(Node x, E e) { + if (x == null) {//没有找到待删除的元素 + return false; + } + + if (cmp.compare(e, x.element) > 0) { + boolean reval = delete0(x.right, e); + if (reval == false) { + return false; + } + + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (getHight(x.left.left) > getHight(x.left.right)) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } else if (cmp.compare(e, x.element) < 0) { + boolean reval = delete0(x.left, e); + if (reval == false) { + return false; + } + + int lh = getHight(x.left); + int rh = getHight(x.right); + if (rh - lh == 2) { + if (getHight(x.right.right) > getHight(x.right.left)) { + antiClockwiseRotate(x); + } else { + clockwistRotate(x.right); + antiClockwiseRotate(x); + } + } + } else {//找到待删除的元素 + Node P = x.parent; + + if (x.left == null) {//左子支为空,可直接删除,在这一层一定不需要旋转 + size--; + if (P.left == x) { + P.left = x.right; + if (P.left != null) { + P.left.parent = P; + } + } else { + P.right = x.right; + if (P.right != null) { + P.right.parent = P; + } + } + } else if (x.right == null) {//右子支为空,可直接删除,在这一层一定不需要旋转 + size--; + if (P.left == x) { + P.left = x.left; + if (P.left != null) { + P.left.parent = P; + } + } else { + P.right = x.left; + if (P.right != null) { + P.right.parent = P; + } + } + } else {//找到待删除的节点,用后继节点代替,然后删除后继节点 + E nextVal = treeMin(x.right); + x.element = nextVal; + delete0(x.right, nextVal); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (getHight(x.left.left) > getHight(x.left.right)) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } + } + x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; + return true; + } + +} diff --git a/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java b/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java new file mode 100644 index 0000000000000000000000000000000000000000..4b2cc0e01892029b10a0b05813105dab90a463d2 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java @@ -0,0 +1,199 @@ +package com.lin.tree.nome.avltree; + +//AVL树的节点类 +class AVLNode { + T element; + AVLNode left; + AVLNode right; + int height;//记录高度 + + //构造器 + public AVLNode(T theElement) { + this(theElement, null, null); + element = theElement; + } + + public AVLNode(T theElement, AVLNode left, AVLNode right) { + this.element = theElement; + this.left = left; + this.right = right; + this.height = 0; + } +} + +//AVL树 +public class AVLTree2 { + //私有属性 + private AVLNode root;//根节点 + + private int height(AVLNode t) { + return t == null ? -1 : t.height; + } + + //构造方法 + AVLTree2() { + this.root = null; + } + + //插入操作 + public void insert(T x) { + this.root = insert(x, root); + } + + //删除操作 + public void remove(T x) { + this.root = remove(x, root); + } + + //中序打印操作 + public void infPrintTree() { + infPrintTree(root); + System.out.println(); + } + + //判断是否是AVL树 + public boolean isAVL() { + return Math.abs(maxDeep(root.right) - maxDeep(root.left)) < 2; + } + + public AVLNode findMax(AVLNode t) { + if (t == null) + throw new RuntimeException("this AVLNode is Empty"); + if (t.right == null) + return t; + return findMax(t.right); + } + + public AVLNode insert(T x, AVLNode t) { + if (t == null)//传入节点为空,则将该节点作为根节点返回 + return new AVLNode<>(x, null, null); + int compareResult = x.compareTo(t.element); + if (compareResult < 0)//传入元素x小于t + t.left = insert(x, t.left); + else if (compareResult > 0)//传入元素x大于t + t.right = insert(x, t.right); + return balance(t); + } + + //重新进行平衡 + public AVLNode balance(AVLNode t) { + if (t == null) + return t; + if (height(t.left) - height(t.right) > 1) {//左插入 + if (height(t.left.left) >= height(t.left.right)) //左左插入 情形1 + t = singleRightRotate(t);//右旋 + else //左右插入 情形2 + t = doubleLeftRightRotate(t);//左右双旋 + } + if (height(t.right) - height(t.left) > 1) {//右插入 + if (height(t.right.right) >= height(t.right.left)) //右右插入 情形3 + t = singleLeftRotate(t);//左旋 + else //右左插入 情形4 + t = doubleRightLeftRotate(t);//右左双旋 + } + t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1; + return t; + } + + //右单旋 + private AVLNode singleRightRotate(AVLNode t) { + System.out.println("进行右旋转==============>>>"); + AVLNode r = t.left; + t.left = r.right; + r.right = t; + t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1; + r.height = height(t.right) > height(r) ? height(t.right) + 1 : height(r) + 1; + return r; + } + + //左单旋 + private AVLNode singleLeftRotate(AVLNode t) { + System.out.println("进行左旋转==============>>>"); + AVLNode r = t.right; + t.right = r.left; + r.left = t; + t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1; + r.height = height(t.left) > height(r) ? height(t.left) + 1 : height(r) + 1; + return r; + } + + //右左双旋 + private AVLNode doubleRightLeftRotate(AVLNode t) { + System.out.println("进行右左双旋==============>>>"); + t.right = singleRightRotate(t.right); + return singleLeftRotate(t); + } + + //左右双旋 + private AVLNode doubleLeftRightRotate(AVLNode t) { + System.out.println("进行左右双旋==============>>>"); + t.left = singleLeftRotate(t.left); + return singleRightRotate(t); + } + + public AVLNode remove(T x, AVLNode t) { + if (t == null)//传入节点为空 + return t; + int compareResult = x.compareTo(t.element); + if (compareResult < 0) + t.left = remove(x, t.left); + else if (compareResult > 0) + t.right = remove(x, t.right); + else if (t.left != null && t.right != null) { //有两个儿子 + t.element = findMax(t.left).element; + remove(t.element, t.left); + } else //单儿子情形 + t = t.left == null ? t.right : t.left; + if (t != null) + t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1; + return balance(t); + } + + public int maxDeep(AVLNode t) { + int dl, dr;//记录左右树的深度 + if (t == null) + return 0; + else { + dl = maxDeep(t.left); + dr = maxDeep(t.right); + } + return dl > dr ? dl + 1 : dr + 1; + } + + + public void infPrintTree(AVLNode t) { + if (t == null) + return; + infPrintTree(t.left); + System.out.print(t.element + " "); + infPrintTree(t.right); + } + +// public static void main(String[] args) { +// AVLTree2 avlT = createAVLTree(); +// System.out.println("是否是AVL树:" + avlT.isAVL()); +// System.out.println("中序打印出该树===>>>"); +// avlT.infPrintTree(); +// avlT.remove(60); +// avlT.insert(35); +// } + + /** + * 50 + * / \ + * 30 60 + * / \ + * 20 40 + * + * @return + */ + private static AVLTree2 createAVLTree() { + AVLTree2 avlT = new AVLTree2(); + avlT.insert(50); + avlT.insert(60); + avlT.insert(30); + avlT.insert(40); + avlT.insert(20); + return avlT; + } +} \ No newline at end of file diff --git a/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java b/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java new file mode 100644 index 0000000000000000000000000000000000000000..0905b7162813a08692b0659f6e96e2c95e14d930 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java @@ -0,0 +1,691 @@ +package com.lin.tree.nome.rbtree; + +/** + * 红黑树 + * @param + */ +public class RBTree1> { + + private RBTNode mRoot; // 根结点 + + private static final boolean RED = false; + private static final boolean BLACK = true; + + public class RBTNode> { + boolean color; // 颜色 + T key; // 关键字(键值) + RBTNode left; // 左孩子 + RBTNode right; // 右孩子 + RBTNode parent; // 父结点 + + public RBTNode(T key, boolean color, RBTNode parent, RBTNode left, RBTNode right) { + this.key = key; + this.color = color; + this.parent = parent; + this.left = left; + this.right = right; + } + + public T getKey() { + return key; + } + + public String toString() { + return ""+key+(this.color==RED?"(R)":"B"); + } + } + + public RBTree1() { + mRoot=null; + } + + private RBTNode parentOf(RBTNode node) { + return node!=null ? node.parent : null; + } + private boolean colorOf(RBTNode node) { + return node!=null ? node.color : BLACK; + } + private boolean isRed(RBTNode node) { + return ((node!=null)&&(node.color==RED)) ? true : false; + } + private boolean isBlack(RBTNode node) { + return !isRed(node); + } + private void setBlack(RBTNode node) { + if (node!=null) + node.color = BLACK; + } + private void setRed(RBTNode node) { + if (node!=null) + node.color = RED; + } + private void setParent(RBTNode node, RBTNode parent) { + if (node!=null) + node.parent = parent; + } + private void setColor(RBTNode node, boolean color) { + if (node!=null) + node.color = color; + } + + /** + * 前序遍历"红黑树" + */ + private void preOrder(RBTNode tree) { + if(tree != null) { + System.out.print(tree.key+" "); + preOrder(tree.left); + preOrder(tree.right); + } + } + + public void preOrder() { + preOrder(mRoot); + } + + /** + * 中序遍历"红黑树" + */ + private void inOrder(RBTNode tree) { + if(tree != null) { + inOrder(tree.left); + System.out.print(tree.key+" "); + inOrder(tree.right); + } + } + + public void inOrder() { + inOrder(mRoot); + } + + + /** + * 后序遍历"红黑树" + */ + private void postOrder(RBTNode tree) { + if(tree != null) + { + postOrder(tree.left); + postOrder(tree.right); + System.out.print(tree.key+" "); + } + } + + public void postOrder() { + postOrder(mRoot); + } + + + /** + * (递归实现)查找"红黑树x"中键值为key的节点 + */ + private RBTNode search(RBTNode x, T key) { + if (x==null) + return x; + + int cmp = key.compareTo(x.key); + if (cmp < 0) + return search(x.left, key); + else if (cmp > 0) + return search(x.right, key); + else + return x; + } + + public RBTNode search(T key) { + return search(mRoot, key); + } + + /** + * (非递归实现)查找"红黑树x"中键值为key的节点 + */ + private RBTNode iterativeSearch(RBTNode x, T key) { + while (x!=null) { + int cmp = key.compareTo(x.key); + + if (cmp < 0) + x = x.left; + else if (cmp > 0) + x = x.right; + else + return x; + } + + return x; + } + + public RBTNode iterativeSearch(T key) { + return iterativeSearch(mRoot, key); + } + + /** + * 查找最小结点:返回tree为根结点的红黑树的最小结点。 + */ + private RBTNode minimum(RBTNode tree) { + if (tree == null) + return null; + + while(tree.left != null) + tree = tree.left; + return tree; + } + + public T minimum() { + RBTNode p = minimum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找最大结点:返回tree为根结点的红黑树的最大结点。 + */ + private RBTNode maximum(RBTNode tree) { + if (tree == null) + return null; + + while(tree.right != null) + tree = tree.right; + return tree; + } + + public T maximum() { + RBTNode p = maximum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。 + */ + public RBTNode successor(RBTNode x) { + // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。 + if (x.right != null) + return minimum(x.right); + + // 如果x没有右孩子。则x有以下两种可能: + // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。 + // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。 + RBTNode y = x.parent; + while ((y!=null) && (x==y.right)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。 + */ + public RBTNode predecessor(RBTNode x) { + // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。 + if (x.left != null) + return maximum(x.left); + + // 如果x没有左孩子。则x有以下两种可能: + // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。 + // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。 + RBTNode y = x.parent; + while ((y!=null) && (x==y.left)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 对红黑树的节点(x)进行左旋转 + * + * 左旋示意图(对节点x进行左旋): + * px px + * / / + * x y + * / \ --(左旋)-. / \ # + * lx y x ry + * / \ / \ + * ly ry lx ly + * + * + */ + private void leftRotate(RBTNode x) { + // 设置x的右孩子为y + RBTNode y = x.right; + + // 将 “y的左孩子” 设为 “x的右孩子”; + // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲” + x.right = y.left; + if (y.left != null) + y.left.parent = x; + + // 将 “x的父亲” 设为 “y的父亲” + y.parent = x.parent; + + if (x.parent == null) { + this.mRoot = y; // 如果 “x的父亲” 是空节点,则将y设为根节点 + } else { + if (x.parent.left == x) + x.parent.left = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子” + else + x.parent.right = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子” + } + + // 将 “x” 设为 “y的左孩子” + y.left = x; + // 将 “x的父节点” 设为 “y” + x.parent = y; + } + + /** + * 对红黑树的节点(y)进行右旋转 + * + * 右旋示意图(对节点y进行左旋): + * py py + * / / + * y x + * / \ --(右旋)-. / \ # + * x ry lx y + * / \ / \ # + * lx rx rx ry + * + */ + private void rightRotate(RBTNode y) { + // 设置x是当前节点的左孩子。 + RBTNode x = y.left; + + // 将 “x的右孩子” 设为 “y的左孩子”; + // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲” + y.left = x.right; + if (x.right != null) + x.right.parent = y; + + // 将 “y的父亲” 设为 “x的父亲” + x.parent = y.parent; + + if (y.parent == null) { + this.mRoot = x; // 如果 “y的父亲” 是空节点,则将x设为根节点 + } else { + if (y == y.parent.right) + y.parent.right = x; // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子” + else + y.parent.left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子” + } + + // 将 “y” 设为 “x的右孩子” + x.right = y; + + // 将 “y的父节点” 设为 “x” + y.parent = x; + } + + /** + * 红黑树插入修正函数 + * + * 在向红黑树中插入节点之后(失去平衡),再调用该函数; + * 目的是将它重新塑造成一颗红黑树。 + * + * 参数说明: + * node 插入的结点 // 对应《算法导论》中的z + */ + private void insertFixUp(RBTNode node) { + RBTNode parent, gparent; + + // 若“父节点存在,并且父节点的颜色是红色” + while (((parent = parentOf(node))!=null) && isRed(parent)) { + gparent = parentOf(parent); + + //若“父节点”是“祖父节点的左孩子” + if (parent == gparent.left) { + // Case 1条件:叔叔节点是红色 + RBTNode uncle = gparent.right; + if ((uncle!=null) && isRed(uncle)) { + setBlack(uncle); + setBlack(parent); + setRed(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是右孩子 + if (parent.right == node) { + RBTNode tmp; + leftRotate(parent); + tmp = parent; + parent = node; + node = tmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是左孩子。 + setBlack(parent); + setRed(gparent); + rightRotate(gparent); + } else { //若“z的父节点”是“z的祖父节点的右孩子” + // Case 1条件:叔叔节点是红色 + RBTNode uncle = gparent.left; + if ((uncle!=null) && isRed(uncle)) { + setBlack(uncle); + setBlack(parent); + setRed(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子 + if (parent.left == node) { + RBTNode tmp; + rightRotate(parent); + tmp = parent; + parent = node; + node = tmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是右孩子。 + setBlack(parent); + setRed(gparent); + leftRotate(gparent); + } + } + + // 将根节点设为黑色 + setBlack(this.mRoot); + } + + /** + * 将结点插入到红黑树中 + * + * 参数说明: + * node 插入的结点 // 对应《算法导论》中的node + */ + 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 (y!=null) { + 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); + } + + /** + * 新建结点(key),并将其插入到红黑树中 + * + * 参数说明: + * key 插入结点的键值 + */ + public void insert(T key) { + RBTNode node=new RBTNode(key,BLACK,null,null,null); + + // 如果新建结点失败,则返回。 + if (node != null) + insert(node); + } + + + /** + * 红黑树删除修正函数 + * + * 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数; + * 目的是将它重新塑造成一颗红黑树。 + * + * 参数说明: + * node 待修正的节点 + */ + private void removeFixUp(RBTNode node, RBTNode parent) { + RBTNode other; + + while ((node==null || isBlack(node)) && (node != this.mRoot)) { + if (parent.left == node) { + other = parent.right; + if (isRed(other)) { + // Case 1: x的兄弟w是红色的 + setBlack(other); + setRed(parent); + leftRotate(parent); + other = parent.right; + } + + if ((other.left==null || isBlack(other.left)) && + (other.right==null || isBlack(other.right))) { + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + setRed(other); + node = parent; + parent = parentOf(node); + } else { + + if (other.right==null || isBlack(other.right)) { + // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + setBlack(other.left); + setRed(other); + rightRotate(other); + other = parent.right; + } + // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + setColor(other, colorOf(parent)); + setBlack(parent); + setBlack(other.right); + leftRotate(parent); + node = this.mRoot; + break; + } + } else { + + other = parent.left; + if (isRed(other)) { + // Case 1: x的兄弟w是红色的 + setBlack(other); + setRed(parent); + rightRotate(parent); + other = parent.left; + } + + if ((other.left==null || isBlack(other.left)) && + (other.right==null || isBlack(other.right))) { + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + setRed(other); + node = parent; + parent = parentOf(node); + } else { + + if (other.left==null || isBlack(other.left)) { + // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + setBlack(other.right); + setRed(other); + leftRotate(other); + other = parent.left; + } + + // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + setColor(other, colorOf(parent)); + setBlack(parent); + setBlack(other.left); + rightRotate(parent); + node = this.mRoot; + break; + } + } + } + + if (node!=null) + setBlack(node); + } + + /** + * 删除结点(node),并返回被删除的结点 + * + * 参数说明: + * node 删除的结点 + */ + private void remove(RBTNode node) { + RBTNode child, parent; + boolean color; + + // 被删除节点的"左右孩子都不为空"的情况。 + if ( (node.left!=null) && (node.right!=null) ) { + // 被删节点的后继节点。(称为"取代节点") + // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 + RBTNode replace = node; + + // 获取后继节点 + replace = replace.right; + while (replace.left != null) + replace = replace.left; + + // "node节点"不是根节点(只有根节点不存在父节点) + if (parentOf(node)!=null) { + if (parentOf(node).left == node) + parentOf(node).left = replace; + else + parentOf(node).right = replace; + } else { + // "node节点"是根节点,更新根节点。 + this.mRoot = replace; + } + + // child是"取代节点"的右孩子,也是需要"调整的节点"。 + // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 + child = replace.right; + parent = parentOf(replace); + // 保存"取代节点"的颜色 + color = colorOf(replace); + + // "被删除节点"是"它的后继节点的父节点" + if (parent == node) { + parent = replace; + } else { + // child不为空 + if (child!=null) + setParent(child, parent); + parent.left = child; + + replace.right = node.right; + setParent(node.right, replace); + } + + replace.parent = node.parent; + replace.color = node.color; + replace.left = node.left; + node.left.parent = replace; + + if (color == BLACK) + removeFixUp(child, parent); + + node = null; + return ; + } + + if (node.left !=null) { + child = node.left; + } else { + child = node.right; + } + + parent = node.parent; + // 保存"取代节点"的颜色 + color = node.color; + + if (child!=null) + child.parent = parent; + + // "node节点"不是根节点 + if (parent!=null) { + if (parent.left == node) + parent.left = child; + else + parent.right = child; + } else { + this.mRoot = child; + } + + if (color == BLACK) + removeFixUp(child, parent); + node = null; + } + + /** + * 删除结点(z),并返回被删除的结点 + * + * 参数说明: + * tree 红黑树的根结点 + * z 删除的结点 + */ + public void remove(T key) { + RBTNode node; + + if ((node = search(mRoot, key)) != null) + remove(node); + } + + /** + * 销毁红黑树 + */ + private void destroy(RBTNode tree) { + if (tree==null) + return ; + + if (tree.left != null) + destroy(tree.left); + if (tree.right != null) + destroy(tree.right); + + tree=null; + } + + public void clear() { + destroy(mRoot); + mRoot = null; + } + + /** + * 打印"红黑树" + * + * key -- 节点的键值 + * direction -- 0,表示该节点是根节点; + * -1,表示该节点是它的父结点的左孩子; + * 1,表示该节点是它的父结点的右孩子。 + */ + private void print(RBTNode tree, T key, int direction) { + + if(tree != null) { + + if(direction==0) // tree是根节点 + System.out.printf("%2d(B) is root\n", tree.key); + else // tree是分支节点 + System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree)?"R":"B", key, direction==1?"right" : "left"); + + print(tree.left, tree.key, -1); + print(tree.right,tree.key, 1); + } + } + + public void print() { + if (mRoot != null) + print(mRoot, mRoot.key, 0); + } +} \ No newline at end of file diff --git a/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java b/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java new file mode 100644 index 0000000000000000000000000000000000000000..8c8d7654a5fa779cbf40548bd2b9832712f451e0 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java @@ -0,0 +1,440 @@ +package com.lin.tree.nome.rbtree; + + +public class RBTree2 { + + public static class NodeColor { + public static String Red = "red"; + public static String Black = "black"; + } + + public static class RedBlackTreeNode { + private String color; + private int key; + private RedBlackTreeNode left; + private RedBlackTreeNode right; + private RedBlackTreeNode parent; + + //构造Nil结点 + public RedBlackTreeNode() { + this.color = NodeColor.Black; + this.key = 0; + this.left = null; + this.right = null; + this.parent = null; + } + + //构造结点 + public RedBlackTreeNode(String color, int key, RedBlackTreeNode left, RedBlackTreeNode right, RedBlackTreeNode parent) { + this.color = color; + this.key = key; + this.left = left; + this.right = right; + this.parent = parent; + } + + //获取颜色 + public String getColor() { + return color; + } + + //设置颜色 + public void setColor(String color) { + this.color = color; + } + + //获取值 + public int getKey() { + return key; + } + + //设置值 + public void setKey(int key) { + this.key = key; + } + + //获取左子树 + public RedBlackTreeNode getLeft() { + return left; + } + + //设置左子树 + public void setLeft(RedBlackTreeNode left) { + this.left = left; + } + + //获取右子树 + public RedBlackTreeNode getRight() { + return right; + } + + //设置右子树 + public void setRight(RedBlackTreeNode right) { + this.right = right; + } + + //获取父结点 + public RedBlackTreeNode getParent() { + return parent; + } + + //设置父结点 + public void setParent(RedBlackTreeNode parent) { + this.parent = parent; + } + } + + private static RedBlackTreeNode nil = new RedBlackTreeNode(); + private RedBlackTreeNode root = new RedBlackTreeNode(); + + //构造空红黑树 + public RBTree2() { + root = nil; + } + + //创建结点 + public RedBlackTreeNode RB_NODE(int key) { + RedBlackTreeNode node = new RedBlackTreeNode(NodeColor.Red, key, nil, nil, nil); + return node; + } + + //判断是否为Nil结点 + public boolean IsNil(RedBlackTreeNode node) { + if (node == nil) { + return true; + } else { + return false; + } + } + + //获取根结点 + public RedBlackTreeNode getRoot() { + return root; + } + + //设置根结点 + public void setRoot(RedBlackTreeNode root) { + this.root = root; + } + + //插入结点 + public void RB_INSERT(RBTree2 T, RedBlackTreeNode z) { + //临时变量结点y,存储临时结点,默认为Nil + RedBlackTreeNode y = T.nil; + //x初试为根结点 + RedBlackTreeNode x = T.getRoot(); + //循环二查找合适的插入点 + while (IsNil(x) == false) { + //保存当前结点,作为结果的根结点 + y = x; + if (z.getKey() < x.getKey()) { + //查找左子树 + x = x.getLeft(); + } else { + //查找右子树 + x = x.getRight(); + } + } + //临时结点y设置为插入点的父结点 + z.setParent(y); + + if (IsNil(y) == true) { + //空树时设置z为根结点 + T.setRoot(z); + } else if (z.getKey() < y.getKey()) { + //插入为左子树 + y.setLeft(z); + } else { + //插入为右子树 + y.setRight(z); + } + //将插入结点的左右子树设为Nil,颜色为红色,已经在构造时设置过,可以省略 + z.setLeft(T.nil); + z.setRight(T.nil); + z.setColor(NodeColor.Red); + //插入调整 + RB_INSERT_FIXUP(T, z); + } + + //插入调整 + public void RB_INSERT_FIXUP(RBTree2 T, RedBlackTreeNode z) { + //当z的父结点为红色时,插入结点和父结点同为红色,需要调整 + while (z.getParent().getColor() == NodeColor.Red) { + //插入结点的父结点是祖父节点的左子树 + if (z.getParent() == z.getParent().getParent().getLeft()) { + //y定义为叔叔结点 + RedBlackTreeNode y = z.getParent().getParent().getRight(); + //case1:如果叔叔结点为红色,上层父结点和叔叔结点设为黑色,祖父节点设为红色 + if (y.getColor() == NodeColor.Red) { + z.getParent().setColor(NodeColor.Black); + y.setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + //祖父结点设为z + z = z.getParent().getParent(); + } + //case2:插入结点为父结点的右子树,(叔叔结点一定为黑色),父结点设为z,对z左旋 + else if (z == z.getParent().getRight()) { + //对父结点左旋 + z = z.getParent(); + LEFT_ROTATE(T, z); + } + //case3:插入结点为父结点的左子树,(叔叔结点一定为黑色),父结点设为黑色,祖父结点设为红色,对祖父结点右旋 + z.getParent().setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + RIGHT_ROTATE(T, z.getParent().getParent()); + } + //插入结点的父结点是祖父节点的右子树,同理,方向交换 + else { + RedBlackTreeNode y = z.getParent().getParent().getLeft(); + if (y.getColor() == NodeColor.Red) { + z.getParent().setColor(NodeColor.Black); + y.setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + z = z.getParent().getParent(); + } else if (z == z.getParent().getLeft()) { + z = z.getParent(); + RIGHT_ROTATE(T, z); + } + z.getParent().setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + LEFT_ROTATE(T, z.getParent().getParent()); + } + } + T.getRoot().setColor(NodeColor.Black); + } + + //删除结点子函数,把根结点为u的子树替换为根结点为v的子树 + public void RB_TRANSPLANT(RBTree2 T, RedBlackTreeNode u, RedBlackTreeNode v) { + //u为根结点 + if (IsNil(u.getParent())) { + T.root = v; + } + //u为左子树 + else if (u == u.getParent().getLeft()) { + u.getParent().setLeft(v); + } + //u为右子树 + else { + u.getParent().setRight(v); + } + //父结点交换 + v.setParent(u.getParent()); + } + + //查找后继 + public RedBlackTreeNode TREE_MINIMUM(RedBlackTreeNode x) { + //不断查找左子树 + while (IsNil(x.getLeft()) == false) { + x = x.getLeft(); + } + return x; + } + + //删除结点 + public void RB_DELETE(RBTree2 T, RedBlackTreeNode z) { + //临时结点y保存即将删除的结点z信息 + RedBlackTreeNode y = z; + //在结点删除或者移动前必须保存结点的颜色 + String yOriginColor = y.getColor(); + //临时结点x,用于记录y的位置 + RedBlackTreeNode x = null; + //case1:z无左子树,直接将右子树置于z位置 + if (IsNil(z.getLeft()) == true) { + x = z.getRight(); + RB_TRANSPLANT(T, z, z.getRight()); + } + //case2:z无右子树,直接将左子树置于z位置 + else if (IsNil(z.getRight()) == true) { + x = z.getLeft(); + RB_TRANSPLANT(T, z, z.getLeft()); + } + //case3:z有左右子树 + else { + //找到右子树中最小的结点,即z的后继 + y = TREE_MINIMUM(z.getRight()); + //删除的实际是y的位置的结点,要记录y的颜色 + yOriginColor = y.getColor(); + //y可能有右孩子,一定无左孩子,保存右孩子 + x = y.getRight(); + //若y为z的右孩子,直接相连 + if (y.getParent() == z) { + x.setParent(y); + } + //若不相连 + else { + RB_TRANSPLANT(T, y, y.getRight()); + y.setRight(z.getRight()); + y.getRight().setParent(y); + } + RB_TRANSPLANT(T, z, y); + y.setLeft(z.getLeft()); + y.getLeft().setParent(y); + y.setColor(z.getColor()); + } + //删除结点为黑色时需要调整 + if (yOriginColor == NodeColor.Black) { + RB_DELETE_FIXUP(T, x); + } + } + + //删除调整 + public void RB_DELETE_FIXUP(RBTree2 T, RedBlackTreeNode x) { + //临时结点 + RedBlackTreeNode w = null; + //非根结点且为黑色 + while (x != T.getRoot() && x.getColor() == NodeColor.Black) { + //x为父结点左孩子 + if (x == x.getParent().getLeft()) { + //w为兄弟结点 + w = x.getParent().getRight(); + //case1:w兄弟结点为红色 + if (w.getColor() == NodeColor.Red) { + //w设为黑色 + w.setColor(NodeColor.Black); + //被删结点的父结点设为黑色 + x.getParent().setColor(NodeColor.Red); + //对x的父结点左旋 + LEFT_ROTATE(T, x.getParent()); + //更新x的兄弟结点 + w = x.getParent().getRight(); + } + //case2:w兄弟结点和两个孩子结点都为黑 + if (w.getLeft().getColor() == NodeColor.Black && w.getRight().getColor() == NodeColor.Black) { + //w设为黑色 + w.setColor(NodeColor.Red); + //重设x为x的父结点 + x = x.getParent(); + } + //case3:w兄弟结点为黑,w的左孩子为红,右孩子为黑 + else if (w.getRight().getColor() == NodeColor.Black) { + //w的左孩子设为黑 + w.getLeft().setColor(NodeColor.Black); + //w设为红 + w.setColor(NodeColor.Red); + //右旋 + RIGHT_ROTATE(T, w); + //更新w + w = x.getParent().getRight(); + } + //case4:w兄弟结点为黑,w的右孩子为红 + w.setColor(x.getParent().getColor()); + x.getParent().setColor(NodeColor.Black); + w.getRight().setColor(NodeColor.Black); + LEFT_ROTATE(T, x.getParent()); + x = T.getRoot(); + } + //x为父结点右孩子 + else { + w = x.getParent().getLeft(); + if (w.getColor() == NodeColor.Red) { + w.setColor(NodeColor.Black); + x.getParent().setColor(NodeColor.Red); + RIGHT_ROTATE(T, x.getParent()); + w = x.getParent().getLeft(); + } + if (w.getRight().getColor() == NodeColor.Black && w.getLeft().getColor() == NodeColor.Black) { + w.setColor(NodeColor.Red); + x = x.getParent(); + } else if (w.getLeft().getColor() == NodeColor.Black) { + w.getRight().setColor(NodeColor.Black); + w.setColor(NodeColor.Red); + LEFT_ROTATE(T, w); + w = x.getParent().getLeft(); + } + w.setColor(x.getParent().getColor()); + x.getParent().setColor(NodeColor.Black); + w.getLeft().setColor(NodeColor.Black); + RIGHT_ROTATE(T, x.getParent()); + x = T.getRoot(); + } + } + x.setColor(NodeColor.Black); + } + + //左旋 + public void LEFT_ROTATE(RBTree2 T, RedBlackTreeNode x) { + //左旋结点右子树不能为空 + if (IsNil(x.getRight()) == true) + return; + //定义y结点 + RedBlackTreeNode y = x.getRight(); + //y左子树 -> x右子树 + x.setRight(y.getLeft()); + //x -> y左子树父结点 + y.getLeft().setParent(x); + //x父结点 -> y父结点 + y.setParent(x.getParent()); + //y -> x父结点左/右子树或根结点 + if (IsNil(x.getParent()) == true) { + //x为根结点,y设为根结点 + T.setRoot(y); + } else if (x.getParent().getLeft() == x) { + //x为左子树,y设为左子树 + x.getParent().setLeft(y); + } else { + //x为右子树,y设为右子树 + x.getParent().setRight(y); + } + //x -> y左子树 + y.setLeft(x); + //y -> x父结点 + x.setParent(y); + } + + //右旋 + public void RIGHT_ROTATE(RBTree2 T, RedBlackTreeNode x) { + //右旋结点父结点不能为空 + if (IsNil(x.getParent()) == true) + return; + //定义y结点 + RedBlackTreeNode y = x.getParent(); + //x右子树 -> y左子树 + y.setLeft(x.getRight()); + //y -> x右子树父结点 + x.getRight().setParent(y); + //y父结点 -> x父结点 + x.setParent(y.getParent()); + //x -> y父结点左/右子树或根结点 + if (IsNil(y.getParent()) == true) { + //y为根结点,x设为根结点 + T.setRoot(x); + } else if (y.getParent().getLeft() == y) { + //y为左子树,x设为左子树 + y.getParent().setLeft(x); + } else { + //y为右子树,x设为右子树 + y.getParent().setRight(x); + } + //y -> x右子树 + x.setRight(y); + //x -> y父结点 + y.setParent(x); + } + + //前序遍历 + public void preorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + System.out.println(t.getKey()); + preorder(t.getLeft()); + preorder(t.getRight()); + } + } + + //中序遍历 + public void midorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + midorder(t.getLeft()); + System.out.println(t.getKey()); + midorder(t.getRight()); + } + } + + //后序遍历 + public void postorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + postorder(t.getLeft()); + postorder(t.getRight()); + System.out.println(t.getKey()); + } + } +} diff --git a/src/main/java/com/lin/Util/ExcelExportUtil.java b/src/main/java/com/lin/util/ExcelExportUtil.java similarity index 99% rename from src/main/java/com/lin/Util/ExcelExportUtil.java rename to src/main/java/com/lin/util/ExcelExportUtil.java index 9a2957af339d0d718235a8c03dfc08cfa47daaf3..bd263362ec830e9db53df4390e4c45c5868ed1c8 100644 --- a/src/main/java/com/lin/Util/ExcelExportUtil.java +++ b/src/main/java/com/lin/util/ExcelExportUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/ExcelImportUtil.java b/src/main/java/com/lin/util/ExcelImportUtil.java similarity index 99% rename from src/main/java/com/lin/Util/ExcelImportUtil.java rename to src/main/java/com/lin/util/ExcelImportUtil.java index f423a8dff4449ad619eb1b1317fd2f0dac545a9a..c9da58c2f5edbfb07272c08da9dbcd99048b71e7 100644 --- a/src/main/java/com/lin/Util/ExcelImportUtil.java +++ b/src/main/java/com/lin/util/ExcelImportUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/FileReadUtil.java b/src/main/java/com/lin/util/FileReadUtil.java similarity index 98% rename from src/main/java/com/lin/Util/FileReadUtil.java rename to src/main/java/com/lin/util/FileReadUtil.java index ba5c2372a4158479dc7bc65253de54d75f9fa36b..2e33e8fa863ae40239efb8b5e48fb1b60c4d88ab 100644 --- a/src/main/java/com/lin/Util/FileReadUtil.java +++ b/src/main/java/com/lin/util/FileReadUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/lin/Util/FileWriteUtil.java b/src/main/java/com/lin/util/FileWriteUtil.java similarity index 99% rename from src/main/java/com/lin/Util/FileWriteUtil.java rename to src/main/java/com/lin/util/FileWriteUtil.java index b3cbe26f63e5333e16a82accbe5bff524a8c93d2..ca6a7051711d5126545299eccf78e11c28c98a86 100644 --- a/src/main/java/com/lin/Util/FileWriteUtil.java +++ b/src/main/java/com/lin/util/FileWriteUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/HttpConnectionUtil.java b/src/main/java/com/lin/util/HttpConnectionUtil.java similarity index 99% rename from src/main/java/com/lin/Util/HttpConnectionUtil.java rename to src/main/java/com/lin/util/HttpConnectionUtil.java index ee82de7c00f8ca344657f63eb40b7a50cc463f04..911d3cc58eac6eff83eee4995d8df13704134026 100644 --- a/src/main/java/com/lin/Util/HttpConnectionUtil.java +++ b/src/main/java/com/lin/util/HttpConnectionUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/HttpUrlConnectionUtil.java b/src/main/java/com/lin/util/HttpUrlConnectionUtil.java similarity index 99% rename from src/main/java/com/lin/Util/HttpUrlConnectionUtil.java rename to src/main/java/com/lin/util/HttpUrlConnectionUtil.java index b9406d956e7df23cb69d7b9fddac131aba4d1b67..520aa756a195198e197ea38ecbf5c8dff2f53cf8 100644 --- a/src/main/java/com/lin/Util/HttpUrlConnectionUtil.java +++ b/src/main/java/com/lin/util/HttpUrlConnectionUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; diff --git a/src/main/java/com/lin/Util/InvokeUtil.java b/src/main/java/com/lin/util/InvokeUtil.java similarity index 96% rename from src/main/java/com/lin/Util/InvokeUtil.java rename to src/main/java/com/lin/util/InvokeUtil.java index fd309e8361f44ff3c98b0a5aa559c35d58b99f76..ec34cd5f9b98a6debe73fb3779d14b69c0d1333b 100644 --- a/src/main/java/com/lin/Util/InvokeUtil.java +++ b/src/main/java/com/lin/util/InvokeUtil.java @@ -1,11 +1,8 @@ -package com.lin.Util; +package com.lin.util; -import com.sun.org.apache.xpath.internal.operations.Bool; import lombok.extern.slf4j.Slf4j; -import javax.swing.*; import java.lang.reflect.Field; -import java.lang.reflect.Type; import java.util.Map; /** diff --git a/src/main/java/com/lin/Util/XmlParseUtil.java b/src/main/java/com/lin/util/XmlParseUtil.java similarity index 99% rename from src/main/java/com/lin/Util/XmlParseUtil.java rename to src/main/java/com/lin/util/XmlParseUtil.java index 0456574272be25048d885e71a36033e1ff2334fc..0d132879c998a0934bb01b039562edc7f4926a63 100644 --- a/src/main/java/com/lin/Util/XmlParseUtil.java +++ b/src/main/java/com/lin/util/XmlParseUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.w3c.dom.Document; diff --git a/src/test/java/com/lin/TestTree/AVLTree1Test.java b/src/test/java/com/lin/TestTree/AVLTree1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..09bd06cffcd5da44d0156543af935487a4aa8611 --- /dev/null +++ b/src/test/java/com/lin/TestTree/AVLTree1Test.java @@ -0,0 +1,28 @@ +package com.lin.TestTree; + +import com.lin.tree.nome.avltree.AVLTree1; + +public class AVLTree1Test { + + public static void main(String[] args) { + AVLTree1 avl = new AVLTree1<>(); + /*可自行添加插入,删除操作进行测试*/ + avl.insert(3); + avl.insert(5); + avl.insert(6); + avl.insert(7); + avl.insert(8); + avl.insert(9); + avl.preorderTraverse(); + System.out.println(); + System.out.println(avl.size()); + + avl.delete(7); + avl.delete(8); + avl.preorderTraverse(); + System.out.println(); + System.out.println(avl.size()); + } + + +} diff --git a/src/test/java/com/lin/TestTree/RBTree2Test.java b/src/test/java/com/lin/TestTree/RBTree2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..ffbd302675a67cfae9f4e8a60908fef67eb1279f --- /dev/null +++ b/src/test/java/com/lin/TestTree/RBTree2Test.java @@ -0,0 +1,22 @@ +package com.lin.TestTree; + +import com.lin.tree.nome.rbtree.RBTree2; + + +public class RBTree2Test { + + + public static void main(String[] args) { + RBTree2 T = new RBTree2(); + RBTree2.RedBlackTreeNode node1 = T.RB_NODE(10); + T.RB_INSERT(T, node1); + RBTree2.RedBlackTreeNode node2 = T.RB_NODE(20); + T.RB_INSERT(T, node2); + RBTree2.RedBlackTreeNode node3 = T.RB_NODE(30); + T.RB_INSERT(T, node3); + T.preorder(T.getRoot()); + } + + + +} diff --git a/src/test/java/com/lin/TestTree/v4.0.md b/src/test/java/com/lin/TestTree/v4.0.md new file mode 100644 index 0000000000000000000000000000000000000000..f3f3f470c0ca785279eae09cdf3e214a92d6d1be --- /dev/null +++ b/src/test/java/com/lin/TestTree/v4.0.md @@ -0,0 +1,8 @@ +# V4.0 + +1. AVL树实现算法1 +2. AVL树实现算法2 +3. 红黑树实现算法1 +4. 红黑树实现算法2 +5. 二叉平衡树实现算法 +6. 普通二叉树6 \ No newline at end of file diff --git a/src/test/java/com/lin/TestUtil/ExcelTest.java b/src/test/java/com/lin/TestUtil/ExcelTest.java index 316469f66701b02075f3af87032c82b927dd184b..f13923a2dfc648a9dbe97550b044f66fc515ba48 100644 --- a/src/test/java/com/lin/TestUtil/ExcelTest.java +++ b/src/test/java/com/lin/TestUtil/ExcelTest.java @@ -1,9 +1,9 @@ package com.lin.TestUtil; import com.lin.Dto.BookDto; -import com.lin.Util.ExcelExportUtil; -import com.lin.Util.ExcelImportUtil; -import com.lin.Util.FileWriteUtil; +import com.lin.util.ExcelExportUtil; +import com.lin.util.ExcelImportUtil; +import com.lin.util.FileWriteUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.junit.Test; diff --git a/src/test/java/com/lin/TestUtil/FileTest.java b/src/test/java/com/lin/TestUtil/FileTest.java index 505ace7943b2ba6da2ba4f1faebb6fa13da09952..a24d1cb7a0f4c73f624559d7b10ec788c7cdd75a 100644 --- a/src/test/java/com/lin/TestUtil/FileTest.java +++ b/src/test/java/com/lin/TestUtil/FileTest.java @@ -2,8 +2,8 @@ package com.lin.TestUtil; import com.alibaba.fastjson.JSON; import com.lin.Dto.SenseCallbackDto; -import com.lin.Util.FileReadUtil; -import com.lin.Util.FileWriteUtil; +import com.lin.util.FileReadUtil; +import com.lin.util.FileWriteUtil; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/com/lin/TestUtil/HttpConnectionTest.java b/src/test/java/com/lin/TestUtil/HttpConnectionTest.java index e1eb40915da890a740003dfcf36dd6e27bccb880..4e2651460803af7dc23a7753a88c2149b16d84ed 100644 --- a/src/test/java/com/lin/TestUtil/HttpConnectionTest.java +++ b/src/test/java/com/lin/TestUtil/HttpConnectionTest.java @@ -1,7 +1,7 @@ package com.lin.TestUtil; -import com.lin.Util.HttpConnectionUtil; -import com.lin.Util.HttpUrlConnectionUtil; +import com.lin.util.HttpConnectionUtil; +import com.lin.util.HttpUrlConnectionUtil; import org.junit.Test; /** diff --git a/src/test/java/com/lin/TestUtil/InvokeTest.java b/src/test/java/com/lin/TestUtil/InvokeTest.java index 56eb3f48f7f469ba85a32e691765b4a625ff9e79..17438fffa602b2b0d721414f3e1fe9f676d004e7 100644 --- a/src/test/java/com/lin/TestUtil/InvokeTest.java +++ b/src/test/java/com/lin/TestUtil/InvokeTest.java @@ -3,8 +3,8 @@ package com.lin.TestUtil; import com.lin.Dto.BookDto; import com.lin.Dto.SenseCallbackDto; import com.lin.Dto.TestDto; -import com.lin.Util.InvokeUtil; -import com.lin.Util.XmlParseUtil; +import com.lin.util.InvokeUtil; +import com.lin.util.XmlParseUtil; import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; diff --git a/src/test/java/com/lin/TestUtil/XmlTest.java b/src/test/java/com/lin/TestUtil/XmlTest.java index e962f2246fdc4ab344e487930c9781bf58df56e4..92282561206022efc0b2f0f673cb838e63255177 100644 --- a/src/test/java/com/lin/TestUtil/XmlTest.java +++ b/src/test/java/com/lin/TestUtil/XmlTest.java @@ -1,16 +1,11 @@ package com.lin.TestUtil; -import com.lin.Util.FileReadUtil; -import com.lin.Util.XmlParseUtil; +import com.lin.util.XmlParseUtil; import org.junit.Test; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; /** * Xml相关测试工具