How the yield statement of __iter__ works in TreeNode object (BST) - python

I'm implementing a simple binary sort tree in python; the code below is a snippet.
I've read about the __iter__ implemention of TreeNode somewhere, and I try to understand how it works. The code works fine, but I was wondering about one thing:
How does the yield statements actually works here? It seems it starts with the root, traversing the left tree first, print each element but still starts from the root every time.
class BinaryST(object):
def __init__(self):
self.root = None
self.size = 0
def __len__(self):
return self.size
def __iter__(self):
class EmptyIter():
def next(self):
raise StopIteration
if self.root:
return self.root.__iter__()
return EmptyIter()
class TreeNode(object):
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __iter__(self):
# visit the left tree
if self.has_left_child():
for child in self.left:
print 'yielding left child'
yield child
# back to current element; root
print 'yielding root ele'
yield self.val
if self.has_right_child():
for child in self.right:
print 'yield right child'
yield child
Output:
bt = bst.BST()
bt.insert(5)
bt.insert(7)
bt.insert(3)
bt.insert(1)
for i in bt:
print i
yielding root ele
yielding left child
yielding left child
1
yielding root ele
yielding left child
3
yielding root ele
5
yielding root ele
yield right child
7
I'm trying to understand the code flow here. How does the stack looks? Any help would be appreciated.

Related

Tree Inorder Traversal Python

I'm trying to add elements to a binary tree and print them in in-order.
I'm getting an error while adding an element: AttributeError: 'NoneType' object has no attribute 'left'
Please let me know where I have to make a change Below is the code
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def InorderTraversal(self):
if self.data is None:
return
self.left.InorderTraversal()
print(self.data)
self.right.InorderTraversal()
if __name__ == "__main__":
root = Node(1)
root.insert(2)
root.insert(3)
root.insert(4)
root.InorderTraversal()
I am Implementing Trees First time Doesn't Have any idea
You should check if a node has left & right children before recursing on them:
class Node:
...
def InorderTraversal(self):
if self.left: # if left child exists, then recurse on it
self.left.InorderTraversal()
print(self.data)
if self.right: # if right child exists, then recurse on it
self.right.InorderTraversal()
Result:
1
2
3
4
You need the Node to be a separate class which will be used by the Tree class.
The insert and inorder_traversals are operations you do on a tree and not on a node. This is kinda the first thing you should do.
There are already pretty good resources you can look at since I might not be able to explain in that kind of detail :
https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
Also, you need to read up a little on how recursion and the classes work in python as I see some mistakes that can be fixed.
You're recursively printing the inorder traversal but you're doing the checks on self.data and running on self.left and self.right . self is pointing to the same data and you need to pass the node you wanna process next in the recursive function.
Also, you need to check the None condition on the Node and not on the data. Basically the node doesn't exist and that means you've to return from there
The inorder code overall idea is correct but you're working with wrong variables and basically you'll end up with incorrect output (or infinite loop)
My suggestion is to read up some more on tree on geeksforgeeks to begin with!

Why does "temp" in this piece of code keep the value from the left side when doing right side?

# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
self.resultpath = []
def dfs(node,target,temp):
if node is None:
return
temp.append(node.val)
print(temp)
if node.left is None and node.right is None and target == node.val:
self.resultpath.append(temp)
dfs(node.left, target-node.val, temp)
dfs(node.right, target-node.val, temp)
dfs(root, targetSum, [])
return self.resultpath
this is really confusing me. For a "Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22"
picture of the tree: https://imgur.com/a/cAK8kQn
As this code goes through the recursions, at temp = [5,4,11], dfs(node.left ...) will turn this into [5,4,11,7] but temp is still [5,4,11], so dfs(node.right ...) should turn this into [5,4,11,2] but the 7 from dfs(node.left ...) shows up to make it [5,4,11,7,2].
Why is that? How would I fix this code so it doesn't do that?
The issue is quite simple. There is only a single temp. You are passing a reference to this single object in all recursive calls, so any mutations in a recursive call to dfs will be visible from the calling scope.
The key is to simply copy temp every time you make a recursive call.

Python. I am trying to iteratively perform inorder Traversal of a tree, but I am going into an infinite loop

Below in the solution class, I have an implementation of an inorder traversal (left, root, right).
For some reason I am entering into an infinte loop and I wonder if it is becaue of the way python handels consecutive if if/else statements?
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = righ
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
out = []
stack = []
if root is None:
return out
else:
stack.append(root)
while stack != []:
temp = stack.pop()
if temp.right:
stack.append(temp.right)
if temp.left:
a = temp.left
stack.append(temp)
stack.append(a)
else:
out.append(temp.val)
return out

How to determine if a Binary Tree node is a Left or Right child?

I have a simple Tree data structure, however, I would like to implement two methods named isLeftChild and isRightChild.
The problem is I am having a very hard time understanding trees. The concept and general process has not fully been grasped.
Here is my simple tree so far:
class Node(object):
''' A tree node. '''
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def isLeftChild(self):
''' Returns True if the node is a left child, else False. '''
pass
def isRightChild(self):
''' Returns True if the node is a right child, else False. '''
pass
def insert(self, data):
''' Populate the tree. '''
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def printTree(self):
''' Display the tree. '''
if self.left:
self.left.printTree()
print self.data
if self.right:
self.right.printTree()
def main():
root = Node(8)
root.insert(2)
root.printTree()
main()
How can I have a node determine if it is a left child or a right child (without reference to its data)?
I am not sure what I need to add to my tree in order to determine this.
Use a parent attribute and test if the memory reference if the parent's right or left is the same as the child's reference in memory. You're going to need a parent attribute to traverse the tree anyway.
return self is self.parent.left # in the isLeftChild

Counting the nodes in a Binary Search Tree in Python

I'm fairly new to programming and I want to screw around with some Binary Search Trees. I want to make a function that counts the number of nodes in the tree recursively, however, when I run my function it doesn't seem to work and it keeps returning 'none' as if there is nothing in my tree. Could anyone help me find the problem here?
This is my TreeNode class:
class TreeNode(object):
def __init__(self, data = None, left=None, right=None):
self.item = data
self.left = left
self.right = right
def __str__(self):
return str(self.item)
This is my main function, I trimmed most of it down just so we can get to the problem referring to the counting of the nodes.
from TreeNode import TreeNode
class BST(object):
#------------------------------------------------------------
def __init__(self):
"""create empty binary search tree
post: empty tree created"""
self.root = None
def treeSize(self, root, size = 0):
if root is None:
return -1
if root is not None:
size += 1
if root.left is not None:
self.treeSize(root.left, size)
if root.right is not None:
self.treeSize(root.right, size)
This is the code I use to test out my function:
from BinarySearchTree import BST
from TreeNode import TreeNode
tree = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode (7, TreeNode(6),TreeNode(8)))
a = BST()
print(a.postOrder(tree))
print(a.treeSize(tree))
When I called the 'print(a.treeSize(tree))' It just returns 'none' and not '7' like it should.
You can also do it the good old recursive way:
def treeSize(self, root):
if root is None:
return 0
if root is not None:
return 1 + self.treeSize(root.left) + self.treeSize(root.right)
Jonathan's answer is nice as well.
I see. You think size is going to get updated in the called functions. It won't as it's local to each function. You could call global on it, but that's not optimal.
You could set it as a member variable (don't actually do it this way):
def __init__(self):
...
self.size = 0
def treeSize(self,...):
...
self.size += 1
...
return self.size
but the obvious bug is self.size will double every time treeSize is called. You can fix that too, but let's use patterns we know and love. Do it the good old recursive way like VHarisop wrote.

Categories