首页 > 其他分享 >打印树形结构(可视化二叉树)

打印树形结构(可视化二叉树)

时间:2023-05-30 16:33:20浏览次数:32  
标签:Node info node int private 树形 可视化 二叉树 new

平时开发时,偶尔会操作二叉树,而查看二叉树的结构,是一种比较费时的事情,我们可以把它按照本身的结构打印出来,从而方便查看。

例如

        Node a = new Node(110);
        Node b = new Node(105);
        Node c = new Node(115);
        Node d = new Node(102);
        Node e = new Node(107);
        Node f = new Node(112);
        Node g = new Node(117);

        a.left = b;
        a.right = c;
        b.left = d;
        b.right = e;
        c.left = f;
        c.right = g;

当查看此树的数据结构,咱们一般会debug,一个一个节点的看,比较浪费时间。若是把它可视化的打印出来,一窥树的全貌,就能节省一些时间。

打印之后的树:

 代码如下:

import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author wzgl
 * @version 1.0
 * @date 2023/5/30 13:48
 */
public class PrintTree {

    /**
     * 打印二叉树
     *
     * @param info 树信息
     * @param <T>  树泛型
     * @return 树
     */
    public static <T> String printTree(PrintNodeInfo<T> info) {
        if (info == null) {
            return "";
        }
        T node = info.getNode();
        int deep = findDepth(node, info);
        if (deep > info.maxDepth) {
            throw new RuntimeException("太深了, 不好打印啊");
        }
        int size = (1 << deep) - 1;
        List<PrintNode>[] lists = new ArrayList[deep];
        for (int i = 0; i < deep; i++) {
            lists[i] = new ArrayList<>();
        }
        info.setLists(lists);
        addPrint(info, node, size >> 1, 0, deep);
        for (List<PrintNode> list : lists) {
            list.sort((a, b) -> Integer.compare(a.index, b.index));
        }
        StringBuilder all = new StringBuilder();
        for (List<PrintNode> list : lists) {
            StringBuilder sb = new StringBuilder();
            int pre = -1;
            for (PrintNode printNode : list) {
                int index = printNode.index;
                String value = printNode.value;
                int i = index - pre - 1;
                for (int j = 0; j < i; j++) {
                    sb.append(info.getWight());
                }
                pre = index;
                sb.append(value);
            }
            all.append(sb).append(info.line);
        }
        return all.toString();
    }

    /**
     * 前序 遍历,获取节点,并存储到lists中(按层存储,可以层序遍历实现)
     *
     * @param info  树信息
     * @param node  节点
     * @param index 当前元素的坐标为位置
     * @param item  当前深度
     * @param depth 深度
     * @param <T>   树泛型
     */
    private static <T> void addPrint(PrintNodeInfo<T> info, T node, int index, int item, int depth) {
        if (node == null) {
            return;
        }
        List<PrintNode>[] lists = info.getLists();
        List<PrintNode> list = lists[item];
        String s = info.valStr == null ? String.valueOf(info.val.apply(node)) : info.valStr.apply(node);
        PrintNode printNode = new PrintNode(index, s);
        list.add(printNode);
        int w = 1 << (depth - item - 2);
        addPrint(info, info.left.apply(node), index - w, item + 1, depth);
        addPrint(info, info.right.apply(node), index + w, item + 1, depth);
    }

    /**
     * 获取深度
     *
     * @param node 节点
     * @param info 树信息
     * @param <T>  树泛型
     * @return 深度
     */
    private static <T> int findDepth(T node, PrintNodeInfo<T> info) {
        if (node == null) {
            return 0;
        }
        return Math.max(findDepth(info.left.apply(node), info), findDepth(info.right.apply(node), info)) + 1;
    }

    /**
     * 打印的信息
     */
    @Data
    private static class PrintNode {
        // 所处的坐标
        private int index;
        // 打印的内容
        private String value;

        public PrintNode() {
        }

        private PrintNode(int index, String value) {
            this.index = index;
            this.value = value;
        }
    }

    /**
     * 存储一棵树的信息
     *
     * @param <T> 树节点的泛型
     */
    @Data
    public static class PrintNodeInfo<T> {

        // 跟节点
        private T node;

        // 获取当前值,默认为Integer类型,若是其他的类型,则需要修改
        private Function<T, Integer> val;

        // 获取左节点
        private Function<T, T> left;

        // 获取右节点
        private Function<T, T> right;

        // 层序遍历时,存储每一层的节点
        private List<PrintNode>[] lists;

        // 打印的值,若没有设置,则取val(自定义用)
        private Function<T, String> valStr;

        // 占位符,若节点为null,则需要空格占位(长度可以自定义)。
        private String wight = "     ";

        // 每一层拼接换行符,(可以自定义)
        private String line = "\n\n";

        // 若是树深大于此值,则抛出异常,防止打印的过大(默认8,可自定义)
        private int maxDepth = 8;

        public PrintNodeInfo() {
        }

        public PrintNodeInfo(T node, Function<T, Integer> val, Function<T, T> left, Function<T, T> right) {
            this.node = node;
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

}
PrintNodeInfo类是记录树的所有信息,此处使用lambda表达式实现的,便可以使所有的树形结构都可以使用。
使用方式:
import lombok.Data;

/**
 * @author wzgl
 * @version 1.0
 * @date 2023/5/30 16:05
 */
public class PrintTreeTest {

