avl树自带打印功能

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 
* */
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值