import java.util.*;
public class AvlTree {
private Node root;
//左左斜
private static final int LL = 1;
//左右斜
private static final int LR = 2;
//右右斜
private static final int RR = 3;
//右左斜
private static final int RL = 4;
//正常
private static final int NORMAL = 0;
private static final class Node {
private int key;
private int value;
private int height;
private Node left;
private Node right;
private Node(int key, int value, int height, Node left, Node right) {
this.key = key;
this.value = value;
this.height = height;
this.left = left;
this.right = right;
}
@Override
public String toString() {
return String.format("<%d:%d>", key, value);
}
}
public void put(int key, int value) {
root = doPut(root, key, value);
}
public void remove(int key) {
root = doRemove(root, key);
}
public int get(int key) {
return doGet(root, key);
}
//描绘树状结构
public void draw() {
//当前层面积递推公式:(上一层面积*2+当前层数-1)/(当前层数-1)*当前层数
//一层 1
//两层 6
//三层 12
if (root == null) return;
int area = 1;
for (int floor = 2; floor <= root.height; floor++) area = (area * 2 + floor - 1) / (floor - 1) * floor;
int row = root.height;
int col = area / row;
Queue<Node> nodeQueue = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
int nodeCount = (int) Math.pow(2, root.height) - 1;
int idx = 0;
Node node = root;
nodeQueue.offer(node);
while (idx++ < nodeCount) {
node = nodeQueue.poll();
if (node != null) {
nodeQueue.add(node.left);
nodeQueue.add(node.right);
} else {
nodeQueue.add(null);
nodeQueue.add(null);
}
nodeList.add(node);
}
String[][] table = new String[row][col];
int strMaxLength = fillTable(table, nodeList, 0, 0, 0, nodeList.size() - 1);
printTable(table, strMaxLength);
}
//打印所有元素kv,从小到大
public void show() {
System.out.println(this);
}
private int status(Node node) {
if (node == null) return NORMAL;
int status;
Node l = node.left;
Node r = node.right;
int lh = l != null ? l.height : 0;
int rh = r != null ? r.height : 0;
if (2 <= lh - rh) status = LL;
else if (2 <= rh - lh) status = RR;
else return NORMAL;
if (status == LL) {
Node ll = l != null ? l.left : null;
Node lr = l != null ? l.right : null;
int llh = ll != null ? ll.height : 0;
int lrh = lr != null ? lr.height : 0;
status = lrh < llh ? status : LR;
} else {
Node rr = r != null ? r.right : null;
Node rl = r != null ? r.left : null;
int rrh = rr != null ? rr.height : 0;
int rlh = rl != null ? rl.height : 0;
status = rlh < rrh ? status : RL;
}
return status;
}
private Node leftRotate(Node node) {
if (node == null) throw new IllegalArgumentException("node不允许为null");
Node r = node.right;
if (r == null) throw new IllegalArgumentException("node right不允许为null");
Node rl = r.left;
r.left = node;
node.right = rl;
node.height = Math.max(node.left != null ? node.left.height : 0, node.right != null ? node.right.height : 0) + 1;
r.height = Math.max(r.left.height, r.right != null ? r.right.height : 0) + 1;
return r;
}
private Node rightRotate(Node node) {
if (node == null) throw new IllegalArgumentException("node不允许为null");
Node l = node.left;
if (l == null) throw new IllegalArgumentException("node left不允许为null");
Node lr = l.right;
l.right = node;
node.left = lr;
node.height = Math.max(node.left != null ? node.left.height : 0, node.right != null ? node.right.height : 0) + 1;
l.height = Math.max(l.left != null ? l.left.height : 0, l.right.height) + 1;
return l;
}
private Node noRotate(Node root) {
if (root == null) return null;
root.height = Math.max(root.left != null ? root.left.height : 0, root.right != null ? root.right.height : 0) + 1;
return root;
}
private int doGet(Node node, int key) {
if (node == null) throw new IllegalArgumentException("不允许访问不存在的元素");
if (key < node.key) return doGet(node.left, key);
else if (node.key < key) return doGet(node.right, key);
else return node.value;
}
private Node doRemove(Node node, int key) {
if (node == null) throw new IllegalArgumentException("不允许删除不存在的节点");
if (key < node.key) {
node.left = doRemove(node.left, key);
} else if (node.key < key) {
node.right = doRemove(node.right, key);
} else {
if (node.left != null) {
Node leftMax = searchMax(node.left);
swap(node, leftMax);
node.left = doRemove(node.left, key);
} else if (node.right != null) {
Node rightMin = searchMin(node.right);
swap(node, rightMin);
node.right = doRemove(node.right, key);
} else {
node = null;
}
}
return reBalance(node);
}
private void swap(Node node1, Node node2) {
if (node1 == null || node2 == null) throw new IllegalArgumentException("node1 node2 不允许为null");
int tmpKey = node1.key;
int tmpValue = node1.value;
node1.key = node2.key;
node1.value = node2.value;
node2.key = tmpKey;
node2.value = tmpValue;
}
private Node searchMax(Node node) {
if (node.right != null) return searchMax(node.right);
return node;
}
private Node searchMin(Node node) {
if (node.left != null) return searchMin(node.left);
return node;
}
private Node reBalance(Node node) {
switch (status(node)) {
case LL:
//左左倾斜
return rightRotate(node);
case LR:
//左右倾斜
node.left = leftRotate(node.left);
return rightRotate(node);
case RR:
//右右倾斜
return leftRotate(node);
case RL:
//右左倾斜
node.right = rightRotate(node.right);
return leftRotate(node);
default:
//平衡
return noRotate(node);
}
}
private Node doPut(Node root, int key, int value) {
if (root == null) return new Node(key, value, 1, null, null);
if (key < root.key) root.left = doPut(root.left, key, value);
else if (root.key < key) root.right = doPut(root.right, key, value);
else root.value = value;
return reBalance(root);
}
//用于打印avl树,先将表格给初始化出来先返回单个字符串最大长度,用于后期绘图
private int fillTable(String[][] table, List<Node> nodeList, int idx, int strMaxLength, int start, int end) {
if (end < start) return strMaxLength;
int row = (int) Math.floor(Math.log(idx + 1) / Math.log(2));
int col = (start + end) / 2;
Node node = nodeList.get(idx);
table[row][col] = node != null ? nodeList.get(idx).key + "" : "@";
strMaxLength = Math.max(table[row][col].length(), strMaxLength);
return Math.max(fillTable(table, nodeList, idx * 2 + 1, strMaxLength, start, col - 1), fillTable(table, nodeList, idx * 2 + 2, strMaxLength, col + 1, end));
}
private void printTable(String[][] table, int strMaxLength) {
String[][] newTable = new String[table.length * 2 - 1][];
int idx = -1;
for (int i = 0; i < table.length; i++) {
String[] tmp;
tmp = new String[table[i].length * strMaxLength];
newTable[++idx] = tmp;
for (int j = 0; j < table[i].length; j++) {
if (table[i][j] == null) {
for (int z = j * strMaxLength; z < (j + 1) * strMaxLength; z++) tmp[z] = " ";
} else {
for (int z = j * strMaxLength, k = 0; z < (j + 1) * strMaxLength; z++, k++) {
if (k < table[i][j].length()) tmp[z] = table[i][j].charAt(k) + "";
else tmp[z] = " ";
}
}
}
if (newTable.length - 1 <= idx) break;
tmp = new String[table[i].length * strMaxLength];
Arrays.fill(tmp, " ");
newTable[++idx] = tmp;
}
fillTableWithLink(newTable, 0, 0, newTable[0].length - 1);
System.out.println(generateTableWithLink(newTable));
}
//画数节点之间的连接
private String generateTableWithLink(String[][] newTable) {
StringJoiner stringJoiner = new StringJoiner("\r\n");
for (String[] l : newTable) {
StringBuilder stringBuilder = new StringBuilder();
for (String ll : l) {
stringBuilder.append(ll);
}
stringJoiner.add(stringBuilder);
}
return stringJoiner.toString();
}
//填充表格,带连接线的那种
private void fillTableWithLink(String[][] newTable, int row, int start, int end) {
if (newTable.length - 2 <= row) return;
int center = (start + end) / 2;
newTable[row + 1][center] = "|";
int l = center - 1;
int r = center + 1;
int le = 0;
int re = end;
while (le <= l && 0 <= l) {
if (!" ".equals(newTable[row + 2][l])) le = l - 1;
newTable[row + 1][l] = "_";
l--;
}
while (r <= re && r <= end) {
if (!" ".equals(newTable[row + 2][r])) re = r + 1;
newTable[row + 1][r] = "_";
r++;
}
fillTableWithLink(newTable, row + 2, start, center - 1);
fillTableWithLink(newTable, row + 2, center + 1, end);
}
@Override
public String toString() {
//利用栈结构完成中序遍历
Stack<Node> nodeStack = new Stack<>();
StringJoiner stringJoiner = new StringJoiner(" , ");
nodeStack.push(root);
Node node = root;
Node pop;
boolean leftVisited = false;
while (!nodeStack.isEmpty() && node != null) {
if (node.left != null && !leftVisited) {
node = node.left;
nodeStack.push(node);
} else {
pop = nodeStack.pop();
stringJoiner.add(String.format("%d:%d", pop.key, pop.value));
if (pop.right != null) {
node = pop.right;
nodeStack.push(node);
leftVisited = false;
} else {
if (nodeStack.isEmpty()) break;
node = nodeStack.peek();
leftVisited = true;
}
}
}
return "{" + stringJoiner + "}";
}
public static void main(String[] args) {
AvlTree avlTree = new AvlTree();
for (int i = 1; i <= 15; i++) avlTree.put(i, i);
avlTree.draw();
}
}
/*
8
_________|__________
4 12
_____|_____ _____|______
2 6 10 14
__|___ ___|___ ___|___ ___|___
1 3 5 7 9 11 13 15
* */
avl树自带打印功能
于 2024-08-16 18:50:36 首次发布