    public static void main(String[] args) {
        Node a = new Node(110);
        Node b = new Node(105);
        Node c = new Node(115);
        Node d = new Node(102);
        Node e = new Node(107);
        Node f = new Node(112);
        Node g = new Node(117);
        a.left = b;
        a.right = c;
        b.left = d;
        b.right = e;
        c.left = f;
        c.right = g;

        PrintTree.PrintNodeInfo<Node> info = new PrintTree.PrintNodeInfo<>(a, Node::getVal, Node::getLeft, Node::getRight);
        System.out.println(PrintTree.printTree(info));
    }

    @Data
    private static class Node {
        private int val;
        private Node left;
        private Node right;

        public Node(int val) {
            this.val = val;
        }
    }

}

 

需要注意的是,因为都是依靠占位符来调整打印数据格式,当使用了不合理的长度的占位符的时候,可能会出现格式错乱。因为只是为了调试用,所以能大体看出树形结构即可。

自定义某些参数

        PrintTree.PrintNodeInfo<Node> info = new PrintTree.PrintNodeInfo<>(a, Node::getVal, Node::getLeft, Node::getRight);
       // 占位符长度
        info.setPlaceHolder("     ");
        // 打印的内容
        info.setValStr(n -> "$" + n.val + "$");
        // 每一层结尾拼接
        info.setLine("\n\n-->");
        System.out.println(PrintTree.printTree(info));

 

标签:Node,info,node,int,private,树形,可视化,二叉树,new
From: https://www.cnblogs.com/wangzaiguli/p/17443635.html

相关文章

  • 3D轻量化引擎工具助力Canvas GFX开发插图新产品,可视化视图更精准!
    增材制造和3D打印不乏创新技术,无论是硬件变得更加高效和准确,还是材料科学的巨大进步,都拓宽了3D打印部件的使用范围。然而,Techsoft3D作为软件组件供应商,关注点更多的是在将这两个元素结合在一起的效果,即驱动现代打印机发展并支持使用先进材料的软件平台。凭借超过26年开发工程专......
  • 【爬虫+数据清洗+可视化】用Python分析“淄博烧烤“的评论数据
    目录一、背景介绍二、爬虫代码2.1展示爬取结果2.2爬虫代码讲解三、可视化代码3.1读取数据3.2数据清洗3.3可视化3.3.1IP属地分析-柱形图3.3.2评论时间分析-折线图3.3.3点赞数分布-箱线图3.3.4评论内容-情感分布饼图3.3.5评论内容-词云图四、技术总结五、演示视频六、完整......
  • 基于SQL的数据可视化和数据挖掘
           基于SQL的数据可视化和数据挖掘IT奋斗的青年2023-04-1221:34发表于山东我们的项目是一个在线教育平台,平台上有数百门课程,数千名学生在线学习。我们的目标是从数据中挖掘出有价值的信息,帮助平台做出更加科学和有效的运营决策。数据分析流程1.数据......
  • 界面组件Telerik UI for WPF可轻松实现直方图,让数据可视化更简单
    TelerikUIforWPF拥有超过100个控件来创建美观、高性能的桌面应用程序,同时还能快速构建企业级办公WPF应用程序。UIforWPF支持MVVM、触摸等,创建的应用程序可靠且结构良好,非常容易维护,其直观的API将无缝地集成VisualStudio工具箱中。TelerikUIforWPF|下载试用TelerikUI......
  • 代码随想录算法训练营第21天 | ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中
     第六章 二叉树part07今日内容    详细布置   530.二叉搜索树的最小绝对差  需要领悟一下二叉树遍历上双指针操作,优先掌握递归 题目链接/文章讲解:视频讲解:  501.二叉搜索树中的众数  和 530差不多双指针思路,不过 这里涉及到一个很巧妙的代码......
  • 代码随想录算法训练营第15天 | ● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉
     第六章二叉树 part02 今日内容:  ●  层序遍历  10 ●  226.翻转二叉树 ●  101.对称二叉树 2    详细布置   层序遍历  看完本篇可以一口气刷十道题,试一试, 层序遍历并不难,大家可以很快刷了十道题。 题目链接/文章讲解/视频讲解:htt......
  • 代码随想录算法训练营第16天 | ● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111
     第六章二叉树part03 今日内容:  ●  104.二叉树的最大深度  559.n叉树的最大深度●  111.二叉树的最小深度●  222.完全二叉树的节点个数 迭代法,大家可以直接过,二刷有精力的时候 再去掌握迭代法。  详细布置   104.二叉树的最大深度 (优先掌......
  • 代码随想录算法训练营第17天 | ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404
     第六章二叉树part04 今日内容:  ●  110.平衡二叉树 ●  257. 二叉树的所有路径 ●  404.左叶子之和   详细布置  迭代法,大家可以直接过,二刷有精力的时候 再去掌握迭代法。  110.平衡二叉树 (优先掌握递归) 再一次涉及到,什么是高度,什么是......
  • LeetCode 617. 合并二叉树
    题目链接:LeetCode617.合并二叉树题意:给你两棵二叉树:root1和root2。想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新......
  • 代码随想录算法训练营第二十天|654. 最大二叉树、617. 合并二叉树、700. 二叉搜索树
    【参考链接】654.最大二叉树【注意】1.构造二叉树,都需要用前序遍历。2.二叉树的根是数组中的最大元素。3.没必要构造新数组,通过下标控制左右区间。运行效率会高很多。【代码】1#Definitionforabinarytreenode.2#classTreeNode(object):3#def__init......