在Python中错误实现BST反序列化

在Python中错误实现BST反序列化,python,binary-search-tree,Python,Binary Search Tree,这是我用Python实现的BST class BST: def __init__(self): self.root = None self.size = 0 def insert(self, item): self.root = self.insert_helper(item, self.root) self.size += 1 return self.root def insert_he

这是我用Python实现的BST

class BST:
    def __init__(self):
        self.root = None
        self.size = 0

    def insert(self, item):
        self.root = self.insert_helper(item, self.root)
        self.size += 1
        return self.root

    def insert_helper(self, item, root):
        if root is None:
            p = Node(item)
            root = p
            return root
        if item > root.data:
            root.right = self.insert_helper(item, root.right)
        else:
            root.left = self.insert_helper(item, root.left)
        return root


class Node:
    def __init__(self, data):
        if data is None:
            raise ValueError('Cannot create Node with None value.')
        self.data = data
        self.left = None
        self.right = None
现在,我正在尝试将BST
序列化
反序列化成一个列表,反之亦然

这是序列化代码

def serialize(root):
    tree_list = []
    serialize_helper(root, tree_list)
    return tree_list


def serialize_helper(root, tree_list):
    if root is None:
        tree_list.append(sys.maxsize)
        return
    tree_list.append(root.data)
    serialize_helper(root.left, tree_list)
    serialize_helper(root.right, tree_list)
这是反序列化的代码

def deserialize(tree_list):
    index = 0
    return deserialize_helper(tree_list, index)


def deserialize_helper(tree_list, index):
    if index == len(tree_list) or tree_list[index] == sys.maxsize:
        return None
    root = Node(tree_list[index])
    index += 1
    root.left = deserialize_helper(tree_list, index)
    root.right = deserialize_helper(tree_list, index)
    return root

这段代码有缺陷,在左侧和右侧都复制了一个子节点。我调试了代码,似乎当递归折叠时,索引减少了,因此我得到了这种行为。有人能帮我吗

在Python中有两大类对象:不可变对象和可变对象。必须了解它们之间的区别:

a = [] # a list, lists are mutable
b = a  # b and a now reference the same object
b.append(1)  # change b and the change will be in-place
print(a)     # since a references the same object
# [1]

a = 1 # an int, ints are immutable
b = a # b and a may well reference the same object, but
b += 1   # since the object cannot change a new object is bound to b
print(a) # leaving a unaffected
# 1
类似地,如果您将列表传递给一个函数,而该函数更改了列表,但没有显式返回列表,那么调用方仍然可以看到这些更改,事实上,持有列表引用的任何人都可以看到这些更改。有些人把这称为副作用。您正在序列化服务器中使用此技术

如果将一个不可变对象(如
索引
)传递给一个函数,并在该函数中对其进行操作,则原始对象不会更改。函数中的名称仅绑定到调用方不可见的新对象,除非显式返回它们

因此,要修复反序列化程序,请尝试像这样返回子树和当前索引

return root, index
这样调用者就可以像这样更新他们的

root.left, index = deserialize_helper(tree_list, index)

我不能轻易地得到保罗的答案,所以下面是我最终解决问题的方法。感谢Paul帮助我理解不变性和副作用问题,这是主要的bug。我使用了迭代器而不是整数索引

def deserialize(tree_list):
    itr = iter(tree_list)
    return deserialize_helper(tree_list, itr)


def deserialize_helper(tree_list, itr):
    item = next(itr)
    if item is None or item == sys.maxsize:
        return None
    p = Node(item)
    p.left = deserialize_helper(tree_list, itr)
    p.right = deserialize_helper(tree_list, itr)
    return p

与列表不同,INT是不可变的,因此您不能在适当的位置更改它们,这意味着您不能使用它们产生副作用。最简单的方法是让助手返回更新的索引。沿着子树。因此,您可以将新值重新分配给一级索引。@PaulPanzer我是计算机科学新手,我模糊地理解您的意思,但如果您能多解释一下就地和副作用的概念,我将不胜感激。这实际上相当优雅!