forked from sduonline/sc-resources
增加淘宝群内容,修改部分文件组织
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>
|
||||
17
数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.project
Normal file
17
数据结构(双语)/数据结构 day16【瑞客论坛 www.ruike1.com】/代码/07-AVL树/.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>07-AVL树</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.
@@ -0,0 +1,75 @@
|
||||
package com.mj;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mj.file.Files;
|
||||
import com.mj.printer.BinaryTreeInfo;
|
||||
import com.mj.printer.BinaryTrees;
|
||||
import com.mj.tree.AVLTree;
|
||||
import com.mj.tree.BST;
|
||||
import com.mj.tree.BinaryTree;
|
||||
import com.mj.tree.BinaryTree.Visitor;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Main {
|
||||
|
||||
static void test1() {
|
||||
Integer data[] = new Integer[] {
|
||||
67, 52, 92, 96, 53, 95, 13, 63, 34, 82, 76, 54, 9, 68, 39
|
||||
};
|
||||
|
||||
AVLTree<Integer> avl = new AVLTree<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
avl.add(data[i]);
|
||||
// System.out.println("【" + data[i] + "】");
|
||||
// BinaryTrees.println(avl);
|
||||
// System.out.println("---------------------------------------");
|
||||
}
|
||||
|
||||
// for (int i = 0; i < data.length; i++) {
|
||||
// avl.remove(data[i]);
|
||||
// System.out.println("【" + data[i] + "】");
|
||||
// BinaryTrees.println(avl);
|
||||
// System.out.println("---------------------------------------");
|
||||
// }
|
||||
|
||||
|
||||
BinaryTrees.println(avl);
|
||||
}
|
||||
|
||||
static void test2() {
|
||||
List<Integer> data = new ArrayList<>();
|
||||
for (int i = 0; i < 100_0000; i++) {
|
||||
data.add((int)(Math.random() * 100_0000));
|
||||
}
|
||||
|
||||
BST<Integer> bst = new BST<>();
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
bst.add(data.get(i));
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
bst.contains(data.get(i));
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
bst.remove(data.get(i));
|
||||
}
|
||||
|
||||
AVLTree<Integer> avl = new AVLTree<>();
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
avl.add(data.get(i));
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
avl.contains(data.get(i));
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
avl.remove(data.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test1();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.mj.tree;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class AVLTree<E> extends BST<E> {
|
||||
public AVLTree() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public AVLTree(Comparator<E> comparator) {
|
||||
super(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterAdd(Node<E> node) {
|
||||
while ((node = node.parent) != null) {
|
||||
if (isBalanced(node)) {
|
||||
// 更新高度
|
||||
updateHeight(node);
|
||||
} else {
|
||||
// 恢复平衡
|
||||
rebalance(node);
|
||||
// 整棵树恢复平衡
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterRemove(Node<E> node) {
|
||||
while ((node = node.parent) != null) {
|
||||
if (isBalanced(node)) {
|
||||
// 更新高度
|
||||
updateHeight(node);
|
||||
} else {
|
||||
// 恢复平衡
|
||||
rebalance(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node<E> createNode(E element, Node<E> parent) {
|
||||
return new AVLNode<>(element, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复平衡
|
||||
* @param grand 高度最低的那个不平衡节点
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void rebalance2(Node<E> grand) {
|
||||
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
|
||||
Node<E> node = ((AVLNode<E>)parent).tallerChild();
|
||||
if (parent.isLeftChild()) { // L
|
||||
if (node.isLeftChild()) { // LL
|
||||
rotateRight(grand);
|
||||
} else { // LR
|
||||
rotateLeft(parent);
|
||||
rotateRight(grand);
|
||||
}
|
||||
} else { // R
|
||||
if (node.isLeftChild()) { // RL
|
||||
rotateRight(parent);
|
||||
rotateLeft(grand);
|
||||
} else { // RR
|
||||
rotateLeft(grand);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 恢复平衡
|
||||
* @param grand 高度最低的那个不平衡节点
|
||||
*/
|
||||
private void rebalance(Node<E> grand) {
|
||||
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
|
||||
Node<E> node = ((AVLNode<E>)parent).tallerChild();
|
||||
if (parent.isLeftChild()) { // L
|
||||
if (node.isLeftChild()) { // LL
|
||||
rotate(grand, node, node.right, parent, parent.right, grand);
|
||||
} else { // LR
|
||||
rotate(grand, parent, node.left, node, node.right, grand);
|
||||
}
|
||||
} else { // R
|
||||
if (node.isLeftChild()) { // RL
|
||||
rotate(grand, grand, node.left, node, node.right, parent);
|
||||
} else { // RR
|
||||
rotate(grand, grand, parent.left, parent, node.left, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void rotate(
|
||||
Node<E> r, // 子树的根节点
|
||||
Node<E> b, Node<E> c,
|
||||
Node<E> d,
|
||||
Node<E> e, Node<E> f) {
|
||||
// 让d成为这棵子树的根节点
|
||||
d.parent = r.parent;
|
||||
if (r.isLeftChild()) {
|
||||
r.parent.left = d;
|
||||
} else if (r.isRightChild()) {
|
||||
r.parent.right = d;
|
||||
} else {
|
||||
root = d;
|
||||
}
|
||||
|
||||
//b-c
|
||||
b.right = c;
|
||||
if (c != null) {
|
||||
c.parent = b;
|
||||
}
|
||||
updateHeight(b);
|
||||
|
||||
// e-f
|
||||
f.left = e;
|
||||
if (e != null) {
|
||||
e.parent = f;
|
||||
}
|
||||
updateHeight(f);
|
||||
|
||||
// b-d-f
|
||||
d.left = b;
|
||||
d.right = f;
|
||||
b.parent = d;
|
||||
f.parent = d;
|
||||
updateHeight(d);
|
||||
}
|
||||
|
||||
private void rotateLeft(Node<E> grand) {
|
||||
Node<E> parent = grand.right;
|
||||
Node<E> child = parent.left;
|
||||
grand.right = child;
|
||||
parent.left = grand;
|
||||
afterRotate(grand, parent, child);
|
||||
}
|
||||
|
||||
private void rotateRight(Node<E> grand) {
|
||||
Node<E> parent = grand.left;
|
||||
Node<E> child = parent.right;
|
||||
grand.left = child;
|
||||
parent.right = grand;
|
||||
afterRotate(grand, parent, child);
|
||||
}
|
||||
|
||||
private void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
|
||||
// 让parent称为子树的根节点
|
||||
parent.parent = grand.parent;
|
||||
if (grand.isLeftChild()) {
|
||||
grand.parent.left = parent;
|
||||
} else if (grand.isRightChild()) {
|
||||
grand.parent.right = parent;
|
||||
} else { // grand是root节点
|
||||
root = parent;
|
||||
}
|
||||
|
||||
// 更新child的parent
|
||||
if (child != null) {
|
||||
child.parent = grand;
|
||||
}
|
||||
|
||||
// 更新grand的parent
|
||||
grand.parent = parent;
|
||||
|
||||
// 更新高度
|
||||
updateHeight(grand);
|
||||
updateHeight(parent);
|
||||
}
|
||||
|
||||
private boolean isBalanced(Node<E> node) {
|
||||
return Math.abs(((AVLNode<E>)node).balanceFactor()) <= 1;
|
||||
}
|
||||
|
||||
private void updateHeight(Node<E> node) {
|
||||
((AVLNode<E>)node).updateHeight();
|
||||
}
|
||||
|
||||
private static class AVLNode<E> extends Node<E> {
|
||||
int height = 1;
|
||||
|
||||
public AVLNode(E element, Node<E> parent) {
|
||||
super(element, parent);
|
||||
}
|
||||
|
||||
public int balanceFactor() {
|
||||
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
|
||||
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
|
||||
return leftHeight - rightHeight;
|
||||
}
|
||||
|
||||
public void updateHeight() {
|
||||
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
|
||||
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
|
||||
height = 1 + Math.max(leftHeight, rightHeight);
|
||||
}
|
||||
|
||||
public Node<E> tallerChild() {
|
||||
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
|
||||
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
|
||||
if (leftHeight > rightHeight) return left;
|
||||
if (leftHeight < rightHeight) return right;
|
||||
return isLeftChild() ? left : right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String parentString = "null";
|
||||
if (parent != null) {
|
||||
parentString = parent.element.toString();
|
||||
}
|
||||
return element + "_p(" + parentString + ")_h(" + height + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.mj.tree;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BST<E> extends BinaryTree<E> {
|
||||
private Comparator<E> comparator;
|
||||
|
||||
public BST() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public BST(Comparator<E> comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
public void add(E element) {
|
||||
elementNotNullCheck(element);
|
||||
|
||||
// 添加第一个节点
|
||||
if (root == null) {
|
||||
root = createNode(element, null);
|
||||
size++;
|
||||
|
||||
// 新添加节点之后的处理
|
||||
afterAdd(root);
|
||||
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 = createNode(element, parent);
|
||||
if (cmp > 0) {
|
||||
parent.right = newNode;
|
||||
} else {
|
||||
parent.left = newNode;
|
||||
}
|
||||
size++;
|
||||
|
||||
// 新添加节点之后的处理
|
||||
afterAdd(newNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加node之后的调整
|
||||
* @param node 新添加的节点
|
||||
*/
|
||||
protected void afterAdd(Node<E> node) { }
|
||||
|
||||
/**
|
||||
* 删除node之后的调整
|
||||
* @param node 被删除的节点
|
||||
*/
|
||||
protected void afterRemove(Node<E> node) { }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 删除节点之后的处理
|
||||
afterRemove(node);
|
||||
} else if (node.parent == null) { // node是叶子节点并且是根节点
|
||||
root = null;
|
||||
|
||||
// 删除节点之后的处理
|
||||
afterRemove(node);
|
||||
} else { // node是叶子节点,但不是根节点
|
||||
if (node == node.parent.left) {
|
||||
node.parent.left = null;
|
||||
} else { // node == node.parent.right
|
||||
node.parent.right = null;
|
||||
}
|
||||
|
||||
// 删除节点之后的处理
|
||||
afterRemove(node);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package com.mj.tree;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.mj.printer.BinaryTreeInfo;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BinaryTree<E> implements BinaryTreeInfo {
|
||||
protected int size;
|
||||
protected Node<E> root;
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
root = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
queue.offer(node.right);
|
||||
} else { // 后面遍历的节点都必须是叶子节点
|
||||
leaf = true;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
protected Node<E> createNode(E element, Node<E> parent) {
|
||||
return new Node<>(element, parent);
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected 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,就代表停止遍历
|
||||
*/
|
||||
abstract boolean visit(E element);
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
public boolean isLeftChild() {
|
||||
return parent != null && this == parent.left;
|
||||
}
|
||||
|
||||
public boolean isRightChild() {
|
||||
return parent != null && this == parent.right;
|
||||
}
|
||||
|
||||
public Node<E> sibling() {
|
||||
if (isLeftChild()) {
|
||||
return parent.right;
|
||||
}
|
||||
|
||||
if (isRightChild()) {
|
||||
return parent.left;
|
||||
}
|
||||
|
||||
return 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) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user