Python-如何实现树抽象数据类型?

时间:2015-03-21 15:53:54

标签: python binary-search-tree

例如,二叉搜索树有一个条目5;它有两个分支,其中节点条目为2,右边为7.每个节点也有两个分支:对于节点条目2,它有左节点条目1和右节点条目3;对于节点入口7,它已经离开节点入口6和右节点入口10和8.要访问节点'输入顺序正确,首先访问左分支([1,2]然后3);然后访问5;最后访问右分支(第[6,7],然后[8,10])

如何创建一个函数" binary_tree(entry,left,right)"为了获取树抽象数据输出而不是使用排序或排序的函数。以及如何定义条目(树),left_branch(树)和right_branch(树)?

1 个答案:

答案 0 :(得分: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

我仍在使用生成器,因为它显然是“走树”的唯一正确方法(可以选择如何处理每个条目,无论是print还是yield an_entry否则,显然属于循环在这个发生器上的不同功能!)。但是我已经切换到yield的Py2兼容循环,因为如果家庭作业需要,用print替换每个entry会很容易。

我已经从Q的规格中更改了名称,因为Q的规格完全被破坏了WRT命名 - 它们要求本地参数(第一个)被命名为entry用于输入树节点的访问器函数相同命名为entry - 导致完全不必要的命名冲突[*]。所以我只将the_entry名称保留为访问者函数,并将an_entry替换为参数名称,并将for替换为globals()['entry']循环中所需的其他局部变量。< / p>

[*]它可以被解决,例如通过使用{{1}}来访问阴影的全局名称,但是只是愚蠢地把自己故意放在必须达到这样的“冰雹玛丽传递”的位置首先使用非冲突的名称要简单得多! - )