简体   繁体   English

Python代码中的奇怪行为

[英]Strange behavior in Python code

I am trying to write a simple method to link the nodes of a tree together in this way: 我试图写一个简单的方法以这种方式将树的节点链接在一起:

  • Every leaf is linked to the previous and the next leaf in the tree 每个叶子都链接到树中的上一个叶子和下一个叶子
  • Every non-leaf is linked to the previous and the next leaf in the tree 每个非叶子都链接到树中的上一个叶子和下一个叶子

For example, if we have this tree: 例如,如果我们有这棵树:

    A
  / |  \
 B  C    D
   / \  / \
  E  F  G  H
        |
        I

This should be the result of the method: 这应该是该方法的结果:

  • B.nextToken = E B.nextToken = E.
  • C.prevToken = B C.prevToken = B.
  • E.nextToken = F E.nextToken = F.
  • E.prevToken = B E.prevToken = B.
  • F.nextToken = I F.nextToken =我
  • C.nextToken = I C.nextToken =我
  • H.prevToken = I H.prevToken =我

Here is the method code: 这是方法代码:

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

For some strange reason, the non-leaves aren't linked to the next leaves, for example: 由于一些奇怪的原因,非叶子没有链接到下一个叶子,例如:

  • C.nextToken = None C.nextToken =无

Although 虽然

  • F.nextToken = I F.nextToken =我

I wonder why is that happening? 我想知道为什么会这样? The last lines at the end of the recursive function should grantee that a parent will have the same next as its last child! 递归函数末尾的最后几行应该授予父级将与其最后一个子级相同的下一行!

The problem is, when you visit C, you traverse only it's children E & F. 问题是,当你访问C时,你只会遍历它的孩子E&F。

"I" hasn't been visited yet, so C.children[-1].nextToken == None because only visiting "I" will set F.nextToken “我”尚未访问过,所以C.children[-1].nextToken == None因为只访问“我”会设置F.nextToken

Solution: you'll have to do a run on all leaves first, then a second run on the internal nodes. 解决方案:您必须首先在所有叶子上运行,然后在内部节点上运行第二次运行。

For example: 例如:

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]

Also note the change for the prevToken / nextToken of internal nodes. 另请注意内部节点的prevToken / nextToken的更改。 This is needed if you want them to link to the actual first/last leaf. 如果您希望它们链接到实际的第一个/最后一个叶子,则需要这样做。

Alternatively, use generators an an instance-checking loop 或者,使用生成器和实例检查循环

The generator yields the node as the base case if the node has no children, else another generator to travel down the tree. 如果节点没有子节点,则生成器将节点作为基本情况,否则另一个生成器沿树向下传播。 Caveat here is that node.children is ordered from left to right. 这里要注意的是node.children是从左到右排序的。

def leafs(node):
    if len(node.children) == 0:
        yield node
    else:
        for child in node.children:
            yield leafs(child)

...and a loop with stack of generators... This got uglier as I wrote it - I think you could clean it up a bit and get rid of the while True... ......还有一堆带有发电机的循环...当我写这篇文章时它变得更加丑陋 - 我想你可以把它清理一下然后摆脱它真的......

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM