打印二叉树

力扣上刷二叉树相关的题目时,在本地测试总是很麻烦,所以写了个工具。具体功能:

  1. 从 Integer[] 建立二叉树;
  2. 将二叉树填充为满二叉树并打印;
  3. 将二叉树在终端中打印出图形化界面。

所有代码都是跑过的,拿着就能用。这里主要是记录一下,省的以后用的时候又要重写。代码都有注释,如果能够帮助到大家更好。

文章目录

    • 二叉树节点定义
    • 工具类
    • 代码测试
    • 测试结果

二叉树节点定义

public class TreeNode {
    public Integer val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode() {
    }

    public TreeNode(Integer val) {
        this.val = val;
    }

    public TreeNode(Integer val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

工具类

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.LinkedList;

public class TreeProcession {
    /**
     * 通过一个数组建立二叉树
     * @param arr 一个整型数组,按照完全二叉树的规则存储,空节点用null
     * @return
     */
    public TreeNode buildBTbyArray(Integer[]arr){
        if(!isValidBTArray(arr)) {
            System.out.println("Invalid Binary Tree Array!!!");
            return null;
        }
        TreeNode [] tree = new TreeNode[arr.length];
        for(int i=0; i<arr.length; i++){
            if(arr[i]==null){
                tree[i] = null;
            }else {
                tree[i] = new TreeNode(arr[i]);
            }
        }

        for(int i=0; i<tree.length;i++){
            if(tree[i]==null) continue;
            if(2*i+1 < tree.length && tree[2*i+1]!=null){
                tree[i].left = tree[2*i+1];
            }
            if(2*i+2 < tree.length && tree[2*i+2]!=null){
                tree[i].right = tree[2*i+2];
            }
        }
        return tree[0];
    }

    /**
     * 判断输入的数组是否是二叉树的合法表达
     * 判断规则:当一个节点为null,而其子节点不为null,则认为是非法的
     * 还有末尾跟很多无意义null的情况应该也是非法,但是自己用,就不管那么多了
     * @param arr
     * @return
     */
    public boolean isValidBTArray(Integer[]arr){
        for(int i=0; i<arr.length; i++){
            if(arr[i]==null){
                if(2*i+1<arr.length && arr[2*i+1]!=null)
                    return false;
                if(2*i+2<arr.length && arr[2*i+2]!=null)
                    return false;
            }
        }
        return true;
    }

    /**
     * 将一棵二叉树用null填充为满二叉树,并返回其对应存储数组
     * 难点在于判断是否到达最后一层,因为对于非最后一层的null节点,同样要存入null,如果是最后一层,则不再继续存
     * @param root
     * @return
     */
    public ArrayList<Integer> binaryTree2Array(TreeNode root){
        ArrayList<ArrayList<Integer>> arr = _binaryTree2ArrayHelper(root);
        ArrayList<Integer> res = new ArrayList<>();
        for(ArrayList<Integer> levelArr:arr){
            res.addAll(levelArr);
        }
        int j=res.size()-1;
        while (res.get(j)==null){
            res.remove(j);
            j--;
        }
        return res;
    }

    /**
     * 将二叉树补全为完全二叉树并将每层结果存储返回
     * @param root
     * @return 返回二叉树的层序遍历,每层节点单独存放
     */
    private ArrayList<ArrayList<Integer>> _binaryTree2ArrayHelper(TreeNode root){
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        LinkedList<TreeNode> queue = new LinkedList<>();

        int h = height(root);
        int level = 1;
        queue.add(root);
        //通过level来发现是不是到达了最后一层
        while (!queue.isEmpty() && level<h){
            int length = queue.size();
            ArrayList<Integer> levelArray = new ArrayList<>();
            for(int i=0; i<length;i++){
                TreeNode temp = queue.removeFirst();
                if(temp==null){
                    levelArray.add(null);
                    queue.add(new TreeNode());
                    queue.add(new TreeNode());
                }else {
                    levelArray.add(temp.val);
                    if(temp.left!=null){
                        queue.add(temp.left);
                    }else {
                        queue.add(new TreeNode());
                    }
                    if(temp.right!=null){
                        queue.add(temp.right);
                    }else {
                        queue.add(new TreeNode());
                    }
                }
            }
            res.add(levelArray);
            level++;
        }
        //单独处理最后一层
        int length = queue.size();
        ArrayList<Integer> levelArray = new ArrayList<>();
        for(int i=0; i<length;i++){
            TreeNode temp = queue.removeFirst();
            if(temp==null){
                levelArray.add(null);
            }else {
                levelArray.add(temp.val);
            }
        }
        res.add(levelArray);
        return res;
    }


    /**
     * 获得一个二叉树的高度
     * @param root
     * @return
     */
    public int height(TreeNode root){
        if(root == null) return 0;
        return Math.max(height(root.left),height(root.right))+1;
    }

    /**
     * 打印图形化二叉树
     * @param root 二叉树根节点
     */
    public void printGraphBT(TreeNode root){
        String nullC = " ^ ";
        String space = "   "; //打印的树中的每个节点占3个位置,当数字大于三位数时,显示会移位
        ArrayList<ArrayList<Integer>> arr = _binaryTree2ArrayHelper(root);
        ArrayList<StringBuilder> res = new ArrayList<>();
        int h = arr.size(); //根据当前层的高度确定当前层两个节点之间的间距
        for(int j=0; j<arr.size(); j++){
            StringBuilder s = new StringBuilder();
            ArrayList<Integer> levelArr = arr.get(j);
            //将当前层的数字之间加上一定数量的空格
            for(int i=0; i<levelArr.size(); i++){
                if(levelArr.get(i)==null){
                    s.append(nullC);
                }else {
                    //打印的树中的每个节点占3个位置,当数字大于三位数时,显示会移位
                    //对于负数,负号占一个位置,要用不同的格式
                    DecimalFormat dfP = new DecimalFormat("000");
                    DecimalFormat dfN = new DecimalFormat("00");
                    if(levelArr.get(i)>=0){
                        s.append(dfP.format(levelArr.get(i)));
                    }else {
                        s.append(dfN.format(levelArr.get(i)));
                    }
                }
                //本层两个节点之间的空格数 = 以本层节点为根的满二叉树节点数量
                if(j>0 && i<levelArr.size()-1){
                    int n = (int)Math.pow(2,h)-1;
                    StringBuilder inserS = new StringBuilder();
                    for(int k=0;k<n;k++){
                        inserS.append(space);
                    }
                    s.append(inserS);
                }
            }
            res.add(s);
            h--;
        }

        //在树的某一层左右两边加空格
        //空格数(左/右) = (最底层字符数-当前层字符数)/2
        int len = res.get(res.size()-1).length();
        for(int i=0; i<arr.size()-1;i++){
            StringBuilder temp = new StringBuilder();
            for(int j=0; j<(len-res.get(i).length())/2;j++){
//                System.out.println(arr.get(i).size());
                temp.append(' ');
            }
            res.get(i).insert(0,temp.toString());
            res.get(i).append(temp.toString());
        }
        //在左右两侧加上 level 和 节点数
        for(int i=0; i<arr.size();i++){
            res.get(i).insert(0,"level-"+i+":  ");
            res.get(i).append("  nodes=").append((int)Math.pow(2, i));
        }

        System.out.println("【The Binary Tree is】:");
        for(StringBuilder levelArr: res){
            System.out.println(levelArr.toString());
        }
    }

    /**
     * 根据数组中节点打印一个图形化的二叉树
     * @param arr 一个整型数组,按照完全二叉树的规则存储,空节点用null
     */
    public void printGraphBT(Integer [] arr){
        TreeNode root = buildBTbyArray(arr);
        printGraphBT(root);
    }
}

代码测试

这里直接测试从数组打印二叉树 printGraphBT (Integer [] arr) 函数以及打印二叉树节点数组函数binaryTree2Array(TreeNode root),基本就测完了这里面的所有功能。

public class TestTreeUtil {
    public static void main(String[]args){
        Integer[] arr = {10,5,-3,3,2,null,11,3,-2,null,1};
        TreeProcession process = new TreeProcession();
        System.out.println(process.binaryTree2Array(process.buildBTbyArray(arr)));
        process.printGraphBT(arr);
    }
}

测试结果

打印二叉树_第1张图片

你可能感兴趣的:(java,算法,数据结构)