增加淘宝群内容,修改部分文件组织
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>06-二叉搜索树</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@@ -0,0 +1,11 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,483 @@
|
||||
package com.mj;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.mj.printer.BinaryTreeInfo;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BinarySearchTree<E> implements BinaryTreeInfo {
|
||||
private int size;
|
||||
private Node<E> root;
|
||||
private Comparator<E> comparator;
|
||||
|
||||
public BinarySearchTree() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public BinarySearchTree(Comparator<E> comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
root = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public void add(E element) {
|
||||
elementNotNullCheck(element);
|
||||
|
||||
// 添加第一个节点
|
||||
if (root == null) {
|
||||
root = new Node<>(element, null);
|
||||
size++;
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加的不是第一个节点
|
||||
// 找到父节点
|
||||
Node<E> parent = root;
|
||||
Node<E> node = root;
|
||||
int cmp = 0;
|
||||
do {
|
||||
cmp = compare(element, node.element);
|
||||
parent = node;
|
||||
if (cmp > 0) {
|
||||
node = node.right;
|
||||
} else if (cmp < 0) {
|
||||
node = node.left;
|
||||
} else { // 相等
|
||||
node.element = element;
|
||||
return;
|
||||
}
|
||||
} while (node != null);
|
||||
|
||||
// 看看插入到父节点的哪个位置
|
||||
Node<E> newNode = new Node<>(element, parent);
|
||||
if (cmp > 0) {
|
||||
parent.right = newNode;
|
||||
} else {
|
||||
parent.left = newNode;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
|
||||
public void remove(E element) {
|
||||
remove(node(element));
|
||||
}
|
||||
|
||||
public boolean contains(E element) {
|
||||
return node(element) != null;
|
||||
}
|
||||
|
||||
private void remove(Node<E> node) {
|
||||
if (node == null) return;
|
||||
|
||||
size--;
|
||||
|
||||
if (node.hasTwoChildren()) { // 度为2的节点
|
||||
// 找到后继节点
|
||||
Node<E> s = successor(node);
|
||||
// 用后继节点的值覆盖度为2的节点的值
|
||||
node.element = s.element;
|
||||
// 删除后继节点
|
||||
node = s;
|
||||
}
|
||||
|
||||
// 删除node节点(node的度必然是1或者0)
|
||||
Node<E> replacement = node.left != null ? node.left : node.right;
|
||||
|
||||
if (replacement != null) { // node是度为1的节点
|
||||
// 更改parent
|
||||
replacement.parent = node.parent;
|
||||
// 更改parent的left、right的指向
|
||||
if (node.parent == null) { // node是度为1的节点并且是根节点
|
||||
root = replacement;
|
||||
} else if (node == node.parent.left) {
|
||||
node.parent.left = replacement;
|
||||
} else { // node == node.parent.right
|
||||
node.parent.right = replacement;
|
||||
}
|
||||
} else if (node.parent == null) { // node是叶子节点并且是根节点
|
||||
root = null;
|
||||
} else { // node是叶子节点,但不是根节点
|
||||
if (node == node.parent.left) {
|
||||
node.parent.left = null;
|
||||
} else { // node == node.parent.right
|
||||
node.parent.right = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Node<E> node(E element) {
|
||||
Node<E> node = root;
|
||||
while (node != null) {
|
||||
int cmp = compare(element, node.element);
|
||||
if (cmp == 0) return node;
|
||||
if (cmp > 0) {
|
||||
node = node.right;
|
||||
} else { // cmp < 0
|
||||
node = node.left;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 前序遍历
|
||||
// */
|
||||
// public void preorderTraversal() {
|
||||
// preorderTraversal(root);
|
||||
// }
|
||||
//
|
||||
// private void preorderTraversal(Node<E> node) {
|
||||
// if (node == null) return;
|
||||
//
|
||||
// System.out.println(node.element);
|
||||
// preorderTraversal(node.left);
|
||||
// preorderTraversal(node.right);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 中序遍历
|
||||
// */
|
||||
// public void inorderTraversal() {
|
||||
// inorderTraversal(root);
|
||||
// }
|
||||
//
|
||||
// private void inorderTraversal(Node<E> node) {
|
||||
// if (node == null) return;
|
||||
//
|
||||
// inorderTraversal(node.left);
|
||||
// System.out.println(node.element);
|
||||
// inorderTraversal(node.right);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 后序遍历
|
||||
// */
|
||||
// public void postorderTraversal() {
|
||||
// postorderTraversal(root);
|
||||
// }
|
||||
//
|
||||
// private void postorderTraversal(Node<E> node) {
|
||||
// if (node == null) return;
|
||||
//
|
||||
// postorderTraversal(node.left);
|
||||
// postorderTraversal(node.right);
|
||||
// System.out.println(node.element);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 层序遍历
|
||||
// */
|
||||
// public void levelOrderTraversal() {
|
||||
// if (root == null) return;
|
||||
//
|
||||
// Queue<Node<E>> queue = new LinkedList<>();
|
||||
// queue.offer(root);
|
||||
//
|
||||
// while (!queue.isEmpty()) {
|
||||
// Node<E> node = queue.poll();
|
||||
// System.out.println(node.element);
|
||||
//
|
||||
// if (node.left != null) {
|
||||
// queue.offer(node.left);
|
||||
// }
|
||||
//
|
||||
// if (node.right != null) {
|
||||
// queue.offer(node.right);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void preorder(Visitor<E> visitor) {
|
||||
if (visitor == null) return;
|
||||
preorder(root, visitor);
|
||||
}
|
||||
|
||||
private void preorder(Node<E> node, Visitor<E> visitor) {
|
||||
if (node == null || visitor.stop) return;
|
||||
|
||||
visitor.stop = visitor.visit(node.element);
|
||||
preorder(node.left, visitor);
|
||||
preorder(node.right, visitor);
|
||||
}
|
||||
|
||||
public void inorder(Visitor<E> visitor) {
|
||||
if (visitor == null) return;
|
||||
inorder(root, visitor);
|
||||
}
|
||||
|
||||
private void inorder(Node<E> node, Visitor<E> visitor) {
|
||||
if (node == null || visitor.stop) return;
|
||||
|
||||
inorder(node.left, visitor);
|
||||
if (visitor.stop) return;
|
||||
visitor.stop = visitor.visit(node.element);
|
||||
inorder(node.right, visitor);
|
||||
}
|
||||
|
||||
public void postorder(Visitor<E> visitor) {
|
||||
if (visitor == null) return;
|
||||
postorder(root, visitor);
|
||||
}
|
||||
|
||||
private void postorder(Node<E> node, Visitor<E> visitor) {
|
||||
if (node == null || visitor.stop) return;
|
||||
|
||||
postorder(node.left, visitor);
|
||||
postorder(node.right, visitor);
|
||||
if (visitor.stop) return;
|
||||
visitor.stop = visitor.visit(node.element);
|
||||
}
|
||||
|
||||
public void levelOrder(Visitor<E> visitor) {
|
||||
if (root == null || visitor == null) return;
|
||||
|
||||
Queue<Node<E>> queue = new LinkedList<>();
|
||||
queue.offer(root);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
Node<E> node = queue.poll();
|
||||
if (visitor.visit(node.element)) return;
|
||||
|
||||
if (node.left != null) {
|
||||
queue.offer(node.left);
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
queue.offer(node.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
if (root == null) return false;
|
||||
|
||||
Queue<Node<E>> queue = new LinkedList<>();
|
||||
queue.offer(root);
|
||||
|
||||
boolean leaf = false;
|
||||
while (!queue.isEmpty()) {
|
||||
Node<E> node = queue.poll();
|
||||
if (leaf && !node.isLeaf()) return false;
|
||||
|
||||
if (node.left != null) {
|
||||
queue.offer(node.left);
|
||||
} else if (node.right != null) { // node.left == null && node.right != null
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
queue.offer(node.right);
|
||||
} else { // node.right == null
|
||||
leaf = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// public boolean isComplete() {
|
||||
// if (root == null) return false;
|
||||
//
|
||||
// Queue<Node<E>> queue = new LinkedList<>();
|
||||
// queue.offer(root);
|
||||
//
|
||||
// boolean leaf = false;
|
||||
// while (!queue.isEmpty()) {
|
||||
// Node<E> node = queue.poll();
|
||||
// if (leaf && !node.isLeaf()) return false;
|
||||
//
|
||||
// if (node.left != null && node.right != null) {
|
||||
// queue.offer(node.left);
|
||||
// queue.offer(node.right);
|
||||
// } else if (node.left == null && node.right != null) {
|
||||
// return false;
|
||||
// } else { // 后面遍历的节点都必须是叶子节点
|
||||
// leaf = true;
|
||||
// if (node.left != null) {
|
||||
// queue.offer(node.left);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
public int height() {
|
||||
if (root == null) return 0;
|
||||
|
||||
// 树的高度
|
||||
int height = 0;
|
||||
// 存储着每一层的元素数量
|
||||
int levelSize = 1;
|
||||
Queue<Node<E>> queue = new LinkedList<>();
|
||||
queue.offer(root);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
Node<E> node = queue.poll();
|
||||
levelSize--;
|
||||
|
||||
if (node.left != null) {
|
||||
queue.offer(node.left);
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
queue.offer(node.right);
|
||||
}
|
||||
|
||||
if (levelSize == 0) { // 意味着即将要访问下一层
|
||||
levelSize = queue.size();
|
||||
height++;
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
public int height2() {
|
||||
return height(root);
|
||||
}
|
||||
|
||||
private int height(Node<E> node) {
|
||||
if (node == null) return 0;
|
||||
return 1 + Math.max(height(node.left), height(node.right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toString(root, sb, "");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void toString(Node<E> node, StringBuilder sb, String prefix) {
|
||||
if (node == null) return;
|
||||
|
||||
toString(node.left, sb, prefix + "L---");
|
||||
sb.append(prefix).append(node.element).append("\n");
|
||||
toString(node.right, sb, prefix + "R---");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2
|
||||
*/
|
||||
private int compare(E e1, E e2) {
|
||||
if (comparator != null) {
|
||||
return comparator.compare(e1, e2);
|
||||
}
|
||||
return ((Comparable<E>)e1).compareTo(e2);
|
||||
}
|
||||
|
||||
private void elementNotNullCheck(E element) {
|
||||
if (element == null) {
|
||||
throw new IllegalArgumentException("element must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Node<E> predecessor(Node<E> node) {
|
||||
if (node == null) return null;
|
||||
|
||||
// 前驱节点在左子树当中(left.right.right.right....)
|
||||
Node<E> p = node.left;
|
||||
if (p != null) {
|
||||
while (p.right != null) {
|
||||
p = p.right;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// 从父节点、祖父节点中寻找前驱节点
|
||||
while (node.parent != null && node == node.parent.left) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
// node.parent == null
|
||||
// node == node.parent.right
|
||||
return node.parent;
|
||||
}
|
||||
|
||||
private Node<E> successor(Node<E> node) {
|
||||
if (node == null) return null;
|
||||
|
||||
// 前驱节点在左子树当中(right.left.left.left....)
|
||||
Node<E> p = node.right;
|
||||
if (p != null) {
|
||||
while (p.left != null) {
|
||||
p = p.left;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// 从父节点、祖父节点中寻找前驱节点
|
||||
while (node.parent != null && node == node.parent.right) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent;
|
||||
}
|
||||
|
||||
public static abstract class Visitor<E> {
|
||||
boolean stop;
|
||||
/**
|
||||
* @return 如果返回true,就代表停止遍历
|
||||
*/
|
||||
public abstract boolean visit(E element);
|
||||
}
|
||||
|
||||
private static class Node<E> {
|
||||
E element;
|
||||
Node<E> left;
|
||||
Node<E> right;
|
||||
Node<E> parent;
|
||||
public Node(E element, Node<E> parent) {
|
||||
this.element = element;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean isLeaf() {
|
||||
return left == null && right == null;
|
||||
}
|
||||
|
||||
public boolean hasTwoChildren() {
|
||||
return left != null && right != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object root() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object left(Object node) {
|
||||
return ((Node<E>)node).left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object right(Object node) {
|
||||
return ((Node<E>)node).right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object string(Object node) {
|
||||
Node<E> myNode = (Node<E>)node;
|
||||
String parentString = "null";
|
||||
if (myNode.parent != null) {
|
||||
parentString = myNode.parent.element.toString();
|
||||
}
|
||||
return myNode.element + "_p(" + parentString + ")";
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package com.mj;
|
||||
|
||||
public class Car {
|
||||
|
||||
}
|
@@ -0,0 +1,258 @@
|
||||
package com.mj;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.mj.BinarySearchTree.Visitor;
|
||||
import com.mj.file.Files;
|
||||
import com.mj.printer.BinaryTreeInfo;
|
||||
import com.mj.printer.BinaryTrees;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Main {
|
||||
|
||||
private static class PersonComparator implements Comparator<Person> {
|
||||
public int compare(Person e1, Person e2) {
|
||||
return e1.getAge() - e2.getAge();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PersonComparator2 implements Comparator<Person> {
|
||||
public int compare(Person e1, Person e2) {
|
||||
return e2.getAge() - e1.getAge();
|
||||
}
|
||||
}
|
||||
|
||||
static void test1() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 5, 8, 11, 3, 12, 1
|
||||
};
|
||||
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst.add(data[i]);
|
||||
}
|
||||
|
||||
BinaryTrees.println(bst);
|
||||
}
|
||||
|
||||
static void test2() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 5, 8, 11, 3, 12, 1
|
||||
};
|
||||
|
||||
BinarySearchTree<Person> bst1 = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst1.add(new Person(data[i]));
|
||||
}
|
||||
|
||||
BinaryTrees.println(bst1);
|
||||
|
||||
BinarySearchTree<Person> bst2 = new BinarySearchTree<>(new Comparator<Person>() {
|
||||
public int compare(Person o1, Person o2) {
|
||||
return o2.getAge() - o1.getAge();
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst2.add(new Person(data[i]));
|
||||
}
|
||||
BinaryTrees.println(bst2);
|
||||
}
|
||||
|
||||
static void test3() {
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < 40; i++) {
|
||||
bst.add((int)(Math.random() * 100));
|
||||
}
|
||||
|
||||
String str = BinaryTrees.printString(bst);
|
||||
str += "\n";
|
||||
Files.writeToFile("F:/1.txt", str, true);
|
||||
|
||||
// BinaryTrees.println(bst);
|
||||
}
|
||||
|
||||
static void test4() {
|
||||
BinaryTrees.println(new BinaryTreeInfo() {
|
||||
|
||||
@Override
|
||||
public Object string(Object node) {
|
||||
return node.toString() + "_";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object root() {
|
||||
return "A";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object right(Object node) {
|
||||
if (node.equals("A")) return "C";
|
||||
if (node.equals("C")) return "E";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object left(Object node) {
|
||||
if (node.equals("A")) return "B";
|
||||
if (node.equals("C")) return "D";
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// test3();
|
||||
|
||||
|
||||
/*
|
||||
* Java的匿名类,类似于iOS中的Block、JS中的闭包(function)
|
||||
*/
|
||||
|
||||
// BinarySearchTree<Person> bst1 = new BinarySearchTree<>(new Comparator<Person>() {
|
||||
// @Override
|
||||
// public int compare(Person o1, Person o2) {
|
||||
// return 0;
|
||||
// }
|
||||
// });
|
||||
// bst1.add(new Person(12));
|
||||
// bst1.add(new Person(15));
|
||||
//
|
||||
// BinarySearchTree<Person> bst2 = new BinarySearchTree<>(new PersonComparator());
|
||||
// bst2.add(new Person(12));
|
||||
// bst2.add(new Person(15));
|
||||
//
|
||||
|
||||
|
||||
// BinarySearchTree<Car> bst4 = new BinarySearchTree<>(new Car);
|
||||
//
|
||||
//
|
||||
// java.util.Comparator<Integer> iComparator;
|
||||
}
|
||||
|
||||
static void test5() {
|
||||
BinarySearchTree<Person> bst = new BinarySearchTree<>();
|
||||
bst.add(new Person(10, "jack"));
|
||||
bst.add(new Person(12, "rose"));
|
||||
bst.add(new Person(6, "jim"));
|
||||
|
||||
bst.add(new Person(10, "michael"));
|
||||
|
||||
BinaryTrees.println(bst);
|
||||
}
|
||||
|
||||
static void test6() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 5
|
||||
};
|
||||
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst.add(data[i]);
|
||||
}
|
||||
|
||||
// BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
// for (int i = 0; i < 10; i++) {
|
||||
// bst.add((int)(Math.random() * 100));
|
||||
// }
|
||||
BinaryTrees.println(bst);
|
||||
System.out.println(bst.isComplete());
|
||||
|
||||
// bst.levelOrderTraversal();
|
||||
|
||||
/*
|
||||
* 7
|
||||
* 4 9
|
||||
2 5
|
||||
*/
|
||||
|
||||
// bst.levelOrder(new Visitor<Integer>() {
|
||||
// public void visit(Integer element) {
|
||||
// System.out.print("_" + element + "_ ");
|
||||
// }
|
||||
// });
|
||||
|
||||
// bst.inorder(new Visitor<Integer>() {
|
||||
// public void visit(Integer element) {
|
||||
// System.out.print("_" + (element + 3) + "_ ");
|
||||
// }
|
||||
// });
|
||||
|
||||
// System.out.println(bst.height());
|
||||
}
|
||||
|
||||
static void test7() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 5, 8, 11, 3, 12, 1
|
||||
};
|
||||
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst.add(data[i]);
|
||||
}
|
||||
|
||||
BinaryTrees.println(bst);
|
||||
|
||||
bst.remove(7);
|
||||
|
||||
BinaryTrees.println(bst);
|
||||
}
|
||||
|
||||
static void test8() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 1
|
||||
};
|
||||
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst.add(data[i]);
|
||||
}
|
||||
BinaryTrees.println(bst);
|
||||
System.out.println(bst.isComplete());
|
||||
}
|
||||
|
||||
static void test9() {
|
||||
Integer data[] = new Integer[] {
|
||||
7, 4, 9, 2, 1
|
||||
};
|
||||
|
||||
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
bst.add(data[i]);
|
||||
}
|
||||
BinaryTrees.println(bst);
|
||||
|
||||
bst.preorder(new Visitor<Integer>() {
|
||||
public boolean visit(Integer element) {
|
||||
System.out.print(element + " ");
|
||||
return element == 2 ? true : false;
|
||||
}
|
||||
});
|
||||
System.out.println();
|
||||
|
||||
bst.inorder(new Visitor<Integer>() {
|
||||
public boolean visit(Integer element) {
|
||||
System.out.print(element + " ");
|
||||
return element == 4 ? true : false;
|
||||
}
|
||||
});
|
||||
System.out.println();
|
||||
|
||||
bst.postorder(new Visitor<Integer>() {
|
||||
public boolean visit(Integer element) {
|
||||
System.out.print(element + " ");
|
||||
return element == 4 ? true : false;
|
||||
}
|
||||
});
|
||||
System.out.println();
|
||||
|
||||
bst.levelOrder(new Visitor<Integer>() {
|
||||
public boolean visit(Integer element) {
|
||||
System.out.print(element + " ");
|
||||
return element == 9 ? true : false;
|
||||
}
|
||||
});
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test9();
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package com.mj;
|
||||
|
||||
public class Person implements Comparable<Person> {
|
||||
private int age;
|
||||
private String name;
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Person(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Person(int age, String name) {
|
||||
this.age = age;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Person e) {
|
||||
// if (age > e.age) return 1;
|
||||
// if (age < e.age) return -1;
|
||||
// return 0;
|
||||
return age - e.age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return age + "_" + name;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.mj.file;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
||||
public class Files {
|
||||
|
||||
public static void writeToFile(String filePath, Object data) {
|
||||
writeToFile(filePath, data, false);
|
||||
}
|
||||
|
||||
public static void writeToFile(String filePath, Object data, boolean append) {
|
||||
if (filePath == null || data == null) return;
|
||||
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
try (FileWriter writer = new FileWriter(file, append);
|
||||
BufferedWriter out = new BufferedWriter(writer) ) {
|
||||
out.write(data.toString());
|
||||
out.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.mj.printer;
|
||||
|
||||
public interface BinaryTreeInfo {
|
||||
/**
|
||||
* who is the root node
|
||||
*/
|
||||
Object root();
|
||||
/**
|
||||
* how to get the left child of the node
|
||||
*/
|
||||
Object left(Object node);
|
||||
/**
|
||||
* how to get the right child of the node
|
||||
*/
|
||||
Object right(Object node);
|
||||
/**
|
||||
* how to print the node
|
||||
*/
|
||||
Object string(Object node);
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.mj.printer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author MJ Lee
|
||||
*
|
||||
*/
|
||||
public final class BinaryTrees {
|
||||
|
||||
private BinaryTrees() {
|
||||
}
|
||||
|
||||
public static void print(BinaryTreeInfo tree) {
|
||||
print(tree, null);
|
||||
}
|
||||
|
||||
public static void println(BinaryTreeInfo tree) {
|
||||
println(tree, null);
|
||||
}
|
||||
|
||||
public static void print(BinaryTreeInfo tree, PrintStyle style) {
|
||||
if (tree == null || tree.root() == null) return;
|
||||
printer(tree, style).print();
|
||||
}
|
||||
|
||||
public static void println(BinaryTreeInfo tree, PrintStyle style) {
|
||||
if (tree == null || tree.root() == null) return;
|
||||
printer(tree, style).println();
|
||||
}
|
||||
|
||||
public static String printString(BinaryTreeInfo tree) {
|
||||
return printString(tree, null);
|
||||
}
|
||||
|
||||
public static String printString(BinaryTreeInfo tree, PrintStyle style) {
|
||||
if (tree == null || tree.root() == null) return null;
|
||||
return printer(tree, style).printString();
|
||||
}
|
||||
|
||||
private static Printer printer(BinaryTreeInfo tree, PrintStyle style) {
|
||||
if (style == PrintStyle.INORDER) return new InorderPrinter(tree);
|
||||
return new LevelOrderPrinter(tree);
|
||||
}
|
||||
|
||||
public enum PrintStyle {
|
||||
LEVEL_ORDER, INORDER
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
package com.mj.printer;
|
||||
|
||||
/**
|
||||
|
||||
┌──800
|
||||
┌──760
|
||||
│ └──600
|
||||
┌──540
|
||||
│ └──476
|
||||
│ └──445
|
||||
┌──410
|
||||
│ └──394
|
||||
381
|
||||
│ ┌──190
|
||||
│ │ └──146
|
||||
│ ┌──40
|
||||
│ │ └──35
|
||||
└──12
|
||||
└──9
|
||||
|
||||
* @author MJ Lee
|
||||
*
|
||||
*/
|
||||
public class InorderPrinter extends Printer {
|
||||
private static String rightAppend;
|
||||
private static String leftAppend;
|
||||
private static String blankAppend;
|
||||
private static String lineAppend;
|
||||
static {
|
||||
int length = 2;
|
||||
rightAppend = "┌" + Strings.repeat("─", length);
|
||||
leftAppend = "└" + Strings.repeat("─", length);
|
||||
blankAppend = Strings.blank(length + 1);
|
||||
lineAppend = "│" + Strings.blank(length);
|
||||
}
|
||||
|
||||
public InorderPrinter(BinaryTreeInfo tree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printString() {
|
||||
StringBuilder string = new StringBuilder(
|
||||
printString(tree.root(), "", "", ""));
|
||||
string.deleteCharAt(string.length() - 1);
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成node节点的字符串
|
||||
* @param nodePrefix node那一行的前缀字符串
|
||||
* @param leftPrefix node整棵左子树的前缀字符串
|
||||
* @param rightPrefix node整棵右子树的前缀字符串
|
||||
* @return
|
||||
*/
|
||||
private String printString(
|
||||
Object node,
|
||||
String nodePrefix,
|
||||
String leftPrefix,
|
||||
String rightPrefix) {
|
||||
Object left = tree.left(node);
|
||||
Object right = tree.right(node);
|
||||
String string = tree.string(node).toString();
|
||||
|
||||
int length = string.length();
|
||||
if (length % 2 == 0) {
|
||||
length--;
|
||||
}
|
||||
length >>= 1;
|
||||
|
||||
String nodeString = "";
|
||||
if (right != null) {
|
||||
rightPrefix += Strings.blank(length);
|
||||
nodeString += printString(right,
|
||||
rightPrefix + rightAppend,
|
||||
rightPrefix + lineAppend,
|
||||
rightPrefix + blankAppend);
|
||||
}
|
||||
nodeString += nodePrefix + string + "\n";
|
||||
if (left != null) {
|
||||
leftPrefix += Strings.blank(length);
|
||||
nodeString += printString(left,
|
||||
leftPrefix + leftAppend,
|
||||
leftPrefix + blankAppend,
|
||||
leftPrefix + lineAppend);
|
||||
}
|
||||
return nodeString;
|
||||
}
|
||||
}
|
@@ -0,0 +1,528 @@
|
||||
package com.mj.printer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
|
||||
┌───381────┐
|
||||
│ │
|
||||
┌─12─┐ ┌─410─┐
|
||||
│ │ │ │
|
||||
9 ┌─40─┐ 394 ┌─540─┐
|
||||
│ │ │ │
|
||||
35 ┌─190 ┌─476 ┌─760─┐
|
||||
│ │ │ │
|
||||
146 445 600 800
|
||||
|
||||
* @author MJ Lee
|
||||
*
|
||||
*/
|
||||
public class LevelOrderPrinter extends Printer {
|
||||
/**
|
||||
* 节点之间允许的最小间距(最小只能填1)
|
||||
*/
|
||||
private static final int MIN_SPACE = 1;
|
||||
private Node root;
|
||||
private int minX;
|
||||
private int maxWidth;
|
||||
|
||||
public LevelOrderPrinter(BinaryTreeInfo tree) {
|
||||
super(tree);
|
||||
|
||||
root = new Node(tree.root(), tree);
|
||||
maxWidth = root.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printString() {
|
||||
// nodes用来存放所有的节点
|
||||
List<List<Node>> nodes = new ArrayList<>();
|
||||
fillNodes(nodes);
|
||||
cleanNodes(nodes);
|
||||
compressNodes(nodes);
|
||||
addLineNodes(nodes);
|
||||
|
||||
int rowCount = nodes.size();
|
||||
|
||||
// 构建字符串
|
||||
StringBuilder string = new StringBuilder();
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
if (i != 0) {
|
||||
string.append("\n");
|
||||
}
|
||||
|
||||
List<Node> rowNodes = nodes.get(i);
|
||||
StringBuilder rowSb = new StringBuilder();
|
||||
for (Node node : rowNodes) {
|
||||
int leftSpace = node.x - rowSb.length() - minX;
|
||||
rowSb.append(Strings.blank(leftSpace));
|
||||
rowSb.append(node.string);
|
||||
}
|
||||
|
||||
string.append(rowSb);
|
||||
}
|
||||
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个元素节点
|
||||
*/
|
||||
private Node addNode(List<Node> nodes, Object btNode) {
|
||||
Node node = null;
|
||||
if (btNode != null) {
|
||||
node = new Node(btNode, tree);
|
||||
maxWidth = Math.max(maxWidth, node.width);
|
||||
nodes.add(node);
|
||||
} else {
|
||||
nodes.add(null);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以满二叉树的形式填充节点
|
||||
*/
|
||||
private void fillNodes(List<List<Node>> nodes) {
|
||||
if (nodes == null) return;
|
||||
// 第一行
|
||||
List<Node> firstRowNodes = new ArrayList<>();
|
||||
firstRowNodes.add(root);
|
||||
nodes.add(firstRowNodes);
|
||||
|
||||
// 其他行
|
||||
while (true) {
|
||||
List<Node> preRowNodes = nodes.get(nodes.size() - 1);
|
||||
List<Node> rowNodes = new ArrayList<>();
|
||||
|
||||
boolean notNull = false;
|
||||
for (Node node : preRowNodes) {
|
||||
if (node == null) {
|
||||
rowNodes.add(null);
|
||||
rowNodes.add(null);
|
||||
} else {
|
||||
Node left = addNode(rowNodes, tree.left(node.btNode));
|
||||
if (left != null) {
|
||||
node.left = left;
|
||||
left.parent = node;
|
||||
notNull = true;
|
||||
}
|
||||
|
||||
Node right = addNode(rowNodes, tree.right(node.btNode));
|
||||
if (right != null) {
|
||||
node.right = right;
|
||||
right.parent = node;
|
||||
notNull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 全是null,就退出
|
||||
if (!notNull) break;
|
||||
nodes.add(rowNodes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除全部null、更新节点的坐标
|
||||
*/
|
||||
private void cleanNodes(List<List<Node>> nodes) {
|
||||
if (nodes == null) return;
|
||||
|
||||
int rowCount = nodes.size();
|
||||
if (rowCount < 2) return;
|
||||
|
||||
// 最后一行的节点数量
|
||||
int lastRowNodeCount = nodes.get(rowCount - 1).size();
|
||||
|
||||
// 每个节点之间的间距
|
||||
int nodeSpace = maxWidth + 2;
|
||||
|
||||
// 最后一行的长度
|
||||
int lastRowLength = lastRowNodeCount * maxWidth
|
||||
+ nodeSpace * (lastRowNodeCount - 1);
|
||||
|
||||
// 空集合
|
||||
Collection<Object> nullSet = Collections.singleton(null);
|
||||
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
List<Node> rowNodes = nodes.get(i);
|
||||
|
||||
int rowNodeCount = rowNodes.size();
|
||||
// 节点左右两边的间距
|
||||
int allSpace = lastRowLength - (rowNodeCount - 1) * nodeSpace;
|
||||
int cornerSpace = allSpace / rowNodeCount - maxWidth;
|
||||
cornerSpace >>= 1;
|
||||
|
||||
int rowLength = 0;
|
||||
for (int j = 0; j < rowNodeCount; j++) {
|
||||
if (j != 0) {
|
||||
// 每个节点之间的间距
|
||||
rowLength += nodeSpace;
|
||||
}
|
||||
rowLength += cornerSpace;
|
||||
Node node = rowNodes.get(j);
|
||||
if (node != null) {
|
||||
// 居中(由于奇偶数的问题,可能有1个符号的误差)
|
||||
int deltaX = (maxWidth - node.width) >> 1;
|
||||
node.x = rowLength + deltaX;
|
||||
node.y = i;
|
||||
}
|
||||
rowLength += maxWidth;
|
||||
rowLength += cornerSpace;
|
||||
}
|
||||
// 删除所有的null
|
||||
rowNodes.removeAll(nullSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩空格
|
||||
*/
|
||||
private void compressNodes(List<List<Node>> nodes) {
|
||||
if (nodes == null) return;
|
||||
|
||||
int rowCount = nodes.size();
|
||||
if (rowCount < 2) return;
|
||||
|
||||
for (int i = rowCount - 2; i >= 0; i--) {
|
||||
List<Node> rowNodes = nodes.get(i);
|
||||
for (Node node : rowNodes) {
|
||||
Node left = node.left;
|
||||
Node right = node.right;
|
||||
if (left == null && right == null) continue;
|
||||
if (left != null && right != null) {
|
||||
// 让左右节点对称
|
||||
node.balance(left, right);
|
||||
|
||||
// left和right之间可以挪动的最小间距
|
||||
int leftEmpty = node.leftBoundEmptyLength();
|
||||
int rightEmpty = node.rightBoundEmptyLength();
|
||||
int empty = Math.min(leftEmpty, rightEmpty);
|
||||
empty = Math.min(empty, (right.x - left.rightX()) >> 1);
|
||||
|
||||
// left、right的子节点之间可以挪动的最小间距
|
||||
int space = left.minLevelSpaceToRight(right) - MIN_SPACE;
|
||||
space = Math.min(space >> 1, empty);
|
||||
|
||||
// left、right往中间挪动
|
||||
if (space > 0) {
|
||||
left.translateX(space);
|
||||
right.translateX(-space);
|
||||
}
|
||||
|
||||
// 继续挪动
|
||||
space = left.minLevelSpaceToRight(right) - MIN_SPACE;
|
||||
if (space < 1) continue;
|
||||
|
||||
// 可以继续挪动的间距
|
||||
leftEmpty = node.leftBoundEmptyLength();
|
||||
rightEmpty = node.rightBoundEmptyLength();
|
||||
if (leftEmpty < 1 && rightEmpty < 1) continue;
|
||||
|
||||
if (leftEmpty > rightEmpty) {
|
||||
left.translateX(Math.min(leftEmpty, space));
|
||||
} else {
|
||||
right.translateX(-Math.min(rightEmpty, space));
|
||||
}
|
||||
} else if (left != null) {
|
||||
left.translateX(node.leftBoundEmptyLength());
|
||||
} else { // right != null
|
||||
right.translateX(-node.rightBoundEmptyLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addXLineNode(List<Node> curRow, Node parent, int x) {
|
||||
Node line = new Node("─");
|
||||
line.x = x;
|
||||
line.y = parent.y;
|
||||
curRow.add(line);
|
||||
}
|
||||
|
||||
private Node addLineNode(List<Node> curRow, List<Node> nextRow, Node parent, Node child) {
|
||||
if (child == null) return null;
|
||||
|
||||
Node top = null;
|
||||
int topX = child.topLineX();
|
||||
if (child == parent.left) {
|
||||
top = new Node("┌");
|
||||
curRow.add(top);
|
||||
|
||||
for (int x = topX + 1; x < parent.x; x++) {
|
||||
addXLineNode(curRow, parent, x);
|
||||
}
|
||||
} else {
|
||||
for (int x = parent.rightX(); x < topX; x++) {
|
||||
addXLineNode(curRow, parent, x);
|
||||
}
|
||||
|
||||
top = new Node("┐");
|
||||
curRow.add(top);
|
||||
}
|
||||
|
||||
// 坐标
|
||||
top.x = topX;
|
||||
top.y = parent.y;
|
||||
child.y = parent.y + 2;
|
||||
minX = Math.min(minX, child.x);
|
||||
|
||||
// 竖线
|
||||
Node bottom = new Node("│");
|
||||
bottom.x = topX;
|
||||
bottom.y = parent.y + 1;
|
||||
nextRow.add(bottom);
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
private void addLineNodes(List<List<Node>> nodes) {
|
||||
List<List<Node>> newNodes = new ArrayList<>();
|
||||
|
||||
int rowCount = nodes.size();
|
||||
if (rowCount < 2) return;
|
||||
|
||||
minX = root.x;
|
||||
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
List<Node> rowNodes = nodes.get(i);
|
||||
if (i == rowCount - 1) {
|
||||
newNodes.add(rowNodes);
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Node> newRowNodes = new ArrayList<>();
|
||||
newNodes.add(newRowNodes);
|
||||
|
||||
List<Node> lineNodes = new ArrayList<>();
|
||||
newNodes.add(lineNodes);
|
||||
for (Node node : rowNodes) {
|
||||
addLineNode(newRowNodes, lineNodes, node, node.left);
|
||||
newRowNodes.add(node);
|
||||
addLineNode(newRowNodes, lineNodes, node, node.right);
|
||||
}
|
||||
}
|
||||
|
||||
nodes.clear();
|
||||
nodes.addAll(newNodes);
|
||||
}
|
||||
|
||||
private static class Node {
|
||||
/**
|
||||
* 顶部符号距离父节点的最小距离(最小能填0)
|
||||
*/
|
||||
private static final int TOP_LINE_SPACE = 1;
|
||||
|
||||
Object btNode;
|
||||
Node left;
|
||||
Node right;
|
||||
Node parent;
|
||||
/**
|
||||
* 首字符的位置
|
||||
*/
|
||||
int x;
|
||||
int y;
|
||||
int treeHeight;
|
||||
String string;
|
||||
int width;
|
||||
|
||||
private void init(String string) {
|
||||
string = (string == null) ? "null" : string;
|
||||
string = string.isEmpty() ? " " : string;
|
||||
|
||||
width = string.length();
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
public Node(String string) {
|
||||
init(string);
|
||||
}
|
||||
|
||||
public Node(Object btNode, BinaryTreeInfo opetaion) {
|
||||
init(opetaion.string(btNode).toString());
|
||||
|
||||
this.btNode = btNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 顶部方向字符的X(极其重要)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int topLineX() {
|
||||
// 宽度的一半
|
||||
int delta = width;
|
||||
if (delta % 2 == 0) {
|
||||
delta--;
|
||||
}
|
||||
delta >>= 1;
|
||||
|
||||
if (parent != null && this == parent.left) {
|
||||
return rightX() - 1 - delta;
|
||||
} else {
|
||||
return x + delta;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 右边界的位置(rightX 或者 右子节点topLineX的下一个位置)(极其重要)
|
||||
*/
|
||||
private int rightBound() {
|
||||
if (right == null) return rightX();
|
||||
return right.topLineX() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 左边界的位置(x 或者 左子节点topLineX)(极其重要)
|
||||
*/
|
||||
private int leftBound() {
|
||||
if (left == null) return x;
|
||||
return left.topLineX();
|
||||
}
|
||||
|
||||
/**
|
||||
* x ~ 左边界之间的长度(包括左边界字符)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int leftBoundLength() {
|
||||
return x - leftBound();
|
||||
}
|
||||
|
||||
/**
|
||||
* rightX ~ 右边界之间的长度(包括右边界字符)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int rightBoundLength() {
|
||||
return rightBound() - rightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* 左边界可以清空的长度
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int leftBoundEmptyLength() {
|
||||
return leftBoundLength() - 1 - TOP_LINE_SPACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 右边界可以清空的长度
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int rightBoundEmptyLength() {
|
||||
return rightBoundLength() - 1 - TOP_LINE_SPACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 让left和right基于this对称
|
||||
*/
|
||||
private void balance(Node left, Node right) {
|
||||
if (left == null || right == null)
|
||||
return;
|
||||
// 【left的尾字符】与【this的首字符】之间的间距
|
||||
int deltaLeft = x - left.rightX();
|
||||
// 【this的尾字符】与【this的首字符】之间的间距
|
||||
int deltaRight = right.x - rightX();
|
||||
|
||||
int delta = Math.max(deltaLeft, deltaRight);
|
||||
int newRightX = rightX() + delta;
|
||||
right.translateX(newRightX - right.x);
|
||||
|
||||
int newLeftX = x - delta - left.width;
|
||||
left.translateX(newLeftX - left.x);
|
||||
}
|
||||
|
||||
private int treeHeight(Node node) {
|
||||
if (node == null) return 0;
|
||||
if (node.treeHeight != 0) return node.treeHeight;
|
||||
node.treeHeight = 1 + Math.max(
|
||||
treeHeight(node.left), treeHeight(node.right));
|
||||
return node.treeHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 和右节点之间的最小层级距离
|
||||
*/
|
||||
private int minLevelSpaceToRight(Node right) {
|
||||
int thisHeight = treeHeight(this);
|
||||
int rightHeight = treeHeight(right);
|
||||
int minSpace = Integer.MAX_VALUE;
|
||||
for (int i = 0; i < thisHeight && i < rightHeight; i++) {
|
||||
int space = right.levelInfo(i).leftX
|
||||
- this.levelInfo(i).rightX;
|
||||
minSpace = Math.min(minSpace, space);
|
||||
}
|
||||
return minSpace;
|
||||
}
|
||||
|
||||
private LevelInfo levelInfo(int level) {
|
||||
if (level < 0) return null;
|
||||
int levelY = y + level;
|
||||
if (level >= treeHeight(this)) return null;
|
||||
|
||||
List<Node> list = new ArrayList<>();
|
||||
Queue<Node> queue = new LinkedList<>();
|
||||
queue.offer(this);
|
||||
|
||||
// 层序遍历找出第level行的所有节点
|
||||
while (!queue.isEmpty()) {
|
||||
Node node = queue.poll();
|
||||
if (levelY == node.y) {
|
||||
list.add(node);
|
||||
} else if (node.y > levelY) break;
|
||||
|
||||
if (node.left != null) {
|
||||
queue.offer(node.left);
|
||||
}
|
||||
if (node.right != null) {
|
||||
queue.offer(node.right);
|
||||
}
|
||||
}
|
||||
|
||||
Node left = list.get(0);
|
||||
Node right = list.get(list.size() - 1);
|
||||
return new LevelInfo(left, right);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尾字符的下一个位置
|
||||
*/
|
||||
public int rightX() {
|
||||
return x + width;
|
||||
}
|
||||
|
||||
public void translateX(int deltaX) {
|
||||
if (deltaX == 0) return;
|
||||
x += deltaX;
|
||||
|
||||
// 如果是LineNode
|
||||
if (btNode == null) return;
|
||||
|
||||
if (left != null) {
|
||||
left.translateX(deltaX);
|
||||
}
|
||||
if (right != null) {
|
||||
right.translateX(deltaX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LevelInfo {
|
||||
int leftX;
|
||||
int rightX;
|
||||
|
||||
public LevelInfo(Node left, Node right) {
|
||||
this.leftX = left.leftBound();
|
||||
this.rightX = right.rightBound();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.mj.printer;
|
||||
|
||||
public abstract class Printer {
|
||||
/**
|
||||
* 二叉树的基本信息
|
||||
*/
|
||||
protected BinaryTreeInfo tree;
|
||||
|
||||
public Printer(BinaryTreeInfo tree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成打印的字符串
|
||||
*/
|
||||
public abstract String printString();
|
||||
|
||||
/**
|
||||
* 打印后换行
|
||||
*/
|
||||
public void println() {
|
||||
print();
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
*/
|
||||
public void print() {
|
||||
System.out.print(printString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.mj.printer;
|
||||
|
||||
public class Strings {
|
||||
public static String repeat(String string, int count) {
|
||||
if (string == null) return null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while (count-- > 0) {
|
||||
builder.append(string);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String blank(int length) {
|
||||
if (length < 0) return null;
|
||||
if (length == 0) return "";
|
||||
return String.format("%" + length + "s", "");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user