Python(树)中的引用出现问题

时间:2018-10-18 00:06:07

标签: python pointers reference tree

我正在尝试删除仅包含零的所有子树。我的代码如下。现在,在根节点上运行removeFailures根本不会修改树(在前后进行预遍历会得到相同的结果)。

我认为这是因为当我说“ root is None”时,实际上并没有修改root,我只是在创建一个可能是root的临时变量名?如果是这种情况,我该如何解决呢?这种推理在Java中行不通吗?

    # Ex.
    #           4                      4
    #        /     \                /      \
    #       1       3              1        3
    #       / \    / \     -->    /       /  \
    #      0   0  4  6           0       4   6
    #     /\  /\                / \
    #    3 5 0  0              3  5


    class TreeNode:
        def __init__(self, data, left=None, right=None):
            self.data = data
            self.left = left
            self.right = right


    def removeFailures(root):
        if root is None:
            return True

        removeLeft = removeFailures(root.left)
        removeRight = removeFailures(root.right)
        if root.data == 0 and removeLeft and removeRight:
            root = None
            return True
        return False


    def preorder(root):
        print root.data
        if root.left:
            preorder(root.left)
        if root.right:
            preorder(root.right)

    example = TreeNode(4)
    example.left = TreeNode(1, TreeNode(0, TreeNode(3), TreeNode(5)), TreeNode(0, TreeNode(0), TreeNode(0)))
    example.right = TreeNode(3, TreeNode(4), TreeNode(6))
    preorder(example)
    print '*************************'

    removeFailures(example)

    preorder(example) #TODO

2 个答案:

答案 0 :(得分:1)

要检查树中的所有节点是否都包含零,您将必须遍历每个节点。一种可能性是创建一个__iter__方法来查找树中的所有节点,然后可以应用any内置函数来确定它们是否都等于零。最后,一种简单的递归方法可以检查左侧和右侧的子级,并在必要时将其删除。

为简化创建树的过程,使用kwargs来就地构建结构,而无需实现Rotate方法或较长的赋值语句序列:

class Tree:
  def __init__(self, **kwargs):
    self.__dict__ = {i:kwargs.get(i) for i in ['left', 'right', 'val']}
  def __iter__(self):
    yield self.val
    yield from ([] if self.left is None else self.left)
    yield from ([] if self.right is None else self.right)
  @staticmethod
  def remove_empty_trees(_t):
    if not any(_t):
       return None
    _t.remove_trees()
    return _t
  def remove_trees(self):
    if not any([] if self.left is None else self.left):
       self.left = None
    else:
       self.left.remove_trees()
    if not any([] if self.right is None else self.right):
       self.right = None
    else:
       self.right.remove_trees()

#           4         
#        /     \    
#       1       3 
#       / \    / \  
#      0   0  4  6
#     /\  /\            
#    3 5 0  0
t = Tree(val=4, left=Tree(val=1, left=Tree(val=0, left=Tree(val=3), right=Tree(val=5)), right=Tree(val=0, left=Tree(val=0), right=Tree(val=0))), right=Tree(val=3, left=Tree(val=4), right=Tree(val=6)))
new_tree = Tree.remove_empty_trees(t)
print(print(new_tree.left.right))

输出:

None

要处理整个树包含零个节点的情况,staticmethod提供了额外的检查。

答案 1 :(得分:0)

在子节点上递归调用removeFailures()后,如果已成功删除它们,则必须将它们设置为None

def removeFailures(root):
    if root is None:
        return True

    removeLeft = removeFailures(root.left)
    removeRight = removeFailures(root.right)

    # Check if successfully removed children
    if removeLeft:
        root.left = None
    if removeRight:
        root.right = None

    if root.data == 0 and removeLeft and removeRight:
        root = None
        return True
    return False

输出:

4
1
0
3
5
0
0
0
3
4
6
*************************
4
1
0
3
5
3
4
6

将节点本身设置为None是不够的,因为父节点仍保留对其的引用。因此,需要将对该节点的所有引用都设置为None才能正确删除它。