Беда со ссылками в Python (деревья)

1

Я пытаюсь удалить все поддеревья, содержащие только нули. Мой код ниже. В настоящий момент запуск removeFailures на корневом узле вообще не изменяет дерево (выполнение обхода предварительного заказа до и после дает тот же результат).

Я думаю, что это потому, что когда я говорю "root is None", я на самом деле не модифицирую root, я просто могу создать имя переменной temp, возможно, корень? Если это так, как я могу это исправить? Не будет ли это рассуждение работать на 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
Теги:
pointers
reference
tree

2 ответа

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 обеспечивает дополнительную проверку.

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 чтобы правильно удалить его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню