Calling a recursive function inside a class - python

I am trying to call a recursive method in order to find path from root to node in a binary tree. There are few solns. for this problem on the internet, but I am trying to use slightly different approach by implementing a method inside a Node class.
Here is my logic for the soln.
def apend(self, arr, target):
""" arr is the list which has the path from root to target node, self is the root """
if self is None:
return False
arr.append(self.data)
if self.data==target:
return True
if self.left.apend(arr, target) or self.right.apend(arr, target):
return True
arr.pop()
return False
I a perfectly okay with how this logic is working, means if the target is found in either right or left subtree return True.
My question is; what if self is a leaf node, i.e. self.left is None. same with self. right. In that case the recursive call is giving an error.
Can I get some help on how to rectify that situation? thanx

Instead of checking if self is None you need to check if self.left or self.right is None before you make a recursive call.
def apend(self, arr, target):
""" arr is the list which has the path from root to target node, self is the root """
arr.append(self.data)
if self.data==target:
return True
if self.left is not None and self.left.apend(arr, target):
return True
if self.right is not None and self.right.apend(arr, target):
return True
arr.pop()
return False

Related

Why I am seeing None data after deleting the smallest or largest item from Binary Search Tree?

I have a binary search tree. I have written basic insert, delete, traversal of the full tree and find its maximum and minimum node of the tree but I have trouble with finding maximum and minimum node after deleting the minimum or the maximum node.
This function deletes a specific node:
def deleteNode(self,val):
if self.data:
if self.data > val:
self.left.deleteNode(val)
elif self.data < val:
self.right.deleteNode(val)
else:
if self.left is None:
self.data = self.right
return True
elif self.right is None:
self.data = self.left
return True
else:
dltNode = self
dltNode.data = self.data
largest = self.left.findMax()
dltNode.data = largest
dltNode.left.deleteNode(largest)
return True
This function finds the minimum node:
def findMin(self):
if self.data:
if self.left is None:
return self.data
else:
return self.left.findMin()
And this is for the maximum node:
def findMax(self):
if self.data:
if self.right is None:
return self.data
else:
return self.right.findMax()
findMin and findMax functions work fine without deleting any node.
If I ever call then after deleting the minimum and maximum node they will return None, whether they were supposed to return only integer node data. Here is the screenshot of my output:
It should print 34 instead of None.
Here is my full code
There are a few issues in deleteNode
if self.data should not be there: this would mean you cannot delete a node with value 0 from the tree. A similar problem exists in other methods (findMin, findMax, insert, ...).
self.left.deleteNode(val) is executed without checking first that self.left is not None. The same is true for self.right.deleteNode(val)
self.data = self.right assigns a Node reference to a data attribute (which is supposed to be a number).
The function sometimes returns nothing (None) or True. Because of the recursive nature, the original caller of the method will get None. This is not consistent.
The function cannot deal with deleting the root Node, as the caller will keep using the root node reference (t or t2 in your example code).
To solve these issues, you should either create a separate Tree class, or agree that deleteNode returns the root node of the tree, which could be a different root than the root on which the call was made (when the root node was deleted), or even None when that was the last node of the tree.
Here is how that would look:
def deleteNode(self,val):
if self.data > val:
if self.left:
self.left = self.left.deleteNode(val)
elif self.data < val:
if self.right:
self.right = self.right.deleteNode(val)
else:
if self.left is None:
return self.right
elif self.right is None:
return self.left
else:
largest = self.left.findMax()
self.data = largest
self.left = self.left.deleteNode(largest)
return self
To do it right, you would need to use the return value from this method, for example:
t1 = t1.deleteNode(34)
NB: In some methods you check whether self.data is None. I understand this is some special condition for indicating that the root node is not really a node, and should be considered an empty tree, but this is not a nice pattern. Instead, an empty tree should be just None, or you should define another Tree class which has a root attribute which can be None.

Error on checking if a tree is a Binary Search Tree

