能不能用 yield 获取嵌套函数中的所有结果?

huangapple go评论126阅读模式
英文:

Can i use yield to get the result of all the result in nested function?

问题

我找到了很多验证有效二叉树的代码但我尝试创建一个简单的版本但它总是返回True
抱歉我不太理解递归

英文:

I found many code to verify a valid binary tree, but I tried to creat a simple one, however it rise true all the time!
Sorry I don't understand the recursion very well.

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def is_BST():
        if root:
          return all(is_BST1(root))
def is_BST1(curnode):
        if curnode.right:
          if curnode.right.val>curnode.val:
            is_BST1(curnode.right)
          else:
            yield False
        if curnode.left:
          if curnode.left.val<curnode.val:
            is_BST1(curnode.left)
          else:
            yield False
        else:
          yield True

#tree creation code
    
print(is_BST)

答案1

得分: 2

你的代码存在几个问题:

  • 递归调用的结果被忽略了。由于你将 is_BST1 创建为一个生成器,你应该使用 yield from 进行递归调用,像这样:

    yield from is_BST1(curnode.right) 
    
  • 即使有了上面的修复,你仍然会得到错误的结果。例如,对于这个树:

             2
            /
           1
            \
             3
    

    你的代码总是会返回 True,但它未能发现值为 3 的节点违反了BST属性,因为它大于 2。

  • 并非真正的问题,但是你的代码在发现了BST属性的违规后仍然继续查找。这没有任何好处。一旦发现违规,算法就不应该继续调查任何其他节点,并返回 False

  • 如果将树的根传递给 is_BST 函数,会更有用,这样调用者可以指定要验证哪棵树。

要正确验证BST,你需要做的不仅仅是比较父节点的值与直接子节点的值。有几种可能的方法,包括以下两种:

  • 你可以创建一个生成器,按中序序列生成树的值,然后验证生成的值是否按非递减顺序生成。

  • 你可以向每个递归调用传递一个“窗口”,该窗口为访问的子树中的所有值定义了下限和上限,随着在树中的深入,此窗口变得更窄。

两种方法都可以。由于你使用了生成器的思想(使用 yield),我将为第一种方法提供代码:

from itertools import tee

def is_BST(root):
    current, lead = tee(inorder(root))
    next(lead, None)
    return all(a <= b for a, b in zip(current, lead))

def inorder(curnode):
    if curnode:
        yield from inorder(curnode.left)
        yield curnode.val
        yield from inorder(curnode.right)
英文:

There are several issues in your code:

  • The results from the recursive calls are ignored. As you have created is_BST1 as a generator, you would do the recursive call with yield from, like so:

    yield from is_BST1(curnode.right) 
    
  • Even with the above fix, you will get false positives. For instance for this tree:

             2
            /
           1
            \
             3
    

    Your code will always yield True, but it fails to see that node with value 3 is violating the BST property as it is greater than 2.

  • Not a real problem, but your code keeps looking further even when it has found a violation of the BST property. This brings no benefit. Once you have a violation, the algorithm should not investigate any other nodes and quit with False

  • It would be more useful if you would pass the root of the tree to the is_BST function, so the caller can indicate which tree to validate.

To validate a BST properly, you need to do more than just compare a parent value with the value of a direct child. There are several approaches possible, including these two:

  • You could create a generator that produces the tree values in in-order sequence, and then verify that the produced values are yielded in non-decreasing order

  • You could pass down a "window" to each recursive call which defines a lower and upper bound for all values in the visited subtree, as you go deeper in the tree this window becomes more narrow.

Either will work. Since you were working with the idea of a generator (using yield) I will provide the code for the first idea:

from itertools import tee

def is_BST(root):
    current, lead = tee(inorder(root))
    next(lead, None)
    return all(a <= b for a, b in zip(current, lead))

def inorder(curnode):
    if curnode:
        yield from inorder(curnode.left)
        yield curnode.val
        yield from inorder(curnode.right)

答案2

得分: -1

你主要的问题是这一行:

is_BST1(curnode.right)

只返回一个生成器,但并没有对其进行任何操作。你至少应该对该生成器进行迭代:

        ...
        if curnode.right:
          if curnode.right.val > curnode.val:
            # 对从右节点构建的生成器进行迭代
            for i in is_BST1(curnode.right):
                yield i
          else:
            ...

当然,对左子节点也要做同样的操作...

英文:

Your main problem is that this line:

        is_BST1(curnode.right)

only returns a generator, but does nothing with it. You should at least iterate on that generator:

    ...
    if curnode.right:
      if curnode.right.val>curnode.val:
        # iterate on the generator built from right node
        for i in is_BST1(curnode.right):
            yield i
      else:
        ...

and of course do the same for the left child...

huangapple
  • 本文由 发表于 2023年3月12日 17:00:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75712036.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定