【问题标题】:yielding data members in binary search tree在二叉搜索树中产生数据成员
【发布时间】:2019-03-02 00:50:38
【问题描述】:

我正在尝试为我的二叉搜索树实现一个迭代器。为了实现这一点,我尝试按顺序遍历树并产生每个单独的数据成员。这将允许我遍历树的每个项目。

我的功能:

def __iter__(self):
    """
    in-order traversal of a binary search tree
    """
    if self.root is not None:
        self.check(self.root)

def check(self, cur_node):
    if cur_node is not None:
        self.check(cur_node.left)
        yield cur_node.data #if I were to print this data member, it would be fine
        self.check(cur_node.right)

使用迭代测试此函数时,例如

for i in tree:

我收到此错误:

TypeError: iter() returned non-iterator of type 'NoneType'

【问题讨论】:

    标签: python binary-search-tree


    【解决方案1】:

    要实现递归生成器,您不能只“调用”自己,您需要提取元素并生成它们。

    Python 对此有一个特殊的语法:

     yield from expr
    

    其中expr是可迭代的,可以看成是的简写

     for x in expr:
         yield x
    

    使用它,您可以实现按顺序遍历树,如下所示:

    class Node:
        def __init__(self, data, left, right):
            self.data = data
            self.left = left
            self.right = right
    
        def __iter__(self):
            if self.left:
                yield from self.left
            yield self.data
            if self.right:
                yield from self.right
    

    【讨论】:

      【解决方案2】:

      线索是

      iter() 返回 ....

      所以你需要返回一个迭代器。你的类是一个迭代器,所以返回 self

      def __iter__(self):
          """
          in-order traversal of a binary search tree
          """
          if self.root is not None:
              self.check(self.root)
          return self
      

      您可能还应该实现 __next__ 以实际产生值。

      所以解决方案可能看起来像

      class Tree:
          def __init__(...): ...
      
          def __iter__(self):
              return self
      
          def __next__(self):
              if self.left is not None:
                  yield from self.left
              yield self.data
              if self.right is not None:    
                  yield from self.right 
      

      您在此处使用yield from 委托给子节点。见https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator

      实际上你确实需要三个 yield 语句,因为你需要遍历左右子节点,以及产生当前节点的值。

      【讨论】:

      • 更改枚举操作的内部状态是个坏主意...如果多个用户想同时迭代同一棵树怎么办?
      • 我正在经历一个无限循环?我通过将 cur_node.left 编辑为 self.cur_node.left 对您的代码进行了微调。你确定我们需要 3 个 yield 语句吗?
      • 我已对此进行了更新以解决多线程问题并使用类属性。
      【解决方案3】:

      您通常希望您的迭代器作为与数据结构分开的实体,这样您就可以对您的数据拥有多个迭代器,这样您就可以多次迭代您的数据。下面,我将展示如何为一个基本的 BST 类实现一个简单的 DFS 算法。

      class Node:
          def __init__(self, val, left=None, right=None):
              self.val = val
              self.left = left
              self.right = right
          def __iter__(self):
              return BSTIterator(self)
      
      class BSTIterator:
          def __init__(self, root):
              self.stack = []
              curr = root
              while curr:
                  self.stack.append(curr)
                  curr = curr.left
          def __next__(self):
              if not self.stack:
                  raise StopIteration()
              node = self.stack.pop()
              val = node.val
              node = node.right
              while node:
                  self.stack.append(node)
                  node = node.left
              return val
          def __iter__(self):
              return self
      
      root = Node(5, Node(3, Node(1), Node(4)), Node(10, (Node(6, None, Node(7)))))
      list(root)
      # [1, 3, 4, 5, 6, 7, 10]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-20
        • 1970-01-01
        • 2023-03-08
        • 2012-10-11
        相关资源
        最近更新 更多