我试图从python中的列表构建一个树。我树中的节点具有列表索引的值,每个节点的父节点将是该索引列表中指定的节点。
在下面的代码示例中,varlist
使用输入array
中的值存储树的节点元素。
例如,[-1,0,4,0,3]的输入列表应该给出以下树:
0 / \ 1 3 \ 4 \ 2
我这样做的方法是首先在列表中单独初始化节点,默认父节点为None。然后,当我遍历数组时,我按照以下方式分配父和子:
class Node1:
def __init__(self, val, parent, children = []):
self.val = val
if parent == -1:
self.parent = None
else:
self.parent = parent
self.children = children
def __str__(self):
return(str(self.val))
def treeHeight(array):
varlist = [0] * len(array)
for i in range(len(array)):
varlist[i] = Node1(i, None)
for i in range(len(varlist)):
if array[i] != -1:
varlist[i].parent = varlist[array[i]]
varlist[array[i]].children.append(varlist[i])
else:
root = varlist[i]
for i in range(len(array)):
print(varlist[i].val,varlist[i].parent, varlist[i].children)
return(None)
if __name__ == '__main__':
print(treeHeight([-1, 0, 4, 0, 3]))
我得到的输出是:
0 None [<__main__.Node1 object at 0x1041051d0>, <__main__.Node1 object at 0x104105208>, <__main__.Node1 object at 0x104105780>, <__main__.Node1 object at 0x104105cc0>]
1 0 [<__main__.Node1 object at 0x1041051d0>, <__main__.Node1 object at 0x104105208>, <__main__.Node1 object at 0x104105780>, <__main__.Node1 object at 0x104105cc0>]
2 4 [<__main__.Node1 object at 0x1041051d0>, <__main__.Node1 object at 0x104105208>, <__main__.Node1 object at 0x104105780>, <__main__.Node1 object at 0x104105cc0>]
3 0 [<__main__.Node1 object at 0x1041051d0>, <__main__.Node1 object at 0x104105208>, <__main__.Node1 object at 0x104105780>, <__main__.Node1 object at 0x104105cc0>]
4 3 [<__main__.Node1 object at 0x1041051d0>, <__main__.Node1 object at 0x104105208>, <__main__.Node1 object at 0x104105780>, <__main__.Node1 object at 0x104105cc0>]
输出不是我所期望的,因为不知何故,所有节点的children
列表中都有4个元素,当我期望其中2个有2个孩子而其余的空时。有人可以帮我解释一下这里发生了什么吗?
答案 0 :(得分:1)
首先,您需要了解__repr__
和__str__
之间的区别。在这种情况下,您可以尝试表示您创建的Node1
对象,因为 repr 的目标是对象的完整字符串表示形式;而 str 只是为了打印一个很好的字符串。您应该实际定义__repr__
。在您的情况下,您实现的__str__
函数实际上根本没有使用。
另一件事是你永远不应该使用可变对象作为python函数中的默认参数,这实际上是一个不好的做法,如:
将可变列表或字典作为函数的默认参数传递可能会产生无法预料的后果。通常当程序员使用列表或字典作为函数的默认参数时,程序员希望程序在每次调用函数时都创建新的列表或字典。但是,这不是Python所做的。第一次调用该函数时,Python会为列表或字典创建一个持久对象。每次调用该函数时,Python都会使用从第一次调用函数创建的相同持久对象。
class Node1:
def __init__(self, val, parent, children = ()): # default argument should be immutable
self.val = val
if parent == -1:
self.parent = None
else:
self.parent = parent
if not isinstance(children, list):
children = list(children)
self.children = children
def __str__(self):
return(str(self.val))
def __repr__(self):
return(str(self.val)) # need to define __repr__
def treeHeight(array):
varlist = [0] * len(array)
for i in range(len(array)):
varlist[i] = Node1(i, None)
for i in range(len(varlist)):
if array[i] != -1:
varlist[i].parent = varlist[array[i]]
varlist[array[i]].children.append(varlist[i])
else:
root = varlist[i]
for i in range(len(array)):
print(varlist[i].val,varlist[i].parent, varlist[i].children)
return(None)
if __name__ == '__main__':
print('\n\n')
print(treeHeight([-1, 0, 4, 0, 3]))
通常,最佳做法是使用“使用标记值”来表示空列表或字典:
class Node1:
def __init__(self, val, parent=None, child=None): # default argument should be immutable
self.val = val
self.children= []
if parent and parent.val != -1:
self.parent = parent
else:
self.parent = None
if child:
self.children.append(child)
# def __str__(self):
# return(str(self.val))
def __repr__(self):
return(str(self.val)) # need to define __repr__
def treeHeight(arr): # array is reverse attribute in python, use arr instead
varlist = []
for i in range(len(arr)):
varlist.append(Node1(i))
for i in range(len(varlist)):
if arr[i]!=-1:
varlist[i].parent = varlist[arr[i]]
varlist[arr[i]].children.append(varlist[i])
else:
root = varlist[i]
for i in range(len(arr)):
print(varlist[i].val,varlist[i].parent, varlist[i].children)
return
if __name__ == '__main__':
print('\n\n')
treeHeight([-1, 0, 4, 0, 3])