我想找到一种水平输出它的方法(即,根节点在左侧并向右扩展)。
我有一些将树垂直展开的经验(根节点在顶部,向下展开),但是在这种情况下,我不知道从哪里开始。
最好遵循以下几个规则:
- 如果一个节点只有一个子节点,则可以跳过它作为冗余节点(没有子节点的“端节点”始终显示) - 所有相同深度的节点必须垂直对齐;所有节点必须位于所有较浅节点的右侧和所有更深节点的左侧。 - 节点具有包括其深度在内的字符串表示形式。 - 每个“端节点”都有自己独特的行;也就是说,行数是树中端节点的数量,并且当端节点在行上时,在该端节点之后可能没有其他内容。 - 由于最后一个规则,根节点可能最好位于左上角或左下角;首选左上角。
例如,这是一个有效的树,有六个端节点(节点由名称及其深度表示):EDIT:请参见问题底部的替代、更简单的渲染
(分支折叠以节省空间;*表示冗余的单一子节点;请注意,*是实际节点,每个节点仅存储一个子节点,但在此处为了演示而省略名称)
(另外,为了澄清,我想生成第一个水平树;而不是这棵垂直树)
我说语言无关,因为我只是在寻找算法;我说ruby,因为最终我还必须在ruby中实现它。
假设每个“Node”数据结构仅存储其id、左节点和右节点。
一个主要的
Tree
类跟踪所有节点,并具有足够的算法来查找:
- 一个节点的第n个祖先
- 一个节点的第n个后代
- 一个节点的所有末端子孙,以及它们的数量
- 一个节点的一代
- 两个给定节点的最近公共祖先
我已经知道:
- 末端节点的数量
有人有任何想法从哪里开始吗?我应该采用递归方法还是迭代方法?伪代码也很酷,非常感谢 =)
进展
根据walkytalky的建议,我决定看看将每个“相关”或重要节点映射到网格上会是什么样子,其中列是深度,行可通过其末端节点进行标识。以下是发生的情况(跳过第7列,因为在第7层没有重要节点):
深度:0 1 2 3 4 5 6 8 9 10 a b c d e f g h i j k
生成此网格应该很容易,可以使用广度优先或深度优先搜索。可能最简单的方法是仅保留2D数组,并将找到的每个重要节点放入其中,在每个“第二个子项”处插入一行。
现在,知道以下事实:
- 一行中的最后一个节点必须是末端节点
- 子节点始终位于其父节点的右侧,并且在同一行或更低的行上。
- 所有非末端节点必须恰好有两个子节点
- 因此,所有非末端节点的子节点都在其列的右侧的第一个位置,第一个子节点在同一行上,第二个子节点在下面n行,其中n是右侧的节点数。
我们可以看到,对于任何有效的网格,都有一种明确的方式来“连接点”,即表示一个明确的树。
现在,“连接点”不再是二叉树结构问题...它只是一个装饰问题。我们只需要构建一种算法,以正确地放置适当的-
和\
,这些符号可以遵循简单的网格/词典规则,而不是二叉树结构规则。
基本上,这意味着渲染树的问题现在是更简单的问题:渲染网格,带有花哨的装饰。
有人能建议任何制定这些规则的方法吗?或者也许完全不同的方法?
编辑
我构思了一个更加简单的最终渲染方案:
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => 指南线(不渲染)
[a0 ]-------[b3 ]-------[c5 ]-------[d8 ] | | \---------------[e9 ] | \---------[f5 ] \---[g1 ]-------[h4 ]-------[i6 ] | \---------------------------[j10] \---[k3 ]
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => 指南线(不渲染)
相比之前发布的方案,这个方案更容易实现。首先,它保留了漂亮的网格形状,并且您不必担心对角线。所有行都沿着清晰可见的列线映射。不幸的是,它远没有第一个方案那么漂亮。