博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【树结构2】树打印
阅读量:7005 次
发布时间:2019-06-27

本文共 5337 字,大约阅读时间需要 17 分钟。

载一棵小树苗,精心培育,总有一天会长成参天大树
                比如查找二叉、AVL、B + *、红黑……

但是,今天不种树,改成画树……

事情时这样的:在搞懂简单二叉树的过程中,经常需要验证自己的代码有没有问题,我之前的做法是“断点+肉眼观察”大法。随着节点的增多,断点还好,肉眼越来越扛不住,遂决定把树打印出来。把树的各种操作(新增/删除节点)前后进行比对,是非一目了然!

思路

clipboard.png

对于上面的树,我们已经可以从根节点遍历它了。(如果对树的基本操作还不清楚的话,可参看)

直接给出遍历方式:

public void treeIterator(TwoForkTree tree){    if(tree==null){        return ;    }    treeIterator(tree.leftNode);    System.out.print(tree.getId()+"\t");   //打印节点,这个位置是“中序遍历”    treeIterator(tree.rightNode);}

既然我们已经可以遍历它,那有没有方式可以记录下当前节点在第几层呢?也就是,第一层:32;第二层:20、40;第三层:35、41;第四层:38。如果可以做到,我们再按层级,一层一层的输出,不就把树打印出来了嘛!

怎么记录当前层级呢?对遍历方法稍加变动即可

public void record(TwoForkTree tree,int index){    if(tree==null){        return ;    }    index++;    record(tree.leftNode,index);    System.out.println(index+":"+tree.getId()+"\t");    record(tree.rightNode,index);}

执行结果:

clipboard.png

代码实现

接下来的事情简单了,我们把上述控制台输出的内容,用Map保存下来,再逐行输出即可。

//按层级存储节点的值@GetterMap
> layerTree = new HashMap<>();public void record(TwoForkTree tree,int index){ if(tree==null){ return ; } index++; record(tree.leftNode,index); List
layerData = layerTree.get(index); if(CollectionUtils.isEmpty(layerData)){ layerData = new LinkedList<>(); layerTree.put(index,layerData); } layerData.add(tree.id); record(tree.rightNode,index);}

测试以及逐行输出即可:

@Testpublic void testRecord(){    tree.record(tree,0);    SimpleNode simpleNode = (SimpleNode) tree;    Map
> layerTree = simpleNode.layerTree; int layerIndex=0; while (layerIndex
layerData = layerTree.get(layerIndex); for (Integer data:layerData){ System.out.print(data+"\t"); } System.out.println(); }}

执行结果:

clipboard.png

改进

网上的资料大部分到这里就结束了,但看看这个产物,虽然是把树按层级打印出来了,但很多部分还需要你脑补才行。留白太大,对艺术作品还好,但学习研究还是尽可能精准的好。我想要的是,带着枝杈的树!

# 目标   32  /  \20    40     /  \    35   41     \      38

怎么实现呢?遍历节点过程中,像Map中存储节点的时候,我们完全可以知道,它的子节点情况——如果有左子节点,记录一个/;如果有右子节点,记录一个\。由此,我们可以封装一个Bean。

class Printer{    private Integer id;    private int index;    private String leftChildLink;    private String rightChildLink;}

对代码进行调整后,效果变成这样:

clipboard.png

虽然还要进行脑补,但似乎容易了些?当然,这不是结束,其实距离目标效果就差最后一步了。我们需要对数值和子节点连接符(“/”、“\”)分别存储,输出时根据上一层的位置做调整!

给出完整实现:

/** * 树打印 */public void printTree(){    Map
> printMap = printTree(this,0); int layerIndex = 1; StringBuilder idBu = new StringBuilder(); StringBuilder linkBu = new StringBuilder(); LinkedList
nextLineIdPositions = new LinkedList<>(); while (layerIndex<=layerTreeMap.size()){ List
printers = printMap.get(layerIndex); int lastIdLen = 0; int lastIdPosition = 0; for(Printer printer:printers){ int position; if(CollectionUtils.isEmpty(nextLineIdPositions)){ position = 20; }else { position = nextLineIdPositions.removeFirst()-idLen(printer.getId())/2; if(position<=lastIdPosition+lastIdLen){ position+=idLen(printer.getId())/2; } } lastIdPosition = position; lastIdLen = idLen(printer.getId()); appendAt(idBu,position,printer.getId()+"`"); if(!Strings.isNullOrEmpty(printer.getLeftChildLink()) || !Strings.isNullOrEmpty(printer.getRightChildLink())){ int linkPosition = idBu.length()-idLen(printer.getId()); if(!Strings.isNullOrEmpty(printer.getLeftChildLink())){ appendAt(linkBu,linkPosition-idLen(printer.getId())/2,printer.getLeftChildLink()); nextLineIdPositions.add(linkPosition-idLen(printer.getId())/2); } if(!Strings.isNullOrEmpty(printer.getRightChildLink())){// if(Strings.isNullOrEmpty(printer.getLeftChildLink())){// linkPosition+=2;// } appendAt(linkBu,linkPosition+idLen(printer.getId()),printer.getRightChildLink()); nextLineIdPositions.add(linkPosition+idLen(printer.getId())+1); } } } System.out.println(idBu.toString()); System.out.println(linkBu.toString()); idBu.setLength(0); linkBu.setLength(0); layerIndex++; } // 数据还原 layerTreeMap.clear();}private int idLen(Integer id){ return (id+"").length();}private StringBuilder appendAt(StringBuilder bu,int position,String param){ while (bu.length()
> layerTreeMap = new HashMap<>();private Map
> printTree(TwoForkTree node,int index){ if(node==null){ return null; } index++; List tempList = layerTreeMap.get(index); if(CollectionUtils.isEmpty(tempList)){ tempList = new LinkedList(); layerTreeMap.put(index,tempList); } Printer printer = new Printer(); tempList.add(printer); printer.setId(node.getId()); printer.setIndex(index); if(node.leftNode!=null){ printer.setLeftChildLink("/"); } if(node.rightNode!=null){ printer.setRightChildLink("\\"); } printTree(node.leftNode,index); printTree(node.rightNode,index); return layerTreeMap;}@Setter@Getterpublic class Printer{ private Integer id; private int index; private String leftChildLink; private String rightChildLink;}

最终效果:

clipboard.png

注:之所以加了分割符( ' 32` '后面的符号),是因为打印方法还略有不足——有时两个节点会连在一起,没办法看出具体的节点值。分割符的存在算是投机取巧。

转载地址:http://isytl.baihongyu.com/

你可能感兴趣的文章
windows下配置nginx+php环境
查看>>
[工具配置]使用requirejs模块化开发多页面一个入口js的使用方式
查看>>
Jenkins具体安装与构建部署使用教程
查看>>
【ES】学习9-聚合2
查看>>
Mindjet MindManager 思维导图软件-使用思维导图跟踪调用流程,绘制软件框架
查看>>
SQLServer判断指定列的默认值是否存在,并修改默认值
查看>>
贝塞尔曲线与CSS3动画、SVG和canvas的应用
查看>>
将NSTimer加入至RunLoop中的两种方法差别
查看>>
[ajax 学习笔记] ajax初试
查看>>
css中合理的使用nth-child实现布局
查看>>
每天一个JavaScript实例-操作元素定位元素
查看>>
架构-到底什么时候该使用MQ【转】
查看>>
split-brain 脑裂问题(Keepalived)
查看>>
清空,再来
查看>>
7.JAVA编程思想笔记隐藏实施过程
查看>>
CentOS7 以下安装Mysql MMM
查看>>
windows系统里Cygwin中如何正确安装wget(图文详解)
查看>>
让你快速了解并掌握如何进行iOS开发技能
查看>>
html绘制三角形(兼容IE6)
查看>>
Maven安装好后包下载的测试命令和配置变量的查看命令:mvn help:system
查看>>