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

Question:

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)
Asked By: fond bcn

||

Answers:

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…

Answered By: Serge Ballesta

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)
Answered By: trincot
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.