• 二叉树的树状打印(Java)


    原理部分

    实现效果如下:

    在这里插入图片描述

      在控制台打印时,是从上往下一行一行打印的;上面的效果图是将二叉树一层的节点在同一行中打印,因此在遍历时应该层序遍历:将同一层的节点按顺序遍历打印,再继续遍历下一层的节点;

      在打印同一层的节点时,要计算好每个节点之间的间隔距离,同一层节点之间的间隔可以看节点之间的横坐标之差;要计算出横坐标之差,就要得到每一个节点的横坐标;

      如果按照: XA —> XG 的顺序将节点存储到数组中,那么每个节点对应的数组下标可以看作是节点的横坐标;在二叉树中,中序遍历的结果恰好是这个顺序;

      在打印完节点之后,还要打印链接子节点的线段;同一层节点之间有多个节点,因此会有多条链接子节点的线段;而这些线段也在同一层中,因此也要将这些线段拼接在一行中一起打印;

    在这里插入图片描述
      每一条链接子节点线段的长度如何确定呢?也很简单,子节点的坐标与当前节点坐标 之差就是线段的长度;因为节点可能会缺失左节点或者右节点,因此要分别计算链接左右子节点的线段长度;

      多条线段之间的间隔也要计算出来,这个就比较简单了两条线段之间的间隔: distance = leftIndex - lastRightIndex;

    在这里插入图片描述

      以上图为例,如果节点1没有right节点,那么lastRightIndex = 节点1的坐标;如果节点5没有left节点,那么leftIndex = 节点5的坐标 ;

    同一层节点要打印的部分:
    在这里插入图片描述

    • 第一部分是数据节点上的竖线;
    • 第二部分是,数据打印
    • 第三部分是连接线;

    代码

    • 中序遍历,找到每个节点的坐标;
        List<Node> mid = new ArrayList<>();
        void midOrder(Node node){
            if(node == null)return;
            midOrder(node.left);
            mid.add(node);
            midOrder(node.right);
        }
        //将node ,index  ====> 存入map中
        
        Map<Node,Integer> map =new HashMap<>();
        void init(){
            if(root == null)return;
            midOrder(root);
            for (int i = 0; i < mid.size(); i++) {
                map.put(mid.get(i),i);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 层序遍历打印
    
        void treePrint(List<Node> nodes){
            if(nodes.isEmpty())return;
           // nodes : 同一层节点
            printLevel(nodes);//打印同一层的节点
            List<Node> children =  new ArrayList<>();
            //顺序遍历下一层节点;
            for (Node node : nodes) {
                if(node.left != null)children.add(node.left);
                if(node.right != null) children.add(node.right);
            }
            treePrint(children);//递归打印下一层节点
         }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 打印同一层节点
        void printLevel(List<Node> nodes){
            String VLine = "";
            String dataLine = "";
            String line = "";
            int lastNodeIndex = 0;
            int lastRightIndex = 0;
            for (Node node : nodes) {
                int x =  map.get(node);
                String addEmpty = getEmpty(x-lastNodeIndex);
                lastNodeIndex = x;
                VLine    += addEmpty+"|";//竖线拼接
                //数字拼接
                dataLine += addEmpty+node.data;
                //红黑树可以用下面打印语句,打印红色;
                //if(node.red)
                //    dataLine+= addEmpty +"\033[91;1m"+node.data+"\033[0m";//打印红色
                //else
                //    dataLine += addEmpty+node.data;
    //======================组装,左右连接线=======================================
                Node left  = node.left;
                Node right = node.right;
                String leftLine  = null;
                String rightLine = null;
                int leftIndex  = -1;
                int rightIndex = -1;
                if(left  != null){
                    leftIndex = map.get(left);
                    leftLine = getLineToSon(x - leftIndex);
                }
                if(right != null){
                    rightIndex = map.get(right);
                    rightLine = getLineToSon(rightIndex - x);
                }
                String curLine  = (leftLine == null ? "" :leftLine)  + "|"+(rightLine == null ? "" : rightLine);
                if(leftLine == null && rightLine == null)curLine="";
                //线段之间的间隔
                int dif = (leftIndex == -1 ? x : leftIndex) - lastRightIndex;
                String difEmpty = getEmpty(dif);
                line += difEmpty + curLine;//拼接线段
                lastRightIndex = rightIndex == -1 ? x : rightIndex;
            }
            System.out.println(VLine +"\n" + dataLine +"\n" + line);
        }
    
        String  getEmpty(int x){
            String empty ="";
            for (int i = 0; i < x; i++) {
                empty+="\t";
            }
            return empty;
        }
    
    
    	//链接子线段的长度
        String getLineToSon(int end){
            String line = "";
            if(end ==0)return line;
            for (int i = 0; i < end; i++) {
                 line+="____";
            }
            return line;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 打印测试
         public void treePrint(){
            init();
            List<Node> nodes =  new ArrayList<>();
            nodes.add(root);
            treePrint(nodes);
         }
         
        @Test
        public void test(){
            for (int i = 0; i < 20; i++) {
                addVal(i);
            }  
            System.out.println("\n++++++++++++++++TreePrint test+++++++++++++++");
            treePrint();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 结果

    在这里插入图片描述

    红黑树和打印测试代码:Gitee

  • 相关阅读:
    VSCode搭建ESP32 ESP-IDF开发环境-Windows
    Spring IoC 和 AOP
    解锁学习电路设计的正确姿势!
    LeetCode: 1395. 统计作战单位数
    使用curl.exe执行http get指令
    PyQt学习笔记-使用QSettings保存系统配置参数
    引领新一轮IT服务升级,IT相关场景RPA应用
    Vue3+Vite+ElementPlus管理系统常见问题
    零零信安:暗网分析报告——Part 5 他们自称无政府主义者
    RabbitMQ快速入门笔记(详细)
  • 原文地址:https://blog.csdn.net/m0_37550986/article/details/126013196