【问题标题】:Implementing recursive functions for trees in python class在python类中为树实现递归函数
【发布时间】:2017-01-13 07:44:55
【问题描述】:

我创建了一个类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()

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

【问题讨论】:

    标签: python python-2.7 recursion tree


    【解决方案1】:

    是的,您可以在一个函数中实现所有 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)
    

    【讨论】:

      【解决方案2】:

      我不确定将遍历函数实现为单行,但您尝试做的另一种方法是通过将遍历逻辑抽象为一系列来使 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-09
        • 2014-12-27
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 2021-12-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多