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)
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…
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)
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)
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…
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 withyield 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)