【问题标题】:How to return all leaves in a recursive tree如何返回递归树中的所有叶子
【发布时间】:2022-01-25 16:10:19
【问题描述】:

我正在尝试创建一个函数,该函数将返回递归树中的所有叶子。我看到了很多关于它的其他帖子,但我无法将其修改为我自己的代码。我正在尝试像决策树一样。这是我的代码:

class Node:
def __init__(self, data, positive_child=None, negative_child=None):
    self.data = data
    self.positive_child = positive_child
    self.negative_child = negative_child
    self.children_list = []

class Decision:
    def __init__(self, root: Node):
        self.root = root
        self.current = root

    def collect_leaves(self, node, leafs):
        if node is not None:
            if len(node.children_list) == 0:
                leafs.append(node.data)
            for n in node.children_list:
                self.collect_leaves(n, leafs)

    def return_all_leaves(self):
        leafs = []
        self.collect_leaves(self.root, leafs)
        return leafs

由于某种原因,它只返回根,而不是叶子..

例如:

flu_leaf2 = Node("influenza", None, None)
cold_leaf2 = Node("cold", None, None)
hard_leaf2 = Node("hard influenza", None, None)
headache_node2 = Node("headache", hard_leaf2, flu_leaf2)
inner_vertex2 = Node("fever", headache_node2, cold_leaf2)
healthy_leaf2 = Node("healthy", None, None)
root2 = Node("cough", inner_vertex2, healthy_leaf2)
diagnoser2 = Diagnoser(root2)

diagnoser2.return_all_leaves(self) 应该返回:

['hard influenza', 'influenza','cold','healthy']

【问题讨论】:

  • 首先要注意的是你收集的是节点而不是它的数据,这是你的意思吗? leafs.append(node) 而不是 leafs.append(node.data)
  • 嗯,这是真的,但在我改变这个之后,它只附加根而不是叶子(不,我的意思是 node.data)
  • 我想我们需要看看_collect_leaf_nodes
  • 收集树叶is_collect_leaf_nodes,我只是更改了函数的名称。再次,编辑。很抱歉造成误解。
  • 你在children_list 中放了什么东西?

标签: python python-3.x decision-tree


【解决方案1】:

我不确定您是否需要children_list。这似乎只是一个额外的维护。我认为确定节点是否具有positive_childnegative_child 应该就足够了。

注意向 Node 添加了 __str__ 方法,以便在打印时显示一些不错的东西...

看看:

class Node:
    def __init__(self, data, positive_child=None, negative_child=None):
        self.data = data
        self.positive_child = positive_child
        self.negative_child = negative_child

    def __str__(self) -> str:
        return self.data

class Decision:
    def __init__(self, root: Node):
        self.root = root

    def collect_leaves(self, node):
        ## ---------------------------
        ## This node has no children. It is a leaf
        ## ---------------------------
        if not node.positive_child and not node.negative_child:
            return [node]
        ## ---------------------------

        ## ---------------------------
        ## Recursively collect the leaves of children
        ## ---------------------------
        leaves = []
        if node.positive_child:
            leaves.extend(self.collect_leaves(node.positive_child))
        if node.negative_child:
            leaves.extend(self.collect_leaves(node.negative_child))
        return leaves
        ## ---------------------------

    def return_all_leaves(self):
        return self.collect_leaves(self.root)

my_decsion = Decision(
    Node(
        "root",
        Node("root_a", None, None),
        Node(
            "root_b",
            Node("root_b_1", None),
            Node("root_b_2", None),
        ),
    )
)

for node in my_decsion.return_all_leaves():
    print(node)

这应该给你:

root_a
root_b_1
root_b_2

请注意,虽然 python 中的递归有点受限,但您可能希望查看不基于它的实现。

如果您想要一个不基于递归的return_all_leaves() 版本,您可以尝试:

    def return_all_leaves2(self):
        leaves = []
        todo = [self.root]
        while todo:
            this_node = todo.pop(0)

            ## ---------------------------
            ## This node was None... I think this is cleaner than testing
            ## parent_node.positive_child and parent_node.negative_child
            ## ---------------------------
            if not this_node:
                continue
            ## ---------------------------

            ## ---------------------------
            ## This node has no children. It is a leaf
            ## ---------------------------
            if not this_node.positive_child and not this_node.negative_child:
                leaves.append(this_node)
                continue
            ## ---------------------------

            ## ---------------------------
            ## add the leaves of children to future work
            ## ---------------------------
            todo.append(this_node.positive_child)
            todo.append(this_node.negative_child)
            ## ---------------------------

        return leaves

如果我们使用您的数据进行测试:

my_decsion2 = Decision(
    Node(
        "cough",
        Node(
            "fever",
            Node(
                "headache",
                Node("hard influenza", None, None),
                Node("influenza", None, None)
            ),
            Node("cold", None, None)
        ),
        Node("healthy", None, None)
    )
)

for node in my_decsion2.return_all_leaves():
    print(node)

此代码打印:

hard influenza
influenza
cold
healthy

【讨论】:

  • 首先非常感谢:)。它只返回了他们的位置,我的意思是:[<__main__.node object at>, <__main__.node object at>, <__main__.node object at>, <__main__.node object at>] 但是伦很好。它应该返回 4 个项目,但是当我尝试编写 node.positive_child.data 时,它给了我一个错误('str' object has no attribute 'positive_child')
  • 你看到我在Node 中实现了__str__ 方法吗?这使您可以以一种很好的方式执行print(some_node),而不是看到您所看到的。
  • 嗯,是的,我按照你说的写了。如果您想查看,欢迎您尝试,我写了与我正在使用的完全相同的示例:)第二个也是完全相同的问题。再次,非常感谢!你的帮助不明显
  • 看看我贴的代码。它对您的两个课程都有一些更改。此外,您的示例使用了一个 Diagnoser 类,我认为这可能是您没有发布的内容,在这个问题的上下文中应该是 Decision。使用您发布的测试数据,我的这段代码会打印 4 个数据名称
  • 太棒了。非常感谢!没那么重要,但是你知道为什么函数的返回值仍然是[<__main__.node object at>, <__main__.node object at>, <__main__.node object at>, <__main__.node>] ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-17
  • 2022-10-05
  • 1970-01-01
  • 2016-01-24
  • 1970-01-01
相关资源
最近更新 更多