【问题标题】:Breadth First Search does not return the correct ordering for nodes广度优先搜索未返回节点的正确排序
【发布时间】:2020-07-13 10:13:58
【问题描述】:

我已经实现了一个看起来像这样的树:

               1

    2          3          4

 5     6               7      8

我想以广度打印。这是我的代码:

class Node:
    def __init__(self):
        self.data = None
        self.children = []


class Tree:
    def __init__(self):
        self.root = Node()

    def build(self):
        self.root.data = 1
        self.root.children.append(Node())
        self.root.children.append(Node())
        self.root.children.append(Node())
        self.root.children[0].data = 2
        self.root.children[1].data = 3
        self.root.children[2].data = 4

        self.root.children[0].children.append(Node())
        self.root.children[0].children.append(Node())

        self.root.children[2].children.append(Node())
        self.root.children[2].children.append(Node())

        self.root.children[0].children[0].data = 5
        self.root.children[0].children[1].data = 6

        self.root.children[2].children[0].data = 7
        self.root.children[2].children[1].data = 8
        return


    def traverseBF(self, node):
        li = []
        trav = []
        li.append(node)
        while len(li) != 0:
            for x in li:
                trav.append(x.data)
                for z in x.children:
                    li.append(z)
                # map(lambda z: li.append(z), x.children)
                li.remove(x)
        print(trav)



t = Tree()
t.build()
t.traverseBF(t.root)

输出为:[1, 3, 2, 5, 4, 7, 6, 8]

我的问题是:

  1. 为什么 3 在 2 之前被插入到 trav[] 中,即使在 root.children 中的顺序是 [2,3,4]
  2. 为什么注释掉的 map 函数给出的结果与上面的 for 循环不同?

【问题讨论】:

  • 在循环中使用 append 或使用带有副作用的 map 都是扩展列表的非常不合 Python 的方式。请改用list.extend() 方法。

标签: python list tree traversal


【解决方案1】:

问题在于您如何管理队列。使用单个while 循环来检查列表的长度。在此期间,弹出第一个节点,然后使用弹出节点的子节点扩展队列。您的函数应如下所示:

def traverseBF(self, node):
    li = []
    trav = []
    li.append(node)
    while len(li) != 0:
        x = li.pop(0)          # pop the first item
        li.extend(x.children)  # extend the queue with children
        trav.append(x.data)
    print(trav)

有了这个,t.traverseBF(t.root) 打印出[1, 2, 3, 4, 5, 6, 7, 8]


这是您的代码的“更简洁”版本。我喜欢生成器,所以我把它变成了一个生成器,它按 BFS 的顺序一个接一个地返回节点值:

def bfs(node):
    q = [node]
    while q:
        n = q.pop(0)
        q.extend(n.children)
        yield n.data

[*bfs(t.root)]
# [1, 2, 3, 4, 5, 6, 7, 8]

【讨论】:

  • 为什么 while 循环没有在 x = li.pop(0) 处退出?由于根是第一次迭代中的唯一节点,因此 len(li) 在弹出后变为 0。
  • @TyrangeDenhops 在进入循环之前第一次检查循环条件(它通过,因为队列的长度为 1)。下一次再次检查循环条件是在上一次迭代的最后一条语句运行之后(即扩展队列的行 - 因为它的长度为 3,所以它通过了),所以你的假设是不正确的。
  • 哦。天哪,我很尴尬,我不知道自己是 CSE 学生。我曾经认为一旦条件成立,循环就会退出。但以防万一,如果有一天我想要那样做,我该怎么办?检查每一行的条件?
  • 顺便说一句,我接受你的第一个答案。谢谢。第二个超出了我的范围,因为我还没有学习生成器。如果我学习了这些高级概念,您认为会有帮助吗?您多久使用一次?
  • @TyrangeDenhops 如果你正在写类似的东西,你可能做错了。不要出汗。慢慢来,按照老师为您设定的步伐。最终,当您学会使用这种语法时,它就会变得自然。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多