Python 3.x 如何遍历一棵树直到找到一个节点,并将沿途的属性相加

Python 3.x 如何遍历一棵树直到找到一个节点,并将沿途的属性相加,python-3.x,algorithm,tree,Python 3.x,Algorithm,Tree,我正在建造一棵任意结构的树。树的叶子具有其他节点不具有的特定属性。我试图找到一种方法来遍历树,找到一个特定的叶子,并保存我访问过的叶子的属性的总和。我需要我访问过的不是我正在搜索的叶子的累积总和,以及我正在尝试查找的叶子的属性。我需要它从左到右,从上到下搜索 示例树可能如下所示: 我的节点类是: 类节点: def uuu init uuuu(self,name,children=[],**kwargs): 自我记录更新(kwargs) self.name=名称 self.children=儿童

我正在建造一棵任意结构的树。树的叶子具有其他节点不具有的特定属性。我试图找到一种方法来遍历树,找到一个特定的叶子,并保存我访问过的叶子的属性的总和。我需要我访问过的不是我正在搜索的叶子的累积总和,以及我正在尝试查找的叶子的属性。我需要它从左到右,从上到下搜索

示例树可能如下所示:

我的
节点
类是:

类节点:
def uuu init uuuu(self,name,children=[],**kwargs):
自我记录更新(kwargs)
self.name=名称
self.children=儿童
def插入(自身、子项):
self.children.append(子级)
如果我将示例树构建为

l1=节点(“leaf1”,attr=1)
l2=节点(“叶2”,属性=2)
n2=节点(“节点2”,子节点=[l1,l2])
l3=节点(“叶3”,属性=3)
l4=节点(“叶4”,属性=4)
n1=节点(“节点1”,子节点=[n2,l3,l4])
l6=节点(“leaf6”,attr=6)
n4=节点(“节点4”,子节点=[l6])
l5=节点(“叶5”,属性=5)
l7=节点(“leaf7”,attr=7)
n3=节点(“节点3”,子节点=[l5,n4,l7])
根=节点(“根”,子节点=[n1,n3])
我想
搜索\u节点(root,“leaf4”)
,我希望得到
(6,4)
-元组的第一个元素是访问的所有不是leaf4的叶子的总和,第二个元素是附加到leaf4的属性<代码>搜索节点(根,“叶1”)将导致
(0,1)
,因为没有访问的叶不是叶1

以下是我目前掌握的代码:

def search_节点(节点,搜索名称):
总和=0
如果是node.children:
对于node.children中的子节点:
如果child.name==搜索\u名称:
报税表(总和、子女属性)
子树\u attr\u sum,节点\u attr=search\u节点(子节点,search\u名称)
如果node_attr不是None:
返回(子树属性和,节点属性)
其他:
cum_sum+=子树属性和
回报(总和,无)
其他:
返回(node.attr,无)

它似乎对树的左半部分有效,但对右半部分无效。诚然,这段代码很难看,可能会减少。

好的。代码中的一行修改:

def search_node(node, search_name):
    cum_sum = 0
    if node.children:
        for child in node.children:
            if child.name == search_name:
                return (cum_sum, child.attr)
            subtree_attr_sum, node_attr = search_node(child, search_name)
            if node_attr is not None:
                return (cum_sum + subtree_attr_sum, node_attr) # THIS LINE
            else:
                cum_sum += subtree_attr_sum
        return (cum_sum, None)
    else:
        return (node.attr, None)
你疏忽了。您没有将累积和添加到通过递归得到的结果中


另外,您的逻辑中可能存在一个错误:为什么不同时检查根

我无法回答您的问题,但在我看来,
else:return(node.attr,None)
没有用处,应该是
else:return(cum_sum,None)
。这与您的问题无关(因为您只在叶节点中省略了
子节点
arg),但是使用空列表作为
子项的默认参数可能是不明智的。如果您试图使用它将一个叶节点升级为普通节点,“插入”
方法最终会将子节点添加到该列表中,该列表由所有叶共享。@Blckknght您是对的。我的用例是从包含层次映射和节点定义的JSON文件生成树结构。当尝试将子节点插入根节点时,被插入的节点递归地将自己添加到其子节点列表中。是的,就是这样,谢谢!至于我为什么不检查根-我只是在结构中查找叶子(函数可能应该命名为
search\u leaf
或其他什么)。我可能应该做一些错误检查,以确保树本身已填充。