How to fix "global name --- is not defined error " - python

I created two classes, one for a node object and the other for a BST (binary search tree object). For the binary search tree, I have implemented two methods, one for inserting a given value (new_val) into the correct position in the tree and the other for searching the BST for a node with the given value. To implement these functions, I have created helper functions (i.e. insertRecursive and searchRecursive), which work recursively to attain the function goals. For some reason, when I run the code, I am getting the error "NameError: global name 'insert_Recursive' is not defined" and I am unsure why. Any advice on how to solve the issue would be much appreciated.
class Node(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
class BST(object):
def __init__(self, root):
self.root = Node(root)
def insert(self, new_val):
self.insert_Recursive(self.root, new_val)
def insert_Recursive(self, start, new_val):
if start != None:
if (new_val > start.value):
insert_Recursive(start.right, new_val)
else:
insert_Recursive(start.left, new_val)
else:
start.value = new_val
def search(self, find_val):
return searchRecursive(self.root, find_val)
def searchRecursive(self, start, find_val):
if start != None:
if (find_val == start.value):
return True
elif(find_val > start.value):
searchRecursive(start.right, find_val)
else:
searchRecursive(start.left, find_val)
else:
return False
tree = BST(4)
tree.insert(2)
tree.insert(1)
tree.insert(3)
tree.insert(5)
print tree.search(4)
print tree.search(6)

if (new_val > start.value):
insert_Recursive(start.right, new_val)
Should be
if (new_val > start.value):
self.insert_Recursive(start.right, new_val)

Related

Delete a branch in Binary tree( Linked List implementation)

I am trying to create a binary tree using a linked list. I want to delete a node in a binary tree, the way I implemented is to set the address(pointer) to the branch that I want to delete as None, but when I run the traversal methods, the branch still shows up.
here is my code
class tree:
def __init__(self,val):
self.val=val
self.left=None
self.right=None
def preorder(root):
if root is None:
return
print(root.val)
tree.preorder(root.left)
tree.preorder(root.right)
def inorder(root):
if root is None:
return
tree.inorder(root.left)
print(root.val)
tree.inorder(root.right)
def postorder(root):
if root is None:
return
tree.postorder(root.left)
tree.postorder(root.right)
print(root.val)
def levelorder(root):
if root is None:
return
Q=[]
Q.append(root)
while Q!=[]:
l=len(Q)
for i in range(l):
print(Q[i].val)
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
def search(root,value):
o=[]
o.append(tree.levelorder(root))
if value in o:
return "Found"
else:
return "Not Found"
def insert(root,value,where):
if root is None:
return
Q=[]
Q.append(root)
value=tree(value)
while Q!=[]:
for i in Q:
if i.val==where:
if i.left is not None:
i.right=value
else:
i.left=value
return
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
def delete(root,value):
if root is None:
return
Q=[]
Q.append(root)
value=tree(value)
while Q!=[]:
for i in Q:
if i.left is not None and i.left.val==value:
i.left.val=None
i.left=None
if i.right is not None and i.right.val==value:
i.right.val=None
i.right=None
return
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
and here is how I created the tree
base=tree("drinks")
L=tree("hot")
R=tree("cold")
LL=tree("coffe")
LR=tree("tea")
LRL=tree("w milk")
LRR=tree("wo milk")
base.left=L
base.right=R
L.left=LL
L.right=LR
LR.left=LRL
LR.right=LRR
Now when I run the delete method, the object that is supposed to be deleted still shows up.
tree.delete(base,"w milk")
tree.levelorder(base)
drinks
hot
cold
coffe
tea
ice cream
w milk
wo milk <=== the node i am trying to delete
The main issues:
delete method's while loop will exit immediately, because of the return statement
The value to compare with should not be turned into a node with value=tree(value)
Some remarks on your code:
You'll not be able to ever delete the root node of the tree, since you only check the values of child nodes. In order to allow the root to be deleted, and to represent an empty tree, you should really consider creating a second class. The current class could then be renamed to Node and the new class could become Tree.
It is a common habit to use a capital first letter for class names, while for variable names you would always start with a lower case letter. So not Q, but q.
It is not such good practice to print inside methods of such classes: these methods should just provide tools to iterate over nodes, but they should not print them. Use yield instead.
For instance, search should return the node when it is found and None otherwise. Don't print the result.
The insert method may actually delete node(s) when both the left and right child of the where node are already occupied. It would be better to reject such an insert.
In the OOP pattern, it is widely accepted to call the first argument of instance methods self. In OOP, you would call these methods with the dot notation: so instead of tree.postorder(root.left) you would do root.left.postorder().
You have quite some code repetition: mainly for traversals, and where you use the queue algorithm twice. Try to avoid that.
Here is how you could modify your code to align to these suggestions:
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def traverse(self, kind=0, parent=None):
if kind == 0: # pre-order
yield (self, parent) # don't print in methods
if self.left:
yield from self.left.traverse(kind, self)
if kind == 1: # in-order
yield (self, parent)
if self.right:
yield from self.right.traverse(kind, self)
if kind == 2: # post-order
yield (self, parent)
class Tree:
def __init__(self):
self.root = None # Representing an empty tree
def traversevalues(self, kind=0):
if self.root:
for node, parent in self.root.traverse(kind):
yield node.val
def preorder(self):
yield from self.traversevalues(0)
def inorder(self):
yield from self.traversevalues(1)
def postorder(self):
yield from self.traversevalues(2)
def levelorder(self):
if self.root:
q = [self.root]
while q:
temp = []
for node in q:
yield node.val
if node.left:
temp.append(node.left)
if node.right:
temp.append(node.right)
q = temp
def search(self, value):
if self.root:
return next((edge for edge in self.root.traverse() if edge[0].val == value), None)
def insert(self, value, where=None):
if not where:
if self.root:
raise ValueError("Must call insert with second argument")
else:
self.root = Node(value)
else:
edge = self.search(where)
if edge:
parent = edge[0]
if not parent.left:
parent.left = Node(value)
elif not parent.right:
parent.right = Node(value)
else:
raise ValueError(f"Node {where} already has 2 children")
else:
raise ValueError(f"Node {where} not found")
def deletesubtree(self, value):
edge = self.search(value)
if edge:
node, parent = edge
if parent.left == node:
parent.left = None
else:
parent.right = None
else:
raise ValueError(f"Node {value} not found")
tree = Tree()
tree.insert("drinks")
tree.insert("hot", "drinks")
tree.insert("cold", "drinks")
tree.insert("coffee", "hot")
tree.insert("tea", "hot")
tree.insert("with milk", "tea")
tree.insert("without milk", "tea")
print(*tree.levelorder())
tree.deletesubtree("without milk")
print(*tree.levelorder())

Binary Search Tree inorder not working (python)

I've been messing around learning about objects and classes, and as I finally felt that I managed to wrap my head around how to construct a Binary Search Tree in python, I ran into an issue. Here's my code:
class node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def add(self,current,value):
if self.root == None:
self.root = node(value)
else:
if value < current.value:
if current.left == None:
current.left = node(value)
else:
self.add(current.left,value)
if value > current.value:
if current.right == None:
current.right = node(value)
else:
self.add(current.right,value)
def visit(self,node):
print(node.value)
def inorder(self,current):
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Tree = BST()
root = node(2)
Tree.root = root
Tree.add(Tree.root,7)
Tree.inorder(Tree.root)
after running the code, I got an error: AttributeError: 'NoneType' object has no attribute 'left'.
The error comes out of the inorder function, as apparently the value I'm inserting into the function is an object without a type.
as you can see, the root of the tree is a node object, so it should have the attribute "left" as per coded in the class. I would really appreciate if someone could help me with what I'm getting wrong.
Thanks in advance!
EDIT: I should note that I checked whether the root is a node with the isinstance(), function, and indeed it returned True.
I think you sould check current is not None before access its left and right.
def inorder(self, current):
if current:
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Your design has some problems. The Tree should be the only object that knows about the root. You shouldn't have to pass the root in. Notice how this is simpler to use:
class node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def add(self,value,current=None):
if not self.root:
self.root = node(value)
return
if not current:
current = self.root
if value < current.value:
if not current.left:
current.left = node(value)
else:
self.add(value,current.left)
else:
if not current.right:
current.right = node(value)
else:
self.add(value, current.right)
def visit(self,node):
print(node.value)
def inorder(self,current=-1):
if current == -1:
current = self.root
if not current:
return
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Tree = BST()
Tree.add(2)
Tree.add(7)
Tree.inorder()

How can I run this Height of a BST tree function

can someone help me out with this? I implemented a binary search tree data structure in python and I wrote a BST_height() function to calculate the height of the tree. But when I ran my code, It gave me an error saying 'self is not defined'. I know why the error is showing up but can you suggest some other way to run the BST_height function with the root node
class Node:
def __init__(self, data=None):
self.data = data
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = Node()
def display(self):
print('''
{}
/ \\
{} {}
/ \\ / \\
{} {} {} {}
BINARY TREE
'''.format(tree.root.data, tree.root.left.data, tree.root.right.data, tree.root.left.left.data, tree.root.right.right.data, tree.root.left.right.data, tree.root.right.left.data))
def checkRoot(self):
if self.root.data != None:
return 'Root node exists'
else:
return 'Root node doesn\'t exists'
def insert(self, data):
newNode = Node(data)
if self.root.data == None:
# creating the root node
self.root = newNode
else:
self.insertNode(data, self.root)
def insertNode(self, data, curNode):
if data < curNode.data:
if curNode.left == None:
curNode.left = Node(data)
else:
self.insertNode(data, curNode.left)
elif data > curNode.data:
if curNode.right == None:
curNode.right = Node(data)
else:
self.insertNode(data, curNode.right)
else:
print('The value already exists ha ha')# funny
def BST_height(self, node):
if node == None:
return -1
leftHeight = height(node.left)
rightHeight = height(node.right)
return max(leftHeight, rightHeight) + 1
tree = BinarySearchTree()
tree.insert(30)# root node
tree.insert(24)
tree.insert(45)
tree.insert(90)
tree.insert(18)
tree.insert(28)
tree.insert(40)
tree.display()
# getting an error here
# I know self.root can\'t be used outside the class but can you suggest some other way tree.BST_height(self.root)
There are 2 problems with the code:
Self is something you use inside of class functions. Outside you can simply use the object variable. like so:
tree.BST_height(tree.root)
BST_height function has a small error in it. It calls height instead of self.BST_height:
def BST_height(self, node):
if node == None:
return -1
leftHeight = self.BST_height(node.left)
rightHeight = self.BST_height(node.right)
return max(leftHeight, rightHeight) + 1
You might want to read this for clarity on the whole self topic.

Binary Search Tree (Python) not showing result

I'm somewhat new to Python and need help with an issue I'm facing. I'm trying to make a binary search tree. I've written a code and it works, but won't show any result (printed values). I can't figure out what the issue might be. Here is the entire code:
class Node:
def __init__(self, value):
self.value = value
self.left_child = None
self.right_child = None
class binary_search_tree:
def __init__(self):
self.root_node = None
def insert(self, value, curr_node):
if self.root_node == None:
self.root_node == node(value)
elif self.root_node < value:
if self.right_child == None:
self.right.child = value
else:
curr_node == self.right_child
if curr_node < value:
curr_node.right_child = node(value)
elif curr_node > value:
curr_node.left_child = node(value)
else:
print("Error! Value Already Exists!")
elif self.root_node > value:
if self.left_child == None:
self.left.child = value
else:
curr_node == self.left_child
if curr_node < value:
curr_node.right_child = node(value)
elif curr_node > value:
curr_node.left_child = node(value)
else:
print("Error! Value Already Exists!")
else:
print("Error! Value Already Exists!")
def fill_Tree(tree, num_elems = 100, max_int = 1000):
from random import randint
for x in range (num, elems):
curr_elem = randint(0, max_int)
tree.insert(curr_elem)
return tree
I have made a class Node to handle the nodes and a function insert that helps to insert the values. It check for the root node. If its there, it moves onto the leaf based on the values. If not, it adds the value as the root. The program keeps on checking for values and nodes and their differences (less than, greater than etc), just the ways a tree is supposed to function. The program executes, but nothing shows up. Not sure what I'm doing wrong though.
Any sort of help would be appreciated!
Thanks.
If that is your entire code, and if the input and execution is perfect, it would not show any result, because you are not printing any result.
You don't have an apparent main function to create an object of the class binar_search_tree.
The print statements that you have are only when there is an error. If everything works perfectly, your code doesn't print anything
You would need a method that can display the the tree
Currently, your insertion method is assigning values to the left or right children of the root, not traveling to a depth beyond those two nodes, should a value smaller than the left child or greater than the right child be found. Instead, create one class to store the value, left, and right child, along with the necessary insertion method. To determine if a value exists in the tree, it is cleaner to utilize __getitem__ with recursion:
def check_val(f):
def wrapper(cls, _val):
if _val in cls.__class__.seen:
raise ValueError(f"'{_val}' already in '{cls.__class__.__name__}'")
return f(cls, _val)
return wrapper
class Tree:
seen = []
def __init__(self, value=None):
self.left = None
self.value = value
self.right = None
def __lt__(self, _node):
return self.value < getattr(_node, 'value', _node)
#check_val
def insert_val(self, _val):
if self.value is None:
self.value = _val
self.__class__.seen.append(_val)
else:
if _val < self.value:
if self.left is None:
self.left = Tree(_val)
Tree.seen.append(_val)
else:
self.left.insert_val(_val)
else:
if self.right is None:
self.right = Tree(_val)
Tree.seen.append(_val)
else:
self.right.insert_val(_val)
def __getitem__(self, val):
if self.value == val:
return True
if val < self.value:
return getattr(self.left, '__getitem__', lambda _:False)(val)
return getattr(self.right, '__getitem__', lambda _:False)(val)
#classmethod
def load_tree(cls, size = 10):
_t = cls()
import random
for _ in range(size):
_t.insert_val(random.randint(1, 100))
return _t
To run:
t = Tree.load_tree()
print(t.__class__.seen)
#[82, 94, 33, 59, 73, 72, 96, 14, 58, 67]
for i in t.__class__.seen:
assert t[i]
print('all cases passed')
Output:
'all cases passed'

Recursion and return statements in python

I am trying to implement a 2-3 tree but I am having trouble with the find method.
This method given an int as parameter should return the node that contains the int.
The problem is that sometimes it works, sometimes it does't and I don't know why.
I have added a test print. For a particular int that I know for sure that is part of the tree, the code executes the print statement, meaning that it has found the node, but does not return this node. Instead it return False which is at the end of the code.
Can you help me solving this ?
def find(self,data,node=0): #return problem ???
if node==0:
a=self.root
else:
a=node
if a.data2==None:
if data==a.data: ### here is the problem
print("qwertyuiop") ### it does not execute the return statement
return a
elif data < a.data:
if a.left!=None:
return self.find(data,a.left)
elif data > a.data:
if a.right!=None:
return self.find(data,a.right)
else:
if a.data2!=None:
if (data==a.data or data==a.data2):
return a
elif data<a.data:
if a.left!=None:
return self.find(data,a.left)
elif (data>a.data and data<a.data2):
if a.middle!=None:
return self.find(data,a.middle)
elif data>a.data2:
if a.right!=None:
return self.find(data,a.right)
print("Not Found") ### function executes this print
return False
self.root is the root of the tree and is an object of the following class
class Node:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.data2 = None
self.data3 = None
self.left = left
self.right = right
self.middle = None
self.middle2 = None
Binary Search Tree:
class Nodeee:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
class BST:
def __init__(self, root=None):
self.c=[]
self.total=0
self.root = None
def parent(self,data,node=5):
def search(nodee,cc,data):
if data==cc.data:
return nodee
else:
if data<cc.data:
nodee=cc
return search(nodee,cc.left,data)
elif data>cc.data:
nodee=cc
return search(nodee,cc.right,data)
print("Parent Error")
return False
if node==self.root:
print("Root has no parent")
else:
a=self.root
c=self.root
return search(a,c,data)
def lookup(self,data,node=0):
if node==0:
a=self.root
else:
a=node
if data < a.data:
if a.left==None:
return a
else:
return self.lookup(data,a.left)
elif data > a.data:
if a.right==None:
return a
else:
return self.lookup(data,a.right)
def find(self,data,node=0):
if node==0:
a=self.root
else:
a=node
if data==a.data:
print("WTF")
return a
elif data < a.data:
if a.left!=None:
return self.find(data,a.left)
elif data > a.data:
if a.right!=None:
return self.find(data,a.right)
print("Not Found")
return False
def find2(self,data,node=0):
if node==0:
a=self.root
else:
a=node
if data==a.data:
return True
elif data < a.data:
return self.find2(data,a.left)
elif data > a.data:
return self.find2(data,a.right)
return False
def is_empty(self):
if self.root==None:
return True
def is_leaf(self,n):
if (n.left==None and n.right==None):
return True
return False
def delete(self):
self.root=None
def insert(self, data):
if self.root==None:
self.root=Nodeee(data)
self.total+=1
return True
else:
b=self.lookup(data)
if data < b.data:
b.left=Nodeee(data)
self.total+=1
return True
elif data > b.data:
b.right=Nodeee(data)
self.total+=1
return True
print("Insert Error !")
return False
def inorder_swap(self,data):
a=self.find(data)
b=a.right
while self.is_leaf(b)!=True:
if b.left!=None:
b=b.left
elif b.left==None:
b=b.right
temp=a.data
a.data=b.data
b.data=temp
def remove(self,data):
a=self.find(data)
if self.is_leaf(a)==True:
b=self.parent(data)
if b.left==a:
b.left=None
elif b.right==a:
b.right=None
elif self.is_leaf(a)==False:
if a.left==None:
b=self.parent(data)
if b.left==a:
b.left=b.left.right
elif b.right==a:
b.right=b.right.right
elif a.right==None:
b=self.parent(data)
if b.left==a:
b.left=b.left.left
elif b.right==a:
b.right=b.right.left
elif (a.left!=None and a.right!=None):
self.inorder_swap(data)
self.remove(data)
def inorder(self,node):
if node!=None:
self.inorder(node.left)
self.c.append(node.data)
self.inorder(node.right)
def inorder_print(self):
self.c=[]
self.inorder(self.root)
print("\nStart")
for x in range(len(self.c)):
print(self.c[x], end=",")
print("\nFinish\n")
a=BST()
print(a.insert(234)==True)
print(a.insert(13)==True)
print(a.insert(65)==True)
print(a.insert(658)==True)
print(a.insert(324)==True)
print(a.insert(86)==True)
print(a.insert(5)==True)
print(a.insert(76)==True)
print(a.insert(144)==True)
print(a.insert(546)==True)
print(a.insert(2344)==True)
print(a.insert(1213)==True)
print(a.insert(6345)==True)
print(a.insert(653348)==True)
print(a.insert(35324)==True)
print(a.insert(8463)==True)
print(a.insert(5555)==True)
print(a.insert(76539)==True)
print(a.insert(14499)==True)
print(a.insert(59999946)==True)
a.inorder_print()
a.remove(35324)
a.remove(1213)
a.remove(2344)
a.remove(144)
a.remove(5555)
a.remove(6345)
a.remove(59999946)
a.remove(76)
print(a.root.data)
a.inorder_print()
def inorder_swap(self,data):
a=self.find(data)
b=a.right
while self.is_leaf(b)!=True:
if b.left!=None:
b=b.left
elif b.left==None:
b=b.right
temp=a.data
a.data=b.data
b.data=temp
a here is the node containing the passed data. This method does nothing else than swapping a's data with some leaf's data (first one while finds), thereby distorting the tree order. A follow-up find on the same data therefore fails and returns False. Since your code has no error checks, this results in an AttributeError.
You probably want to move nodes around in inorder_swap. However you only assign to the local name b. If you want to change nodes, then you need to use b.left = or b.right =.
It might be that there are more problems, that I don't see right now.
Also your code has several style problems, some of them:
You have four functions doing the same: find, find2, lookup and search in parent.
Most of the naming is not informative or even confusing.
Lines like if a.right==None: should be written as if not a.right: (or maybe if a.right is None:).
Check the return value of functions and don't just assume they return a valid node if they might not (i.e. find might return False instead of a node). Or alternatively use exception handling.
If you have an if ... elif ... elif block you don't have to check the last possibility if it is sure to be true, for example:
if b.left!=None:
# something
elif b.left==None:
# something else
should be
if b.left:
# something
else:
# something else

Categories

Resources