我有一个任意的节点树结构。我想绘制这个树,为用户提供可视化表示。我需要在树上进行递归,并为每个节点添加一个图形项到列表,然后只需在树递归完成后绘制项列表。项目的递归和绘制当然是微不足道的 - 如何定位图形节点以使它们不与其他分支重叠,这有点复杂。
我正在使用Android,但这并不重要 - 我正在寻找一种方法,可能是一种算法,可以在树空间经过树时保持2D空间的图像,因此它只为每个节点分配最合适的坐标因为它通过了。
有什么想法吗?
更新
This is the article with the best and most complete algorithm.
答案 0 :(得分:4)
我建议按行绘制树。你可以通过使用某种移动的“绘图光标”来实现这一点。
您可以为每个节点存储属性width
,其计算方法如下:
width
为1 width
是所有孩子的width
的总和然后,你在中间绘制根“在第一行”,这意味着你只需要生根width
的一半。
然后,在图像上生成网格,使每个网格线对应一行resp。从左到右一步,网格线的每个交叉点都可以包含一个节点,每个节点都有足够的空间。
然后,您遍历子项并在迭代时,累积子项的width
并在下一行中绘制子项“。要绘制currentChild
,请将绘图光标currentWidth/2
向右移动,绘制currentChild
,然后将绘图光标移动到右侧的剩余currentWidth/2
。
为了使节点处于良好状态,您可以考虑进行广度优先搜索。
我希望我的解释清楚,但我认为如果我画一点照片会更好。
这是我们的树(x
是节点,其他所有边缘)
+-------x--+-------+
| | |
+-x-+ +-+x+-+ +-x-+
| | | | | | | | |
x x x x x x x x x
所以,你计算叶子的width
s:
+-------x--+-------+
| | |
+-x-+ +-+x+-+ +-x-+
| | | | | | | | |
1 1 1 1 1 1 1 1 1
然后,自下而上,将width
s作为儿童width
的总和:
+-------9--+-------+
| | |
+-2-+ +-+4+-+ +-3-+
| | | | | | | | |
1 1 1 1 1 1 1 1 1
所以,你从根(width
9)开始,然后在第一行中走4.5步。
然后,将“绘图光标”移动到第二行“第0列”(向左)。
第一个孩子有width
2,所以我们向右移动2/2=1
网格线并绘制节点并将绘图光标向右移动剩余的1个网格线以完成节点。因此,下一个节点有width
4,这意味着我们右转4/2 = 2个网格线,绘制,继续剩下的2个步骤,依此类推。
等下一行。最后(或中间步骤),连接节点。
此过程确保没有重叠的节点(如果网格线彼此相距足够远),但它可能会导致相当大的树形图可以更有效地利用空间。
为了检测未使用的空间,可以在上述过程之后扫描线,看看是否存在未使用的网格线交叉点,然后可能重新对齐某些节点以填充空间。
答案 1 :(得分:4)
我会尝试Walker算法。关于算法的Here's an academic paper。如果您想要查看代码,请查看NodeLinkTreeLayout中的Prefuse。 Prefuse是开源的,因此只要您遵守许可条款,就不会有任何问题使代码适应您的情况。
答案 2 :(得分:2)
看看Dot。您可以将树转换为点表示,然后以您喜欢的任何格式使用 Graphviz 可视化。例如, Doxygen 使用它来表示程序的结构。
答案 3 :(得分:2)
Graphviz和mfgraph功能强大,但它们适用于一般图形,对树木来说可能有点过分。
尝试在树+布局+算法上使用Google搜索或查看Graphic Javascript Tree with Layout。 后者是旧的,但它使用HTML canvas和javascript,它解释了代码,所以代码和方法都应该是可移植的。
答案 4 :(得分:0)
根据数据的性质,TreeMap可能比tinkertoy代表更合适。