fork 自 sduonline/sc-resources
增加淘宝群内容,修改部分文件组织
此提交包含在:
@@ -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
|
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
未顯示二進位檔案。
@@ -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", "");
|
||||
}
|
||||
}
|
新增問題並參考
封鎖使用者