I am attempting to create a simple version of spell check which takes a .txt file and compares whether each word is found in the dictionary or not. I have established functions that turn .txt files into lists and the dictionary into a list, but I am struggling calling upon my sorted binary search tree for the dictionary in my spell check function. Here is the class for BinarySearchTree followed by my spell checker function
class BinarySearchTree:
def __init__(self):
self.root = None
def insert(self,val):
if self.root == None:
self.root = BinaryNode(val)
else:
self.recursive_insert(root,val)
def recursive_insert(self,parent,val):
if parent.data < val:
if parent.right != None:
self.recursive_insert(parent.right,val)
else:
parent.right = BinaryNode(val)
else:
if parent.left != None:
self.recursive_insert(parent.left,val)
else:
parent.left = BinaryNode(val)
def dictionary_insert(self,text):
for word in text:
self.insert(word)
def search(self,val):
if self.recursive_search(self.root,val) != None:
return True
else:
return False
def recursive_search(self,parent,val):
if parent.data == val:
return parent
elif parent.data > val:
return self.recursive_search(parent.left,val)
else:
return self.recursive_search(parent.right,val)
Here is my spell checker function:
def spell_checker(text):
N = len(text)
misspelled = 0
for i in range(N):
if BinarySearchTree().search(text[i]) == True:
misspelled = misspelled
else:
misspelled = misspelled + 1
print text[i]
if misspelled == 0:
print "There are no spelling errors!"
Any help would be greatly appreciated.
When you first call recursive_search, you pass self.root as parent. However, in __init__, self.root was set to None. Therefore trying to access parent.data gives you an error, as None.data doesn't exist. You need to do a dictionary_insert, passing in a list of valid words, as part of your setup procedure, so that the tree actually has words in it:
dct = BinarySearchTree()
dct.dictionary_insert(valid_word_list)
You will also need to correct the last line of insert:
self.recursive_insert(self.root, val)
Just to fill this out in an answer:
The recursive_search call doesn't handle failure correctly:
def recursive_search(self,parent,val):
if parent.data == val:
return parent
elif parent.data > val:
return self.recursive_search(parent.left,val)
else:
return self.recursive_search(parent.right,val)
If the word isn't found in the tree at all, eventually this will be called with the parent argument set to None, and the statement if parent.data == val: will throw a NoneType exception.
The solution here is to return None when parent == None:
def recursive_search(self,parent,val):
if parent == None:
return None
if parent.data == val:
return parent
elif parent.data > val:
return self.recursive_search(parent.left,val)
else:
return self.recursive_search(parent.right,val)
Related
I have below method where self contains a data structure as below
self.place = "India"
self.children = ["Tamil Nadu", "Karnataka"]
self.parent
Method
def get_node(self, value):
if value is None:
return self
if self.place == value:
return self
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
return node.get_node(value)
So via recursion, I am iterating on all possible child nodes to find the node I am looking for via return node.get_node(value) but I observed that, iteration happening via "Tamil Nadu" but not via "Karnataka".
I understood that, it took the first element of the list and then continued from there, but not coming back to 2nd element of the list.
is this expected behavior from recursion or am I doing something wrong ?
Full code( In case needed for testing)
class TreeNode:
def __init__(self, place):
self.place = place
self.children = []
self.parent = None
def add_child(self, child):
child.parent = self
self.children.append(child)
def print_tree(self):
prefix = ""
if self.parent is None:
print(self.place)
else:
prefix = prefix + (" " * self.get_level() * 3)
prefix = prefix + "|__"
print(prefix + self.place)
for child in self.children:
child.print_tree()
def get_level(self):
level = 0
p = self.parent
while p:
level = level + 1
p = p.parent
return level
def get_node(self, value):
if value is None:
return self
if self.place == value:
return self
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
return node.get_node(value)
def tree_map(self, nodes):
for node in nodes:
self.add_child(TreeNode(node))
def build_places():
root = TreeNode("Global")
india = TreeNode("India")
usa = TreeNode("USA")
root.add_child(india)
root.add_child(usa)
india_nodes = ["Gujarat" ,"Karnataka"]
gujarath_nodes = [ "Ahmedabad", "Baroda"]
karnataka_nodes = ["Bangalore", "Mysore"]
usa_nodes = ["New Jersey", "California"]
newjersey_nodes = ["Princeton", "Trenton"]
california_nodes = ["San Franciso", "Mountain View", "Palo Alto"]
for node in india_nodes:
india.add_child(TreeNode(node))
for node in usa_nodes:
usa.add_child(TreeNode(node))
gujarath_node = root.get_node("Gujarat")
print(gujarath_node.place)
for node in gujarath_nodes:
gujarath_node.add_child(TreeNode(node))
karnataka_node = root.get_node("Karnataka")
print(karnataka_node.place)
return root
if __name__ == "__main__":
root = build_places()
root.print_tree()
The problem is that in your loop you are always exiting the loop in its first iteration (when the node has at least some children). You should only exit on success, not when the recursive call comes back without success.
So change the loop to this:
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
result = node.get_node(value)
if result:
return result
Secondly, there is a strange base case you have at the start of this function. I would replace this:
if value is None:
return self
With:
if value is None:
return None
...since you didn't look for the value in that case: so then (in my opinion) it is not right to return a node instance (which might have any value -- you didn't verify it). It seems more consistent to return None or to remove this whole if block and not treat None in a special way.
Ok to preface, this is to help with a school assignment. I understand there are unpythonic methods in the following code but this is the format they insist upon. In my insert method I have 4 cases to account for. All of them are dealt with appropriately except for else and im unsure why. For some reason the method insert isn't updating the linked list to include the new_node when this new_node is not placed at the end or start of the list. I'm unsure why this is as at the appropriate position we store the old value of current, we then store its previous and we set current = new_node, we then set new_node's next to be the old value of current and new_node's previous to be the old currents previous. I'm confused as to why this won't work.
class DLinkedListNode:
# An instance of this class represents a node in Doubly-Linked List
def __init__(self,initData,initNext,initPrevious):
self.data = initData
self.next = initNext
self.previous = initPrevious
if initNext != None:
self.next.previous = self
if initPrevious != None:
self.previous.next = self
def getData(self):
return self.data
def setData(self,newData):
self.data = newData
def getNext(self):
return self.next
def getPrevious(self):
return self.previous
def setNext(self,newNext):
self.next = newNext
def setPrevious(self,newPrevious):
self.previous = newPrevious
class DLinkedList:
# An instance of this class represents the Doubly-Linked List
def __init__(self):
self.__head=None
self.__tail=None
self.__size=0
def search(self, item):
current = self.__head
found = False
while current != None and not found:
if current.getData() == item:
found= True
else:
current = current.getNext()
return found
def index(self, item):
current = self.__head
found = False
index = 0
while current != None and not found:
if current.getData() == item:
found= True
else:
current = current.getNext()
index = index + 1
if not found:
index = -1
return index
def add(self, item):
new_node=DLinkedListNode(item,None,None)
new_node.setNext(self.__head)
self.__head=new_node
current=self.__head
new_node.setPrevious(None)
current=current.getNext()
self.__size+=1
def remove(self, item):
# remove the node containing the item from the list
if self.__size == 0:
raise Exception('List is Empty')
current = self.__head
previous = None
found = False
while current != None and not found:
if current.getData() == item:
found = True
else:
previous = current
current = current.getNext()
if not found:
raise Exception('Item not in list')
else:
if previous == None: # the item is in the first node of the list
self.__head = current.getNext()
else: # item is not in the first node
previous.setNext(current.getNext())
self.__size = self.__size -1
def append(self, item):
# adds an item at the end of the list
new_node = DLinkedListNode(item,None,None)
current = self.__head # Start the traversal
if self.__size == 0: # check if list is empty
self.add(item)
else:
while (current.getNext()!=None):
current= current.getNext() # traversing the list
new_node.setNext(None)
new_node.setPrevious(current)
current.setNext(new_node)
self.__size = self.__size +1
def insert(self, pos, item):
# inserts the item at pos
# pos should be a positive number (or zero) of type int
assert type(pos)==int,'Error:pos is not an integer'
assert pos>=0,'Error:pos must be positive'
current=self.__head
new_node= DLinkedListNode(item,None,None)
if pos==0:
self.add(item)
elif pos==self.__size:
self.append(item)
elif pos>self.__size:
raise Exception('Position attempted to enter is larger than the size of linked list.')
else:
current_pos=0
while(current.getNext()!=None):
if (pos)==current_pos:
# storage is a holder variable
storage=current
right=current.getNext()
left=current.getPrevious()
current=new_node
new_node.setPrevious(left)
new_node.setNext(storage)
return True
current=current.getNext()
current_pos+=1
self.__size+=1
# doubly linked list
#Hello(prev)<-->World(store data)-->None
def pop1(self):
current = self.__head
previous = None
while (current.getNext() != None):
previous = current
current = current.getNext()
if (previous == None):
self.__head = None
else:
previous.setNext(None)
self.__size -= 1
return current.getData()
def pop(self, pos=None):
if pos!=None:
assert pos<=self.__size,'Pos must be within list'
assert type(pos)==int,'Pos must be an int'
assert pos>=0,'Pos must not be negative'
current=self.__head
current_pos=0
if pos==(self.getSize()-1) or pos==None:
data_from_method=self.pop1()
return data_from_method
else:
while current.getNext()!=None:
if pos==current_pos:
data=current.getData()
left=current.getPrevious()
right=current.getNext()
left.setNext(right)
right.setPrevious(left)
return data
current_pos+=1
current=current.getNext()
# doubly linked list
#Hello(prev)<-->World(store data)-->None
def searchLarger(self, item):
current=self.__head
current_pos=0
while current.getNext()!=None:
if item<current.getData():
return current_pos
current=current.getNext()
current_pos+=1
return -1
def getSize(self):
return self.__size
def getItem(self, pos):
assert type(pos)==int,'position must be type int'
assert pos<=self.__size,'Position is outside of the list'
current=self.__head
current_pos=0
if pos>=0:
while current!=None:
if current_pos==pos:
return current.getData()
current_pos+=1
current=current.getNext()
else:
current=self.__tail
while current!=None:
if current_pos==pos:
return current.getData()
current_pos-=1
current=current.getPrevious()
def __str__(self):
# returns a string representation of the list
current = self.__head
string = ''
while current != None:
if current.getNext()==None:
string = string + str(current.getData())+''
else:
string=string+str(current.getData())+' '
current = current.getNext()
return string
def test():
new_list=DLinkedList()
for i in range(20):
new_list.insert(i,i)
new_list.insert(1,90)
print(new_list)
test()
You currently have code that links the new node to nodes in the list, but no code that links the existing nodes to the new node. The only gesture you have in that direction is current=new_node, which doesn't achieve anything useful (since current is a local variable and you're about to return from the function).
You probably want something like left.setNext(newnode) and right.setPrevious(newnode), though I'm not sure you've set up both of those variables correctly (one of them should probably be current, unless you're intending to replace an existing node).
please suggest some edit in the delete function for the binary tree in python.I am not able to delete any element with this part of code.
def min_value_node(self,cur_node):
current=cur_node
while(current.left is not None):
current=current.left
return current
def delete(self,data):
if self.root==None:
return False
else:
return self._delete(data,self.root)
def _delete(self,data,cur_node):
if data>cur_node.data:
self. _delete(data,cur_node.right)
elif data>cur_node.data:
self. _delete(data,cur_node.right)
else:
if data==cur_node.data:
if cur_node.left is not None and cur_node.right is not None:
cur_node.data==self.min_value_node(cur_node.right)
else:
if cur_node.left == None:
cur_node = node.right
elif cur_node.right == None:
cur_node = node.left
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'
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