二叉 Tree/Search 树

Binary Tree/Search Tree

我开始学习 Python 中的数据结构和算法,我现在正在学习二叉树。但是我真的很困惑如何实施它们。我看到一些实现有两个 classes,一个用于节点,一个用于树本身,如下所示:

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

class Tree: 
    def __init__(self):
    self.root = None
    
    def insert()
    def preorder()
    .
    .
    .

但是我也看到没有节点 class 的实现,而是所有代码都进入树 class 而没有以下

def __init__(self):
    self.root = None

谁能帮我理解为什么有两种不同的方法,每种方法的优缺点,它们之间的区别以及我应该遵循哪种方法来实现二叉树。

谢谢!

是的,有这两种方式。

首先,在 1-class 方法中,class 实际上是 2-[= 的 Node class(可能命名不同) 107=] 方法。没错,所有的方法都在 Node class 上,但在 2-class 方法中也可能是这种情况,其中 Tree class 会通过调用 Node class 上的方法来推迟大部分工作。所以 1-class 方法真正缺少的是 Tree class。 class 的名称可能会掩盖这一观察,但最好这样看,即使使用树的方法在 Node class.[=48 上也是如此=]

当您需要表示一棵空树时,差异就变得很明显了。使用 1-class 方法,您必须将主变量设置为 None。但是 None 与没有节点的树是不同的概念。因为在代表一棵空树的对象上,仍然可以调用方法再次添加节点。您不能在 None 上调用方法。这也意味着调用者需要知道何时将其自己的变量更改为 None 或更改为 Node 实例,具体取决于树是否恰好(或变为)空。

对于 2-class 系统,此管理从调用者手中取出,并在 Tree 实例内部进行管理。调用者将始终使用对该实例的单一引用,与树是否为空无关。

示例

1。创建一个空树

1-class方法:

root = None

2-class 方法:

tree = Tree()

2。将第一个值添加到空树

1-class 方法

# Cannot use an insert method, as there is no instance yet
root = new Node(1)  # Must get the value for the root

2-class 方法

tree.insert(1)  # No need to be aware of a changing root

由于1-class方法在这种情况下需要获取根的值,你经常看到使用这种方法,根总是被捕获就像那样,即使树不是空的。在那种情况下,调用者的 root 变量的值不会真正改变。

3。从树中删除最后一个值

root = root.delete(1)  # Must get the new value for the root; could be None!  

2-class 方法

tree.delete(1)  # No need to be aware of a changing root

尽管删除通常不会导致空树,但在 1-class 方法中,调用者必须考虑到这种可能性并始终分配给自己的根引用,因为它可能会变成None.

1-class 系统的变体

1。一个None

有时您会看到用具有 None 值的 Node 实例表示空树的方法,以表明这不是真正的数据。然后,当第一个值添加到树中时,该节点的值更新为该值。通过这种方式,调用者不再需要管理根:它总是对同一个 Node 实例的引用,有时它可以有一个 None 值,以表明树实际上是空的.

调用者使用此 1-class 变体的代码将与 2-class 方法相同。

这是不好的做法。在某些情况下,您可能希望一棵树能够将 None 值作为数据,然后您不能创建具有这样值的树,因为它会被误认为是代表空树的虚拟节点

2。哨兵节点

这是上述的变体。这里的虚拟节点 always 在那里。空树由单个节点实例表示。当第一个值被插入到树中时,这个虚拟节点的值永远不会更新,但是插入发生在它的 left 成员上。所以虚拟节点从来没有起到保存数据的作用,而只是在其 left 成员中维护树的真正根的容器。这实际上意味着虚拟节点与 2-class 方法中的 Tree 实例平行。它没有适当的 root 成员,而是具有该角色的 left 成员,并且它的 right 成员没有用处。

本机数据结构是如何实现的

2-class 方法更像是本机数据类型的工作方式。例如,以 Python 中的标准 list 为例。空列表由 [] 表示,而不是 None[]None 之间有明显的区别。一旦获得列表引用(如 lst = []),该引用就永远不会改变。您可以追加和删除,但您永远不必 分配给 lst 本身。