我正在尝试编写一种简单的方法,以这种方式将树的节点链接在一起:
例如,如果我们有这棵树:
A
/ | \
B C D
/ \ / \
E F G H
|
I
这应该是该方法的结果:
以下是方法代码:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinking(c)
tree.prevToken = tree.children[0].prevToken
tree.nextToken = tree.children[-1].nextToken
由于某些奇怪的原因,非叶子没有链接到下一个叶子,例如:
虽然
我想知道为什么会这样?递归函数末尾的最后一行应该授予父项与下一个子项相同的下一行!
答案 0 :(得分:1)
问题是,当你访问C时,你只会遍历它的孩子E& F。
“我”尚未访问过,C.children[-1].nextToken == None
因为只访问“我”会设置F.nextToken
解决方案:您必须首先在所有叶子上运行,然后在内部节点上运行第二次运行。
例如:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
depthFirstTraverseTokenLinkingPhase1(tree)
depthFirstTraverseTokenLinkingPhase2(tree)
def depthFirstTraverseTokenLinkingPhase1(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase1(c)
def depthFirstTraverseTokenLinkingPhase2(tree):
if len(tree.children) == 0:
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase2(c)
if tree.children[0].prevToken is not None:
tree.prevToken = tree.children[0].prevToken
else:
tree.prevToken = tree.children[0]
if tree.children[-1].nextToken is not None:
tree.nextToken = tree.children[-1].nextToken
else:
tree.nextToken = tree.children[-1]
另请注意内部节点的prevToken
/ nextToken
的更改。如果您希望它们链接到实际的第一个/最后一个叶子,则需要这样做。
答案 1 :(得分:1)
或者,使用生成器和实例检查循环
如果节点没有子节点,则生成器将节点作为基本情况,否则另一个生成器沿树向下传播。这里需要注意的是node.children是从左到右排序的。
def leafs(node):
if len(node.children) == 0:
yield node
else:
for child in node.children:
yield leafs(child)
...还有一堆带有生成器的循环......当我写这篇文章的时候,它变得更加丑陋 - 我想你可以把它清理一下然后摆脱真正的......
current_node = leafs(a)
stack = []
last_node = None
while True:
if isinstance(current_node, types.GeneratorType):
stack.append(current_node)
current_node = current_node.next()
else:
if last_node and last_node != current_node:
last_node.nextToken = current_node
current_node.prevToken = last_node
last_node = current_node
try:
current_node = stack[-1].next()
except StopIteration:
stack.pop()
except IndexError:
break