因为工作需要,重新回顾了一年前写的代码,看的时候一点印象也没,老了。。。
树,除了根节点外,所有节点只有一个父节点,称为树。
树,怎样才能称之为好看,拿张草稿纸画了画,得出下述结论:
- 按层分隔,层间距一致
- 节点连线不重合,即要求同一层中,节点按父节点的顺序摆放。同一层中,节点间距最好满足 1*gap、2*gap、3*gap.....
- 父节点的坐标在子节点的中间位置(x轴方向上),对称。
分析及实现
对于第一点
其实很容易,从根节点开始,层次遍历树,当层数变化时,对y轴坐标++,上图即效果。
代码实现方面,不同于一般意义上的层次遍历实现,使用队列或递归实现,其实都会对层数变化无感知,因此,tmpList存放当前层的节点,设置y轴坐标,secondList存放下一层节点,为下次循环做准备。
tmpList.add(rootNode);
int y=0;
while (!tmpList.isEmpty()) {
for (NodeTree tmp : tmpList) {
secondList.addAll(tmp.getChildren());//保存下一层的所有节点
tmp.setY(y);//设置层
}
y++;
tmpList.clear();
tmpList.addAll(secondList);//用于下次循环
secondList.clear();
}
复制代码
对于第二点
简单做的话,其实每次循环设置x为0,child.setX(x++);即可,但效果如下。
对于第三点
首先讲一下,在一种特殊情况下,是如何确定x轴坐标的。 套用下满二叉树的概念,满树,除最后一层外,其它层节点都用子节点。
坐标设置思路
- 将第一点中每次循环的tmpList保存到List<List>中。
- 设置最后一层节点x轴坐标,从0开始,x++
- 倒数第二层的节点,坐标由子节点取平均得到,以此类推,设置完所有节点坐标。 效果如下:
AB距离=(A子树底层节点个数+B子树底层节点个数)/2
进而得出x轴坐标:
Ax=Bx+(A子树底层节点个数+B子树底层节点个数)/2,另外,每层的x从0开始。(未考虑坐标放大缩小)
“满树”坐标的计算方法得到了,那么普通树呢
普通树显然是不能使用子树底层节点个数的,普通树可以使用子树的叶子节点个数。 因为,普通树可以直线加节点,变成“满树”,而满树的底层节点个数=普通树的叶子节点个数,各自的子树也同理。
结论
设置y轴,层次遍历,y++; 设置x轴,X=前一个节点的X+(前一个节点的子树个数+当前节点的子树个数)/2
延申
- 其实效果也并不是很好,图中,第二层两侧节点向中间移动,树会更瘦一点,比较好,影响因素只考虑了当前子树的叶子节点,需要增加旁边子树的影响,但还不知道怎么加。
- 重看一年前的代码,原因在于,需要实现:一棵树部分节点已知,设置其他节点 的坐标 ,要求 已知节点坐标尽量不变、需要有格式化的效果、已知节点和未知节点需要平滑过渡。
不考虑时间复杂度的实现,一点点挪;考虑效率,则差不多就行