【问题标题】:'Node' object has no attribute 'insert' for Binary Tree Implementation“节点”对象没有用于二叉树实现的属性“插入”
【发布时间】:2021-01-17 08:13:01
【问题描述】:

我知道以前有人问过这类问题,我并不是盲目地问你们这个问题,因为我已经回答了以前的问题,但我完全没有得到它。这是下面的代码:

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

class BST():
    def __init__(self):
        self.head=None

    def insert(self,data):
        if self.head is None:
            self.head=Node(data)

        if self.head:
            if data<self.head.data:
                if self.head.left is None:
                    self.head.left=Node(data)
                else:
                    self.head.left.insert(data)

            if data>self.head.data:
                if self.head.right is None:
                    self.head.right=Node(data)
                else:
                    self.head.right.insert(data)  #Actual error point

l1=BST()
l1.insert(2)
l1.insert(4)
l1.insert(6) #Getting the error while inserting this

我知道我要么需要将 insert 方法放在 Node 类中,要么将 Node 类属性继承到 BST 类中,但是我很难实现这两种解决方案,请你们走我通过这两种解决方案,用书面代码的解释对我真的很有帮助。

你可能已经厌倦了看到这些问题,你们都是这里的专家,你知道这对于初学者来说有多难,尤其是我不想从不清楚的概念开始。

【问题讨论】:

  • stackoverflow 不是一个教程网站,所以在我看来你问的不是主题。
  • @martineau 你至少能给我一个解决我的错误的方法吗?
  • 我不会给你一个完整的解决方案,但你可能会发现了解leftright应该是子树而不是独立的节点。所以你根本不需要class Node - 只需将data 放在class BST 中。

标签: python python-3.x data-structures binary-search-tree object-reference


【解决方案1】:

解决这个问题的一种方法是给Nodes 一个方法,根据它的值与它自己的值相比如何将另一个附加到它,并让树class 调用它。然后,树类实例可以调用它的头部 Node 来执行此操作。下面的代码展示了如何做到这一点。

值得注意的是,我还更改了树类,因此通过将 head 设置为 Node 在创建时具有唯一数据值,它永远不会为空。这样做意味着需要检查空树的唯一时间是在尝试将数据附加到树时引发TypeError - 而不是在Node.attach() 方法中一遍又一遍地递归.以这种方式实现它可以使代码更简单并且运行得更快。通过查看树的头部是否不是不可能是真实数据的特殊值来完成检查。

此类特殊值称为“sentinel values”,确保它们与任何可能的合法值区分开来很重要。在 Python 中,您可以创建一个内置(基本上没有功能)object 类的实例来获取一个。

class BinaryTree:
    SENTINEL = object()  # Unique value.

    def __init__(self):
        self.head = Node(self.SENTINEL)

    def insert(self, data):
        try:
            self.head.attach(data)
        except TypeError:
            if self.head.data is self.SENTINEL:  # Empty tree?
                self.head.data = data  # First is special case.
            else:
                raise

    def print(self):
        self.head.print()
        print()


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

    def attach(self, data):
        if data < self.data:
            if self.left is None:
                self.left = Node(data)
            else:
                self.left.attach(data)
        elif data > self.data:
            if self.right is None:
                self.right = Node(data)
            else:
                self.right.attach(data)

    def print(self):
        if self.left:
            self.left.print()
        print(self.data, end=' ')
        if self.right:
            self.right.print()


if __name__ == '__main__':

    tree = BinaryTree()
    tree.insert(2)
    tree.insert(4)
    tree.insert(6)
    tree.print()  # -> 2 4 6

【讨论】:

  • 非常感谢您提供的详细信息,只是想知道您为什么必须在两个类中编写insert 方法?
  • 我这样做是因为您的测试代码正在调用树类实例的insert 方法,这似乎是一个描述性名称。如果您发现其中两个令人困惑,您可以轻松地将 Node 类中的一个重命名为其他名称。 Node 类中的那个或多或少是私有的,因为树类的用户不直接使用它,因此它实际上并不是它自己的“公共”接口的一部分。
  • 好的,现在它更有意义了,感谢您的时间和解释,我很感激。我赞成您的回答,顺便问一下,您有没有推荐关于“哨兵”价值观的文章?跨度>
  • 感谢您这样做。 “哨兵”值的使用由来已久。我第一次了解它们是在 Niklaus Wirth 写的一本关于数据结构的书中。在主题的wikipedia article 中有一些关于它们的信息以及它们在编程中的用途。
  • P.S.我将Node 类的insert() 方法的名称更改为attach(),因为这样可以更好地描述它的作用(在当前方法上附加一个新的Node)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多