【问题标题】:Python-How to implement tree abstract data type? [duplicate]Python-如何实现树抽象数据类型? [复制]
【发布时间】:2015-05-24 22:25:52
【问题描述】:

例如,二叉搜索树有一个条目 5;它有两个分支,左节点条目为 2,右节点条目为 7。每个节点也有两个分支:对于节点条目 2,它有左节点条目 1 和右节点条目 3;对于节点条目 7,它有左节点条目 6 和右节点条目 10 和 8。要以正确的顺序访问节点的条目,首先访问左分支([1,2] 然后 3);然后访问5;最后访问正确的分支(先是[6,7],然后是[8,10])

如何创建函数“binary_tree(entry,left,right)”以获取树抽象数据输出,而不是使用 sorted 或 sorted 函数。?以及如何定义entry(tree)、left_branch(tree)和right_branch(tree)?

【问题讨论】:

  • @Carsten 不是真的,而是这应该太宽泛了......

标签: python binary-search-tree


【解决方案1】:

根据定义,抽象类是你不能直接实例化的;相反,您实例化实现它的具体类(通常是抽象类的子类)。

所以,为你的抽象类定义你想要的编程接口:例如,在 Python 2 中(它在 Py 3 中更优雅一点,但等效):

import abc

class AbstractTree(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def entry(self): return

    @abc.abstractmethod
    def left(self): return

    @abc.abstractmethod
    def right(self): return

然后是一个或多个具体的子类,并使用后者。

例如:

class SimpleTree(AbstractTree):

    def __init__(self, entry, left=None, right=None):
        self.entry = entry
        self.left = left
        self.right = right

    def entry(self): return self.entry

    def left(self): return self.left

    def right(self): return self.right

请注意,这是一个非常反常的情况,因为具体类没有从那个空的抽象类中获得任何功能——在现实生活中,即除了教学目的之外,我不会为此使用抽象类案例,因为这里没有附加值。不过,如果你坚持,这就是你的做法:-)。

对于您指定的辅助功能也是如此(这里我将切换到 Py 3,因为优雅是不可抗拒的):

def binary_tree_generator(entry, left, right):
    if left is not None:
        yield from binary_tree_generator(left.entry, left.left, left.right)
    yield entry
    if right is not None:
        yield from binary_tree_generator(right.entry, right.left, right.right)

def binary_tree(entry, left, right):
    for anentry in binary_tree_generator(entry, left, right):
        print(anentry)

在现实生活中,我会将此作为 AbstractTree 的方法,不是您需要的独立函数。同样对于您指定的其他三个辅助函数,它们与抽象类的 getter 方法完全相同...!

编辑:显然,形容词 abstract 已经足够重载,以至于 Q 不是关于 Python 自己的抽象基类,而是更抽象(!)的感觉“抽象”这个词。在这种情况下,例如,可以将每个树节点映射到一个 3 项元组(如果树节点是不可变的):

(entry, left, right)

仍然使用None 来表示“失踪”的leftright 孩子;在这种情况下,访问函数显然是

def entry(tree): return tree[0]
def left_branch(tree): return tree[1]
def right_branch(tree): return tree[2]

并且请求的在树上按顺序遍历的函数将使用生成器,例如(回到与 Py2 兼容的代码:-)...:

def binary_tree_generator(the_entry, left, right):
    if left is not None:
        for an_entry in binary_tree_generator(
            entry(left), left_branch(left), right_branch(left)):
            yield an_entry
    yield the_entry
    if right is not None:
        for an_entry in binary_tree_generator(
            entry(right), left_branch(right), right_branch(right)):
            yield an_entry

我仍在使用生成器,因为它显然是走一棵树的“唯一正确的方法”(可以选择如何处理每个条目,无论是 printing 还是其他方式,显然属于在这个生成器上循环的不同函数!)。但是我已经切换到 yield an_entry 的 Py2 兼容循环,因为如果作业需要,用 print 替换每个 yield 是微不足道的。

我更改了 Q 规范中的名称,因为 Q 的规范完全破坏了 WRT 命名——它们要求将本地参数(第一个参数)命名为 entry树节点条目的访问器函数完全相同命名为entry——导致完全不必要的命名冲突[*]。所以我只保留了 entry 名称作为访问器函数,并切换到 the_entry 作为参数名称和 an_entry 作为 for 循环中所需的其他局部变量。

[*] 它可以解决,例如通过使用globals()['entry'] 来访问阴影全局名称,但是当只使用非- 首先冲突的名称要简单得多!-)

【讨论】:

  • 我想这更多是关于一些基于 SICP 的 Python 编程课程,他们需要做抽象数据类型而不是类。
  • 是的,我认为这个问题只是要求基本的 ADT。
  • @chrsitinav,在 Python 中确实没有“基本 ADT”之类的东西(虽然有 抽象 基类作为语言的一部分!),但我已经编辑了我的答案,以展示一种处理我认为你的意思的方法,看看。
  • @Alex 感谢您的明确解释。我在 python 中输入了我的代码并对其进行了测试,但它无法运行。 (例如:print(entry(build_tree(1,2,3)))——1)
  • @chrsitinav,这是您有史以来第一次提到build_tree函数...!抱歉,我们读心术——如果您忘记提及关键规格并希望我们读懂您的想法,那么您会非常失望! 告诉我们关于所有的规格怎么样,而不是期望我们猜测其中的一半或更多——对你来说太具有革命性的概念......?!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
  • 2018-10-29
  • 2020-06-25
  • 2022-11-30
  • 1970-01-01
相关资源
最近更新 更多