how does __contains__ method work in binary search trees Python? - python

I have two classes, Node() and binarySearchTree().
Node() has the attributes:
self.left= None
self.right= None
self.key= key
self.data = data
And binarySearchTree() has methods for inserting, searching and printing the binary search tree (BST). I must also include a __contains__ method for my BST, which enables me to write something like:
tree= Bintree()
tree.store("table")
if "table" in tree: <--
do something <--
It complains about the last two "__contains__" that they're not defined. But I'd like it to work recursively. But it's not working.
def __contains__(self, key):
if self.root == None:
return False
elif key== self.root.key:
return True
elif key < self.root.key:
return __contains__(self.root.key.left,key)
elif key > self.root.key:
return __contains__(self.root.key.right,key)

__contains__ is not a global variable; it's a class attribute, and so must be accessed via BinTree or one of its instances. At the very least, you need to write
def __contains__(self, key):
if self.root == None:
return False
elif key == self.root.key:
return True
elif key < self.root.key:
return BinTree.__contains__(self.root.left, key)
elif key > self.root.key:
return BinTree.__contains__(self.root.right, key)
(Note that the key attribute isn't needed in the first argument; it's self.root itself, not its key, that has left and right attributes.
However, this is just a non-standard way of calling an instance attribute that prevents inherited from working correctly. It will also fail if you change the name of the class without updating the definition of the method to use the new name. The next best thing would be to invoke the method normally.
def __contains__(self, key):
if self.root == None:
return False
elif key == self.root.key:
return True
elif key < self.root.key:
return self.root.left.__contains__(key)
elif key > self.root.key:
return self.root.right.__contains__(key)
But best of all is to not call __contains__ directly, but use to use in, which will invoke __contains__ for you.
def __contains__(self, key):
if self.root == None:
return False
elif key == self.root.key:
return True
elif key < self.root.key:
return key in self.root.left
else: # key > self.root.key is the only option left
return key in self.root.right
WARNING: All of the above assumes that self.root.left and self.root.right exist and are not None, an assumption that may not be accurate but cannot be confirmed without code showing how a BinTree is constructed.

If you have separate tree and node types, you want two functions, one of them recursing through the nodes and the other just to get things going.
Something like this:
def __contains__(self, key):
returns self.node_contains(self.root, key)
def node_contains(self, node, key):
if node == None:
return False
elif key == node.key:
return True
elif key < node.key:
return self.node_contains(node.left, key)
elif key > node.key:
return self.node_contains(node.right, key)
or, you could divide the work between the classes, which could look like
In the tree class:
def __contains__(self, key):
return self.root and key in self.root
In the node class:
def __contains__(self, key):
return self.key == key
or (key < self.key and self.left and key in self.left)
or (self.right and key in self.right)

Trivial fix
1 def __contains__(self, key):
2 if self.root == None:
3 return False
4 elif key== self.root.key:
5 return True
6 elif key < self.root.key:
7 return self.__contains__(self.root.key.left,key)
8 elif key > self.root.key:
9 return self.__contains__(self.root.key.right,key)
just call self.__contains__

Related

Asking how to insert a new node to BST? Python

I am doing my practice, and the practice request create DSATreeNode and DSABinarySearchTree classes. The DSATreeNode is working fine, but when I use the function of insertRec. The insert function will call the insertRec that store the node in the right place. The problem comes is it is not storing and there is nothing in new node. Also the self._root is None, never insert anything into it.
Here's my code
class DSATreeNode:
def __init__(self, inKey, inValue):
self._key = inKey
self._value = inValue
self._left = self._right = None
class DSABinarySearchTree:
def __init__(self):
self._root = None
def find(self, key):
return self._findRec(key, self._root)
def _findRec(self, key, cur):
value = None
if cur == None: # Base case: not found
raise Exception("Key " + key + " not found")
elif key == cur._key: # Base case: found
value = cur._value
elif key < cur._key: # Go left (recursive)
value = self._findRec(key, cur._left)
else: # Go right(recursive)
value = self._findRec(key, cur._right)
return value
def insert(self, inKey, inValue):
return self.insertRec(inKey, inValue, self._root)
def insertRec(self, key, value, curNode):
createNode = DSATreeNode(key, value)
if curNode == None:
curNode = createNode
elif key < curNode._key:
curNode._left = self.insertRec(key, value, curNode._left)
else:
curNode._right = self.insertRec(key, value, curNode._right)
def getRoot(self):
return self._root._key, self._root._value
A few issues:
_insertRec does not return a node. It should have return curNode as its last statement.
There is no code that assigns a node to self._root. The insert method should assign like this: self._root = self.insertRec(inKey, inValue, self._root).
The error message generated in _findRec assumes that key is a string, but if it isn't, then it will fail. Better do raise Exception("Key " + str(key) + " not found") or raise Exception(f"Key {key} not found")
Not blocking, but _insertRec should not create a node when it still is going to make a recursive call. So move that first line into the first if block:
if curNode == None:
curNode = DSATreeNode(key, value)

NameError: name 'heigth' is not defined

I am inexperienced in python.
I'm doing a college activity and I wrote a class to find the height of a binary tree.
But when I'm going to call the function recursively I have the message:
NameError Traceback (most recent call last)
<ipython-input-5-109fbd93416e> in <module>
7 raiz.insert(3)
8
----> 9 heigth(raiz)
NameError: name 'heigth' is not defined
The function is :
def heigth(self, n:"Node")-> int:
if n:
return 1
else:
left = heigth(n.left)
right = heigth(n.right)
if(left < right):
return right + 1
else:
return left + 1
All code:
from typing import List
class Node:
def __init__(self, key, left:"Node"=None, right:"Node"=None):
self.key = key
self.left = left
self.right = right
def print_tree(self):
"""
Prints the tree from the current node
"""
if self.left:
self.left.print_tree()
print(self.key, end=" ")
if self.right:
self.right.print_tree()
def insert(self, key) -> bool:
"""
Insert a node in the tree that has the key "key"
"""
if key < self.key:
if self.left:
return self.left.insert(key)
else:
self.left = Node(key)
return True
elif key > self.key:
if self.right:
return self.right.insert(key)
else:
self.right = Node(key)
return True
else:
return False
def search(self, key) -> bool:
"""
Returns true if the key exists in the tree
"""
if key < self.key:
if self.left:
return self.left.search(key)
elif key > self.key:
if self.right:
return self.right.search(key)
else:
return True
return False
def to_sorted_array(self, arr_result:List =None) -> List:
"""
Returns a vector of the ordered keys.
arr_result: Parameter with the items already added.
"""
if(arr_result == None):
arr_result = []
if self.left:
self.left.to_sorted_array(arr_result)
arr_result.append(self.key)
if self.right:
self.right.to_sorted_array(arr_result)
return arr_result
def max_depth(self,current_max_depth:int=0) -> int:
"""
calculates the greatest distance between the root node and the leaf
current_max_depth: Value representing the longest distance so far
when calling for the first time, there is no need to use it
"""
current_max_depth = current_max_depth +1
val_left,val_right = current_max_depth,current_max_depth
if self.left:
val_left = self.left.max_depth(current_max_depth)
if self.right:
val_right = self.right.max_depth(current_max_depth)
if(val_left>val_right):
return val_left
else:
return val_right
def position_node(self, key, current_position:int=1) -> int:
"""
Returns the position of the desired node in the tree
current_position: represents the position of the tree at that moment
when calling for the first time, there is no need to use it
"""
if key < self.key:
if self.left:
return self.left.position_node(key, current_position*2)
elif key > self.key:
if self.right:
return self.right.position_node(key, current_position*2+1)
else:
return current_position
def heigth(self, n:"Node")-> int:
if n:
return 1
else:
left = heigth(n.left)
right = heigth(n.right)
if(left < right):
return right + 1
else:
return left + 1
You are using method of a class, but when you refer to it just as a heigth it looks for the method not in a class of the object, but on a module level where it can't find it, hence the error.
Try replacing heigth calls with self.heigth, so that method of a class is called.
You cannot call the function in classes you must call the class first using self than the function:
left = self.height(n.left)
right = self.height(n.right)
You can make height a static method of Node.
You have to call the height method with the raiz instance as argument.
class Node:
# ...
#staticmethod
def height(n:"Node")-> int:
return 1 + max(self.height(n.left), self.height(n.right)) if n else 0
raiz.insert(3)
print(Node.height(raiz))
Or make it a recursive method
class Node:
# ...
def _height(self, n:"Node") -> int:
return n.height() if n else 0
def height(self) -> int:
return 1 + max(self._height(self.left), self._height(self.right))
raiz.insert(3)
print(raiz.height())

Defining Search of an RB Tree

def Search(root,key):
if root is None:
return 0
if(root.val == key):
return 1
if(root.val < key):
Search(root.right,key)
elif(root.val > key):
Search(root.left,key)
Above is a Python code that is supposed to return 1 if the given node exists in the Red-Black Tree and 0 if it doesn't. So the goal is, in the main() function, I will write
x = int(input())
print("Found") if Search(root,x)==1 else print("not found")
where x is the node to be checked.
Unfortunately, Search(root,x) is of return type "None" and I don't know how to fix this.
You just forgot the return keyword for the two recursive calls.
def Search(root,key):
if root is None:
return 0
if(root.val == key):
return 1
if(root.val < key):
return Search(root.right,key)
elif(root.val > key):
return Search(root.left,key)

Python Recusrive Method returns NoneType [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 years ago.
So, (It's about the search method), the method is recursive but when I try to return my self.key and self.value, the functions returns a NoneType, how can I fix this?
(There is more to the class, but this is the relevant part, the other parts of code have no effect on this part)
I've seen other solutions where you have to return the whole method (In my case that would be: return search(self, key) ) but those just give me an infinite loop
class BinairySearchTree:
def __init__(self, key=None, value=None, lefttree=None, righttree=None):
self.key = key
self.value = value
self.lefttree = lefttree
self.righttree = righttree
def insert(self, key, value):
if self.key != None:
if key > self.key:
if self.righttree != None:
self.righttree.insert(key, value)
else:
self.righttree = BinaireZoekBoom(key, value)
elif key == self.key:
self.key = key
self.value = value
elif key < self.key:
if self.lefttree != None:
self.lefttree.insert(key, value)
else:
self.lefttree = BinaireZoekBoom(key, value)
elif self.key == None:
self.key = key
self.value = value
def search(self, key):
if key > self.key:
self.righttree.search(key)
elif key == self.key:
return self.key, self.value
elif key < self.key:
self.lefttree.search(key)
I think I just saw the problem: your search function doesn't propagate the found node up the tree. You have to return a value at every level to get the result back to the original caller.
def search(self, key):
if key > self.key:
return self.righttree.search(key)
elif key == self.key:
return self.key, self.value
elif key < self.key:
return self.lefttree.search(key)

Python: global name "treeInsert" is not defined - recursive

I have the following code:
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
def treeInsert(rootnode, key):
if rootnode is None:
return Node(key)
if rootnode.key == key:
return rootnode
elif key < rootnode.key:
rootnode.left = treeInsert(rootnode.left, key)
else:
rootnode.right = treeInsert(rootnode.right, key)
return rootnode
If I now want to use the treeInsert method, I get the following error:
NameError: global name 'treeInsert' is not defined.
treeInsert is not a global name, but a method of the Node class. As written, you should make it a static method, and refer to it as Node.treeInsert.
#staticmethod
def treeInsert(rootnode, key):
if rootnode is None:
return Node(key)
if rootnode.key == key:
return rootnode
elif key < rootnode.key:
rootnode.left = Node.treeInsert(rootnode.left, key)
else:
rootnode.right = Node.treeInsert(rootnode.right, key)
return root node
Better yet, make it a proper instance method, something like
def treeInsert(self, key):
if self.key == key:
return key
elif key < self.key:
return (self.left or Node(key)).treeInsert(key)
else:
return (self.right or Node(key)).treeInsert(key)

Categories