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

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)

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)

Why is my helper method not activating recursively?

I have a Binary Search Tree and I am trying to trace recursively in order through the tree and append each key,value to a list. It is only appending the first key,value to the list and not going through the list in order. I pasted my code below, along with the test code I used at the bottom. Any help on how to get past this issue is super appreciated!
class TreeMap:
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.left = None
self.right = None
def __init__(self):
self.root = None
self.numsearches = 0
self.numcomparisons = 0
def add(self, newkey, newvalue):
newkey = newkey.lower()
if self.root == None:
self.root = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(self.root, newkey, newvalue)
def add_helper(thisnode, newkey, newvalue):
if newkey <= thisnode.key:
if thisnode.left == None:
thisnode.left = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(thisnode.left, newkey, newvalue)
else:
if thisnode.right == None:
thisnode.right = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(thisnode.right, newkey, newvalue)
def print(self):
TreeMap.print_helper(self.root, 0)
def print_helper(somenode, indentlevel):
if somenode == None:
print(" "*(indentlevel),"---")
return
if not TreeMap.isleaf(somenode):
TreeMap.print_helper(somenode.right, indentlevel + 5)
print(" "*indentlevel + str(somenode.key) + ": " +str(somenode.value))
if not TreeMap.isleaf(somenode):
TreeMap.print_helper(somenode.left, indentlevel + 5)
def isleaf(anode):
return anode.left == None and anode.right == None
def listify(self, whichorder="in"):
'''
Returns a list consisting of all the payloads of the tree. (This returns a plain old Python List.)
The order of the payloads is determined by whichorder, which defaults to inorder.
The other possibilities are "pre" and "post".
If the tree is empty, return the empty list.
'''
assert type(whichorder) is str,"Whichorder is a string, and can only be pre, in or post"
assert whichorder in ["pre","in","post"],"Whichorder is a string, and can only be pre, in or post"
return TreeMap.listify_helper(self.root, whichorder)
def listify_helper(somenode, whichorder):
order_list = []
if somenode == None:
return order_list
elif somenode != None and whichorder == 'in':
TreeMap.listify_helper(somenode.left, 'in')
order_list.append(somenode.key+ '='+somenode.value)
TreeMap.listify_helper(somenode.right, 'in')
return order_list
TEST CODE:
import treemap
translator = treemap.TreeMap()
translator.add("cat", "Katze")
translator.add("bird", "Vogel")
translator.add("dog", "Hund")
translator.add("snake", "IDK")
translator.add("bear", "IDK")
translator.add("octopus", "Tintenfisch")
translator.add("horse", "Pferd")
translator.add("zebra", "IDK")
translator.print()
print("---------------------------------------------------")
print (translator.listify())
The problem is here:
def listify_helper(somenode, whichorder):
order_list = []
This function initialises its own local order_list every time it is invoked. Pass order_list as a parameter instead so that the same list is appended to by each recursive invocation.
Alternatively, append each element of the result of the recursive calls of listify_helper to order_list, although this approach could result in unneeded copying.

how does __contains__ method work in binary search trees 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__

Maximum recursion with large lists

I am making a binary tree with a very large list, almost 10000 objects. The issue is that I get a maximum recursion error due to the huge size. It happens specifically in the binarytree class where TreeNode is being called to create new objects. I am unsure how to implement this without recursion, as it seems to be the easiest way to implement the code.
class TreeNode:
def __init__(self,key,val,left=None,right=None,parent=None):
self.key = key
self.payload = val
self.leftChild = left
self.rightChild = right
self.parent = parent
def hasLeftChild(self):
return self.leftChild
def hasRightChild(self):
return self.rightChild
def isLeftChild(self):
return self.parent and self.parent.leftChild == self
def isRightChild(self):
return self.parent and self.parent.rightChild == self
def isRoot(self):
return not self.parent
def isLeaf(self):
return not (self.rightChild or self.leftChild)
def hasAnyChildren(self):
return self.rightChild or self.leftChild
def hasBothChildren(self):
return self.rightChild and self.leftChild
Binary Tree:
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.size
def put(self,key,val):
if self.root:
self._put(key,val,self.root)
else:
self.root = TreeNode(key,val)
self.size = self.size + 1
def _put(self,key,val,currentNode):
if key < currentNode.key:
if currentNode.hasLeftChild():
self._put(key,val,currentNode.leftChild)
else:
currentNode.leftChild = TreeNode(key,val,parent=currentNode)
else:
if currentNode.hasRightChild():
self._put(key,val,currentNode.rightChild)
else:
currentNode.rightChild = TreeNode(key,val,parent=currentNode)
def __setitem__(self,k,v):
self.put(k,v)
def get(self,key):
if self.root:
res = self._get(key,self.root)
if res:
return res.payload
else:
return None
else:
return None
def _get(self,key,currentNode):
if not currentNode:
return None
elif currentNode.key == key:
return currentNode
elif key < currentNode.key:
return self._get(key,currentNode.leftChild)
else:
return self._get(key,currentNode.rightChild)
def __getitem__(self,key):
return self.get(key)
def __contains__(self,key):
if self._get(key,self.root):
return True
else:
return False
It is fairly simple to convert your recursive methods to iterative ones, e.g.:
def get(self, key):
node = self.root
while node:
if node.key == key:
return node.payload
elif key < node.key:
node = node.leftChild
else:
node = node.rightChild
return None
def put(self, key, val):
if not self.root:
self.root = TreeNode(key, val)
else:
self._put(key, val, self.root)
self.size = self.size + 1
def _put(self, key, val, currentNode):
while True:
if key < currentNode.key:
if currentNode.hasLeftChild():
currentNode = currentNode.leftChild
else:
currentNode.leftChild = TreeNode(key, val, parent=currentNode)
break
else:
if currentNode.hasRightChild():
currentNode = currentNode.rightChild
else:
currentNode.rightChild = TreeNode(key, val, parent=currentNode)
break
This gets rid of any recursion (limits) and is just as readable.

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)

Categories