Jus*_* L. 8 ruby language-agnostic algorithm text binary-tree
它是一个非常普通的二叉树,除了其中一个节点可能为空的事实.
我想找到一种以水平方式输出它的方法(也就是说,根节点在左侧并向右扩展).
我有一些垂直扩展树木的经验(根节点在顶部,向下扩展),但在这种情况下,我不知道从哪里开始.
最好是遵循以下几条规则:
例如,这是一个有效的树,有六个端节点(节点由一个名称及其深度表示):编辑:请参阅问题的底部以获得替代,更容易渲染
[a0]-----------[b3]------[c5]------[d8] \ \ \----------[e9] \ \----[f5] \-[g1]--------[h4]------[i6] \ \--------------------[j10] \-[k3]
它代表垂直的显式二叉树:
0 a / \ 1 g * / \ \ 2 * * * / \ \ 3 k * b / / \ 4 h * * / \ \ \ 5 * * f c / \ / \ 6 * i * * / / \ 7 * * * / / \ 8 * * d / / 9 * e / 10 j
(为了紧凑而折叠的分支; *
代表冗余的,一个子节点;请注意,*
这是实际的节点,每个节点存储一个子节点,为了表示,这里省略了名称)
(另外,为了澄清,我想生成第一个水平树;而不是这个垂直树)
我说语言不可知因为我只是在寻找算法; 我说ruby是因为我最终还是要在ruby中实现它.
假设每个Node
数据结构仅存储其id,左节点和右节点.
主Tree
类保留所有节点的轨道,并具有足够的算法来查找:
我已经知道了:
任何人都有我可以从哪里开始的想法?我应该采用递归方法吗?迭代?一些Psuedo代码也会很酷,非常感谢=)
进展
根据walkytalky的建议,我决定看看将每个"相关"或重要节点映射到网格的样子,其中列是深度,行可以通过端节点识别.以下是发生的情况(跳过第7列,因为深度7中没有重要节点):
depth: 0 1 2 3 4 5 6 8 9 10 a b c d e f g h i j k
使用广度优先或深度优先搜索生成此网格应该很容易.也许最简单的是通过简单地保持2D数组并将每个重要节点放入其中,为每个"第二个孩子"插入一行.
现在,了解这些事实:
我们可以看到,给定任何有效网格,有一种明确的方法可以"连接点",可以这么说; 有一个明确的树被代表.
现在,"连接点"不再是二元树结构问题......它只是一个装饰问题.我们只需要构建一个算法来正确放置权利-
和\
它们可以去的地方,也许只遵循简单的网格/词典规则,而不是二叉树结构规则.
基本上,这意味着渲染树的问题现在是渲染网格的更简单的问题,具有奇特的装饰.
谁能建议任何制定这些规则的方法?或者可能完全不同的方法?
编辑
我已经设想了一个更容易,更简单的最终渲染:
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered) [a0 ]-------[b3 ]-------[c5 ]-------[d8 ] | | \---------------[e9 ] | \---------[f5 ] \---[g1 ]-------[h4 ]-------[i6 ] | \---------------------------[j10] \---[k3 ] --d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered)
尝试创建这个可能更容易,而不是我之前发布的那个.首先,它保留了一个漂亮的网格形状,你不必用对角线变幻无常.这些行都沿着清晰可见的列线映射.不幸的是,它远没有第一个那么漂亮.
如果有N
结束节点,则必须有N-1
具有 2 个子节点的内部节点。(可以有任意数量的具有 1 个子节点的内部节点,我们必须对其进行计数才能获得深度,但否则会忽略。)因此,生成树相当于将这些节点放置在网格上,其中:
N
1+floor(log2(N))
和 之间2*N-1
, depending on how much overlap there is; this probably doesn't matter much for our purposes, though那么,让我们看看:
将每个内部节点向下到其左子节点上方的行的空单元标记为垂直分支,并将左子节点所在级别的单元标记为结点。
使用适当的 ASCII 装饰进行打印。
更新:
正如你所说,定位足以明确地确定连接,但你仍然需要做一些自下而上的工作才能做到这一点,所以我可能仍然会在网格构建过程中执行“标记”步骤。
我有点认为印刷是微不足道的,足以掩盖,但是:
size of fixed elements + max label length + floor(log10(depth) + 1)
。(例如,固定元素可能是[
和。我们可以替换]-
]\n
as the suffix for endpoints.)如果您首先生成直接版本,然后在字符数组中进行一些替换,则将其转换为打印对角线可能是最简单的 - 否则您可能会遇到在与它所在的列不同的列中渲染长垂直分支的情况起源。
在某些时候,我可能会尝试将其放入代码中,但今天可能不会——这是要做的事情!