在python类中实现树的递归函数

时间:2017-01-13 07:44:55

标签: python python-2.7 recursion tree

我创建了一个班级Tree和一个班级Node。现在我需要实施preOrderpostOrderinOrder遍历。我是用私人功能做的。但有没有办法只使用一个函数来做同样的事情?

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

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

    # Private helper functions
    def __insert(self, data, root):
        if data < root.data:
            if root.left is None:
                root.left = Node(data)
            else:
                self.__insert(data, root.left)
        elif data >= root.data:
            if root.right is None:
                root.right = Node(data)
            else:
                self.__insert(data, root.right)

    # Traversals
    def __preOrder(self, root):
        print root.data
        if root.left:
            self.__preOrder(root.left)
        if root.right:
            self.__preOrder(root.right)

    # Wrapper Functions 
    def insert(self, data):
        if self.root == None:
            self.root = Node(data)
        else:
            self.__insert(data, self.root)

    def preOrder(self):
        self.__preOrder(self.root)


tree = Tree()
print "Enter elements to be inserted in the tree(End with a -1): "
while True:
    elem = int(raw_input())
    if elem == -1:
        break
    tree.insert(elem)

print "Preorder traversal: "
tree.preOrder()

这里我必须使用辅助函数,因为我不希望用户明确地提供根元素。

2 个答案:

答案 0 :(得分:6)

是的,您可以在单个函数中实现所有3种类型的遍历。我已经将遍历函数转换为生成器,以使它们更加通用。因此,它们不是打印数据,而是生成数据的迭代器。这使您可以在数据生成时处理数据,也可以将数据捕获到列表(或其他集合)中。

在Python 2中,您的类应该继承自object,否则您将获得旧式类,与新式类相比,它们相当有限(Python 3只有新式类)。

顺便说一句,没有必要为私有函数(调用Python的name-mangling机制)使用双下划线,单个前导下划线就足够了。

我还在类中添加了简单的__repr__方法,这些方法在开发过程中非常方便。调试。

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

    def __repr__(self):
        return repr((self.data, self.left, self.right))


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

    def __repr__(self):
        return repr(self.root)

    # Private helper functions
    def _insert(self, data, root):
        if data < root.data:
            if root.left is None:
                root.left = Node(data)
            else:
                self._insert(data, root.left)
        else: # data >= root.data:
            if root.right is None:
                root.right = Node(data)
            else:
                self._insert(data, root.right)

    def _traverse(self, root, mode):
        if mode == 'pre':
            yield root.data
        if root.left:
            for u in self._traverse(root.left, mode):
                yield u
        if mode == 'in':
            yield root.data
        if root.right:
            for u in self._traverse(root.right, mode):
                yield u
        if mode == 'post':
            yield root.data

    # Wrapper Functions 
    def insert(self, data):
        if self.root == None:
            self.root = Node(data)
        else:
            self._insert(data, self.root)

    def preOrder(self):
        for u in self._traverse(self.root, 'pre'):
            yield u

    def inOrder(self):
        for u in self._traverse(self.root, 'in'):
            yield u

    def postOrder(self):
        for u in self._traverse(self.root, 'post'):
            yield u

# Test

tree = Tree()

for elem in '31415926':
    tree.insert(elem)

print tree

print "Preorder traversal: "
print list(tree.preOrder())

print "InOrder Traversal: "
print list(tree.inOrder())

print "PostOrder Traversal: "
print list(tree.postOrder())

<强>输出

('3', ('1', None, ('1', None, ('2', None, None))), ('4', None, ('5', None, ('9', ('6', None, None), None))))
Preorder traversal: 
['3', '1', '1', '2', '4', '5', '9', '6']
InOrder Traversal: 
['1', '1', '2', '3', '4', '5', '6', '9']
PostOrder Traversal: 
['2', '1', '1', '6', '9', '5', '4', '3']

以下是处理数据的示例:

for data in tree.inOrder():
    print data

FWIW,这段代码在Python 3中会更加清晰,因为我们可以使用yield from语法而不是那些for循环。而不是

for u in self._traverse(root.left, mode):
    yield u

我们可以做到

yield from self._traverse(root.left, mode)

答案 1 :(得分:1)

我不确定将遍历函数实现为单行,但是您尝试做的另一种方法是通过抽象使Strategy Pattern适应您的用例将遍历逻辑转换为一系列独立的类,这些类都继承自一个公共TraversalStrategy。然后,您可以将遍历策略对象作为依赖项注入Tree,从而将树的结构与用于遍历它的逻辑分离。

这种方法有以下好处:

  • 它允许您摆脱当前Tree方法的大部分
  • 它提高了程序的可测试性(您可以单独测试树遍历策略,而不是与其他树相关的逻辑)
  • 它增加了可重用性(您可以在其他情况下使用这些遍历策略)
  • 一般情况下,它会使您的计划更加SOLID
    • 您的Tree班级现在有一个单一的责任 - 一个改变的理由
    • 您可以为树实施新的遍历行为,而无需触及Tree的源代码,即它已关闭以进行修改
    • 您将遍历逻辑作为依赖项注入,因此在不同的实现之间替换非常容易,包括模拟

下面的代码是为Python 3编写的,因此需要对Python 2进行一些小改动。

from abc import ABC, abstractmethod


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

    def __repr__(self):
        return str(self.data)


class Tree:
    def __init__(self, traversal_strategy):
        self.root = None
        self.traversal_strategy = traversal_strategy

    def insert(self, data):
        if self.root is None:
            self.root = Node(data)
        else:
            self.__insert(data, self.root)

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

    def traverse(self):
        self.traversal_strategy.traverse(self.root)


class TraversalStrategy(ABC):
    @abstractmethod
    def traverse(self, node):
        pass

    def _attempt_traverse(self, node):
        if node:
            self.traverse(node)


class PreOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        print(node)
        self._attempt_traverse(node.left)
        self._attempt_traverse(node.right)


class InOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        self._attempt_traverse(node.left)
        print(node)
        self._attempt_traverse(node.right)


class PostOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        self._attempt_traverse(node.left)
        self._attempt_traverse(node.right)
        print(node)


def build_tree(traversal_strategy):
    tree = Tree(traversal_strategy)
    elements = [1, 3, 6, 9, 2, 8]

    for element in elements:
        tree.insert(element)

    return tree


if __name__ == '__main__':
    pre_order_tree = build_tree(PreOrderTraversal())
    in_order_tree = build_tree(InOrderTraversal())
    post_order_tree = build_tree(PostOrderTraversal())

    print('Pre order traversal: ')
    pre_order_tree.traverse()
    print()

    print('In order traversal: ')
    in_order_tree.traverse()
    print()

    print('Post order traversal: ')
    post_order_tree.traverse()
    print()

<强>输出

Pre order traversal: 
1
3
2
6
9
8

In order traversal: 
1
2
3
6
8
9

Post order traversal: 
2
8
9
6
3
1