I am currently trying to check if a tree is a BST, while keeping notice of the fact that the values must not be equal to any other one in the tree. I tried keeping count of the interval on which each value should be ( considering a min and a max as arg[0] and arg[1]).
If we are for example going all the way down on the left subtree, there will be no min, only a max. However, when we switch to the right, we will also have a minimum ( the value of the root node we just switched right from).
However, my code is not showing the right answer and i have no idea why. Could you please help me?
These are my functions: ( i am resolving this on hackerrank therefore that's why i have two functions instead of one)
""" Node is defined as
class node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
"""
def check_binary_search_tree_(root):
check_bst(root,None,None)
def check_bst(root,*arg):
res, res2 = True, True
if arg[0] is None and arg[1] is not None:
if root.data >=arg[1]:
return False
elif arg[1] is None and arg[0] is not None:
if root.data <= arg[0]:
return False
elif arg[1] is not None and arg[0] is not None and (root.data<=arg[0] or root.data >= arg[1]):
return False
if root.left:
res = check_bst(root.left, arg[0], root.data)
if root.right:
res2= check_bst(root.right, root.data, arg[1])
if not res or not res2:
return False
return True
Your problem here is that you don't have the check_binary_search_tree_ function that HackerRank calls returning anything. Instead of this
def check_binary_search_tree_(root):
check_bst(root,None,None)
you should be doing this
def check_binary_search_tree_(root):
return check_bst(root,None,None)

Insertion into a Binary Search Tree

This is the code I came up with to insert a new value into a BST:
class BST(object):
def __init__(self, root):
self.root = Node(root)
def insert(self, new_val):
self.__internal_insert(self.root, new_val)
def __internal_insert(self, node, new_val):
if node is None:
node = Node(new_val)
elif new_val < node.value:
self.__internal_insert(node.left, new_val)
else:
self.__internal_insert(node.right, new_val)
# Set up the tree
tree = BST(4)
# Insert elements
tree.insert(2)
tree.insert(1)
tree.insert(3)
tree.insert(5)
however, while debugging I noticed that the self.root is never updated, eg.: as soon as the __internal_insert() method finishes and a new insert() is performed, its sibling nodes left and right are back to None instead to the previous value that was set.
Hope you help me spot where the bug is. I picked up Python recently, my apologizes if this is a trivial question.
You defined node = Node(new_val), but then where do you ever attach that node to it's parent?
Basically, you recurse, but never captured the results you're building
Try returning the node you created
def __internal_insert(self, node, new_val):
if node is None:
node = Node(new_val)
elif new_val < node.value:
node.left = self.__internal_insert(node.left, new_val)
else:
node.right = self.__internal_insert(node.right, new_val)
return node
I see two issues with the code.
First, when you reassign node, it is not assigning the value to the BST object. To do that, you need to reference it directly: self.left = Node(new_val).
Second, you're not checking the equals condition, so your code isn't going to work like a traditional BST. You'll end up with a lot of extraneous nodes.

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.

Simple Tree Traversal in Python: Help me debug

This is how I would traverse a binary tree in Python
def binary_tree(root):
if root.left:
binary_tree(root.left)
print root
if root.right:
binary_tree(root.right)
if I need to return the traversed path:
def binary_tree(node, path):
if root.left:
binary_tree(root.left)
path.append(root)
if root.right:
binary_tree(root.right)
return path
Okay, easy enough. I am confident in tree traversals, so I try the following.
def nary_tree(root, value):
"""return True if there is a node with value exists in root"""
if not root: #empty tree
return False
if root.left:
nary_tree(root.left, value)
if root.data == value: #recurse up until the current node has a right child
return True
if root.right:
nary_tree(root.right, value)
return False
This does not return True when it should. So I try to debug, stepping into the function. I realize that I am not supposed to escape a recursion just by returning a value. The above code will return True once and False many times, in case there is a matching node, and I will almost always get a False. So I try the following:
def nary_tree(root, value):
"""return True if there is a node with value exists in root"""
if not root: #empty tree
return False
if root.left:
return nary_tree(root.left, value)
if root.data == value:
#but in this case, this is never executed
return True
if root.right:
return nary_tree(root.right, value)
return False #how was this being executed in above example then?
Questions:
What am I misunderstanding?
How would you fix the above code?
I have been fairly comfortable at writing recursive functions, but I seem to be still confused.
Even if the current node has the data, if it has a left node, you are returning from the function. Ideally, this should have been like this
def nary_tree(root, value):
"""return True if there is a node with value exists in root"""
if not root: #empty tree
return False
if root.data == value:
return True
if nary_tree(root.left, value):
return True
if nary_tree(root.right, value):
return True
return False #how was this being executed in above example then?

Categories