How can I solve Attribute Error in Binary Search Tree Insertion? - python

I'm studying BST and have reached a problem within this topic.
This is all of the code.
class Node:
# elem is element of Node.
def __init__(self, key, left=None, right=None, parent=None, elem=None):
self.left = left
self.right = right
self.parent = parent
self.key = key
self.elem = elem
# External Node Check
def isExternal(node):
if (node.left is None) and (node.right is None):
return True
else:
return False
# Internal Node Check
def isInternal(node):
if (node.left is not None) and (node.right is not None):
return True
else:
return False
def expandExternal(z):
leftnode = Node()
rightnode = Node()
leftnode.left = None
leftnode.right = None
leftnode.parent = z
rightnode.left = None
rightnode.right = None
rightnode.parent = z
z.left = leftnode
z.right = rightnode
return
class BST:
def __init__(self):
self.root = None
def insertItem(self, key, elem):
node = self.treeSearch(self.root, key)
if Node.isInternal(node):
return
node.elem = elem
node.key = key
Node.expandExternal(node)
return
def treeSearch(self, node, key):
if Node.isExternal(node):
return node
if key == node.key:
return node
elif key < node.key:
return self.treeSearch(node.left, key)
else:
return self.treeSearch(node.right, key)
def main():
n=int(input("ENTER THE NUMBER OF STUDENTS: \n"))
b=BST()
for i in range (n):
print("\nENTER THE DETAILS OF STUDENT ",i+1,":")
key=int(input("Enter the roll num: "))
name=input("Enter name: ")
b.insertItem(key, name)
if __name__ == '__main__':
main()
then Error is
AttributeError: 'NoneType' object has no attribute 'left'
The error occurs in this part:
def isExternal(node):
if (node.left == None) & (node.right == None): # <-- error here
return True
else:
return False
What is wrong with this code?
I wanted to put the roll number as the key and the name as the element and insert them, however I couldn't.

Related

I'm trying to implement Binary Tree insert method with recursive calls

I'm trying to implement Binary Tree insert method with recursive calls. When i run insert function it gives me an AtributeError : BinTree instance has no atribute 'root. Can you tell me pls how I can fix it??
from random import randint
class Node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BinTree:
def __init___(self):
self.root = None
def insert(self, value):
if self.root == None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curr_node):
if value < curr_node.value:
if curr_node.left == None:
curr_node.left = Node(value)
else:
self._insert(value, curr_node.left)
elif value>curr_node.value:
if curr_node.right == None:
curr_node.right = Node(value)
else:
self._insert(value, curr_node.rigth)
else:
print('Node already exist!')
def printTree(self):
if self.root != None:
self._printTree(self.root)
def _printTree(self, curr_node):
if curr_node !=None:
self._printTree(curr_node.left)
print(str(curr_node.val))
self._printTree(curr_node.right)
def fillTree(tree):
for _ in range(100):
curr_elem = randint(0,50)
tree.insert(curr_elem)
return tree
tree = BinTree()
fillTree(tree)
tree.printTree()
Your __init__ has a typo in the name. There are 3 trailing underscores. Change it to:
...
class BinTree:
def __init__(self):
self.root = None
And your code should work
Edit: found a couple of more issues. Here's the complete fixed code:
from random import randint
class Node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BinTree:
def __init__(self):
self.root = None
def insert(self, value):
if self.root == None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curr_node):
if value < curr_node.value:
if curr_node.left == None:
curr_node.left = Node(value)
else:
self._insert(value, curr_node.left)
elif value>curr_node.value:
if curr_node.right == None:
curr_node.right = Node(value)
else:
self._insert(value, curr_node.right)
else:
print('Node already exist!')
def printTree(self):
if self.root != None:
self._printTree(self.root)
def _printTree(self, curr_node):
if curr_node !=None:
self._printTree(curr_node.left)
print(str(curr_node.value))
self._printTree(curr_node.right)
def fillTree(tree):
for _ in range(100):
curr_elem = randint(0,50)
tree.insert(curr_elem)
return tree
tree = BinTree()
fillTree(tree)
tree.printTree()
Only BinTrees have roots; the children of a BinTree are Nodes, not BinTrees and thus don't have roots.

Function to create a binary search tree recursively

Picture of Question with specific details
I'm trying to write a function that creates a binary search tree. Here's what I have so far:
def add_items(bst, low, high):
if low == high:
bst.insert(high)
return
else:
left = add_items(bst, low, high)
right = add_items(bst, low, high)
item = BinarySearchTreeMap.Item(low)
node = BinarySearchTreeMap.BinarySearchTreeMap.Node(item)
node.left = left
node.right = right
return node
The problems I noticed with this is that the function returns a node when it finishes all the recursive calls. I want to return the root of this binary search tree, but I'm not sure how to return it at the end. The picture includes a more detailed description of what I am trying to do. I appreciate any help, advice, or ideas anyone may have. add_items is actually sort of a helper function as it is called by this little snippet of code:
def create_complete_bst(n):
bst = BinarySearchTreeMap.BinarySearchTreeMap()
add_items(bst, 1, n)
return bst
P.S. here is the binary search tree class that I have been provided with and am using in this program
class BinarySearchTreeMap:
class Item:
def __init__(self, key, value=None):
self.key = key
self.value = value
class Node:
def __init__(self, item):
self.item = item
self.parent = None
self.left = None
self.right = None
def num_children(self):
count = 0
if (self.left is not None):
count += 1
if (self.right is not None):
count += 1
return count
def disconnect(self):
self.item = None
self.parent = None
self.left = None
self.right = None
def __init__(self):
self.root = None
self.size = 0
def __len__(self):
return self.size
def is_empty(self):
return len(self) == 0
# raises exception if not found
def __getitem__(self, key):
node = self.find(key)
if (node is None):
raise KeyError(str(key) + " not found")
else:
return node.item.value
# returns None if not found
def find(self, key):
curr = self.root
while (curr is not None):
if (curr.item.key == key):
return curr
elif (curr.item.key > key):
curr = curr.left
else: # (curr.item.key < key)
curr = curr.right
return None
# updates value if key already exists
def __setitem__(self, key, value):
node = self.find(key)
if (node is None):
self.insert(key, value)
else:
node.item.value = value
# assumes key not in tree
def insert(self, key, value=None):
item = BinarySearchTreeMap.Item(key, value)
new_node = BinarySearchTreeMap.Node(item)
if (self.is_empty()):
self.root = new_node
self.size = 1
else:
parent = self.root
if(key < self.root.item.key):
curr = self.root.left
else:
curr = self.root.right
while (curr is not None):
parent = curr
if (key < curr.item.key):
curr = curr.left
else:
curr = curr.right
if (key < parent.item.key):
parent.left = new_node
else:
parent.right = new_node
new_node.parent = parent
self.size += 1
# raises exception if key not in tree
def __delitem__(self, key):
node = self.find(key)
if (node is None):
raise KeyError(str(key) + " is not found")
else:
self.delete_node(node)
# assumes key is in tree + returns value assosiated
def delete_node(self, node_to_delete):
item = node_to_delete.item
num_children = node_to_delete.num_children()
if (node_to_delete is self.root):
if (num_children == 0):
self.root = None
node_to_delete.disconnect()
self.size -= 1
elif (num_children == 1):
if (self.root.left is not None):
self.root = self.root.left
else:
self.root = self.root.right
self.root.parent = None
node_to_delete.disconnect()
self.size -= 1
else: #num_children == 2
max_of_left = self.subtree_max(node_to_delete.left)
node_to_delete.item = max_of_left.item
self.delete_node(max_of_left)
else:
if (num_children == 0):
parent = node_to_delete.parent
if (node_to_delete is parent.left):
parent.left = None
else:
parent.right = None
node_to_delete.disconnect()
self.size -= 1
elif (num_children == 1):
parent = node_to_delete.parent
if(node_to_delete.left is not None):
child = node_to_delete.left
else:
child = node_to_delete.right
child.parent = parent
if (node_to_delete is parent.left):
parent.left = child
else:
parent.right = child
node_to_delete.disconnect()
self.size -= 1
else: #num_children == 2
max_of_left = self.subtree_max(node_to_delete.left)
node_to_delete.item = max_of_left.item
self.delete_node(max_of_left)
return item
# assumes non empty subtree
def subtree_max(self, curr_root):
node = curr_root
while (node.right is not None):
node = node.right
return node
def inorder(self):
for node in self.subtree_inorder(self.root):
yield node
def subtree_inorder(self, curr_root):
if(curr_root is None):
pass
else:
yield from self.subtree_inorder(curr_root.left)
yield curr_root
yield from self.subtree_inorder(curr_root.right)
def __iter__(self):
for node in self.inorder():
yield node.item.key
After revising with suggestions:
def create_complete_bst(n):
bst = BinarySearchTreeMap.BinarySearchTreeMap()
add_items(bst, 1, n)
return bst
def add_items(bst, low, high):
if low == high:
bst.insert(high)
return
elif high < low:
return
else:
mid = (low+high) // 2
bst.insert(mid)
add_items(bst, low, mid-1)
add_items(bst, mid+1, high)
return bst

How can I find visited nodes called in functions?

Here's my programme of Binary Search Tree, all the functions are working in uploading system, except the last one, I somehow have to find out which of the Nodes I visited throughout calling previous functions. Any ideas?
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
class BinarySearchTree:
def __init__(self):
self.root = None
def insert(self, value):
if self.root is None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curNode):
if value < curNode.data:
if curNode.left is None:
curNode.left = Node(value)
else:
self._insert(value, curNode.left)
else:
if curNode.right is None:
curNode.right = Node(value)
else:
self._insert(value, curNode.right)
def fromArray(self, array):
for i in range(len(array)-1):
value = array[i]
self.insert(value)
i += 1
def search(self, value):
if self.root is not None:
return self._search(value, self.root)
else:
return False
def _search(self, value, curNode):
if value == curNode.data:
return True
elif value < curNode.data and curNode.left is not None:
self._search(value, curNode.left)
elif value > curNode.data and curNode.right is not None:
self._search(value, curNode.right)
else:
return False
def min(self):
curNode = self.root
while curNode.left is not None:
curNode = curNode.left
return curNode
def max(self):
curNode = self.root
while curNode.right is not None:
curNode = curNode.right
return curNode
def visitedNodes(self):
pass
And it has to return the values of nodes in list.
The straight forward answer would be to add a visited flag to each node, that is explicitly flipped in each of your functions when a Node is visited:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
self.visited = False
and then:
def _search(self, value, curNode):
curNode.visited = True
if value == curNode.data:
return True
# etc., unchanged
Same for min and max, and finally:
def visitedNodes(self, current=self.root, accumulator=[]):
if current == None:
return
if current == self.root:
accumulator = []
if current.visited:
accumulator.append(current)
visitedNodes(current.left)
visitedNodes(current.right)
return accumulator
This is just one implementation, there are many other ways to do this. I also assume this function, which traverses the whole tree, should not set the visited flag.
If you don't want to modify your current code, maybe this can help you:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self._data = value
self.visited = False
#property
def data(self):
self.visited = True
return self._data
#data.setter
def data(self, value):
self.visited = False
self._data = value
n = Node(3)
print(n.visited)
print(n.data)
print(n.visited)
Output:
False
3
True
Then in your visitedNodes method you would have to look at the visited attribute of everynode. (Which will be slow)
Other way of doing it is adding a new set attribute to your BinarySearchTree and manually add a node each time you look at it, this will make you modify your code.

Indexing into a Dictionary and Iterating in Python

I am indexing a large CSV (5000+ lines) file into Python using the following code:
index = {}
df = open('file.csv', encoding='UTF-8')
fp = 0
l = df.readline()
while l:
r = l.split(',')
index[r[0]] = fp
fp = df.tell()
l = df.readline()
df.seek(index["Sarah"])
print(df.readline())
df.close()
Here is an example of the file content:
John, Always wears a blue hat
Alex, Always wears a red shirt
Sarah, Hates the colour pink
Here is an example of how they have been indexed:
{'John': 26389, 'Alex': 217059, 'Sarah': 142108...}
I am trying to add the indexed data into a binary search tree I've built using a tutorial on interactivepython. Here is the BST:
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
def replaceNodeData(self,key,value,lc,rc):
self.key = key
self.payload = value
self.leftChild = lc
self.rightChild = rc
if self.hasLeftChild():
self.leftChild.parent = self
if self.hasRightChild():
self.rightChild.parent = self
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
def delete(self,key):
if self.size > 1:
nodeToRemove = self._get(key,self.root)
if nodeToRemove:
self.remove(nodeToRemove)
self.size = self.size-1
else:
raise KeyError('Error, key not in tree')
elif self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error, key not in tree')
def __delitem__(self,key):
self.delete(key)
def spliceOut(self):
if self.isLeaf():
if self.isLeftChild():
self.parent.leftChild = None
else:
self.parent.rightChild = None
elif self.hasAnyChildren():
if self.hasLeftChild():
if self.isLeftChild():
self.parent.leftChild = self.leftChild
else:
self.parent.rightChild = self.leftChild
self.leftChild.parent = self.parent
else:
if self.isLeftChild():
self.parent.leftChild = self.rightChild
else:
self.parent.rightChild = self.rightChild
self.rightChild.parent = self.parent
def findSuccessor(self):
succ = None
if self.hasRightChild():
succ = self.rightChild.findMin()
else:
if self.parent:
if self.isLeftChild():
succ = self.parent
else:
self.parent.rightChild = None
succ = self.parent.findSuccessor()
self.parent.rightChild = self
return succ
def findMin(self):
current = self
while current.hasLeftChild():
current = current.leftChild
return current
def remove(self,currentNode):
if currentNode.isLeaf(): #leaf
if currentNode == currentNode.parent.leftChild:
currentNode.parent.leftChild = None
else:
currentNode.parent.rightChild = None
elif currentNode.hasBothChildren(): #interior
succ = currentNode.findSuccessor()
succ.spliceOut()
currentNode.key = succ.key
currentNode.payload = succ.payload
else: # this node has one child
if currentNode.hasLeftChild():
if currentNode.isLeftChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRightChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.leftChild
else:
currentNode.replaceNodeData(currentNode.leftChild.key,
currentNode.leftChild.payload,
currentNode.leftChild.leftChild,
currentNode.leftChild.rightChild)
else:
if currentNode.isLeftChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.rightChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
currentNode.replaceNodeData(currentNode.rightChild.key,
currentNode.rightChild.payload,
currentNode.rightChild.leftChild,
currentNode.rightChild.rightChild)
I can add individual items using the command:
mytree = BinarySearchTree()
mytree[1] = "One"
What I am trying to do is iterate over the index dictionary but I keep getting an error.
Here is how I am iterating over the dictionary:
for k, v in index.items():
mytree[k] = v
I think what you mean to do is to add the elements in the binary tree based on their csv position. If so, then try adding the element based on their value (instead of the key).
for k, v in index.items():
mytree[v] = k
EDIT: Based on the comments, it looks like the OP is trying to enter the elements in the tree based on their names (and not values). In order to catch which key value pair is causing this exception, how about adding this code? This would atleast narrow down the issue to the specific key-value pair causing this exception. One possibility is that the key in some cases is a string and in other cases might be a int (just a guess!)
def _put(self,key,val,currentNode):
try:
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)
except TypeError as e:
print "key = ", key
print "currentNode key = ", currentNode.key
print "val = ", val
raise e
You get the error as soon as some of the keys are ints and some are strings, they aren't comparable so that's not going to work.
Did you actually use the line
ytree[1] = "One"
? Because that uses an int key, and the rest of the code inserts strings as keys. It should have been the other way around.

How to implement a binary search tree in Python?

This is what I've got so far but it is not working:
class Node:
rChild,lChild,data = None,None,None
def __init__(self,key):
self.rChild = None
self.lChild = None
self.data = key
class Tree:
root,size = None,0
def __init__(self):
self.root = None
self.size = 0
def insert(self,node,someNumber):
if node is None:
node = Node(someNumber)
else:
if node.data > someNumber:
self.insert(node.rchild,someNumber)
else:
self.insert(node.rchild, someNumber)
return
def main():
t = Tree()
t.root = Node(4)
t.root.rchild = Node(5)
print t.root.data #this works
print t.root.rchild.data #this works too
t = Tree()
t.insert(t.root,4)
t.insert(t.root,5)
print t.root.data #this fails
print t.root.rchild.data #this fails too
if __name__ == '__main__':
main()
Here is a quick example of a binary insert:
class Node:
def __init__(self, val):
self.l_child = None
self.r_child = None
self.data = val
def binary_insert(root, node):
if root is None:
root = node
else:
if root.data > node.data:
if root.l_child is None:
root.l_child = node
else:
binary_insert(root.l_child, node)
else:
if root.r_child is None:
root.r_child = node
else:
binary_insert(root.r_child, node)
def in_order_print(root):
if not root:
return
in_order_print(root.l_child)
print root.data
in_order_print(root.r_child)
def pre_order_print(root):
if not root:
return
print root.data
pre_order_print(root.l_child)
pre_order_print(root.r_child)
r = Node(3)
binary_insert(r, Node(7))
binary_insert(r, Node(1))
binary_insert(r, Node(5))
3
/ \
1 7
/
5
print "in order:"
in_order_print(r)
print "pre order"
pre_order_print(r)
in order:
1
3
5
7
pre order
3
1
7
5
class Node:
rChild,lChild,data = None,None,None
This is wrong - it makes your variables class variables - that is, every instance of Node uses the same values (changing rChild of any node changes it for all nodes!). This is clearly not what you want; try
class Node:
def __init__(self, key):
self.rChild = None
self.lChild = None
self.data = key
now each node has its own set of variables. The same applies to your definition of Tree,
class Tree:
root,size = None,0 # <- lose this line!
def __init__(self):
self.root = None
self.size = 0
Further, each class should be a "new-style" class derived from the "object" class and should chain back to object.__init__():
class Node(object):
def __init__(self, data, rChild=None, lChild=None):
super(Node,self).__init__()
self.data = data
self.rChild = rChild
self.lChild = lChild
class Tree(object):
def __init__(self):
super(Tree,self).__init__()
self.root = None
self.size = 0
Also, main() is indented too far - as shown, it is a method of Tree which is uncallable because it does not accept a self argument.
Also, you are modifying the object's data directly (t.root = Node(4)) which kind of destroys encapsulation (the whole point of having classes in the first place); you should be doing something more like
def main():
t = Tree()
t.add(4) # <- let the tree create a data Node and insert it
t.add(5)
class Node:
rChild,lChild,parent,data = None,None,None,0
def __init__(self,key):
self.rChild = None
self.lChild = None
self.parent = None
self.data = key
class Tree:
root,size = None,0
def __init__(self):
self.root = None
self.size = 0
def insert(self,someNumber):
self.size = self.size+1
if self.root is None:
self.root = Node(someNumber)
else:
self.insertWithNode(self.root, someNumber)
def insertWithNode(self,node,someNumber):
if node.lChild is None and node.rChild is None:#external node
if someNumber > node.data:
newNode = Node(someNumber)
node.rChild = newNode
newNode.parent = node
else:
newNode = Node(someNumber)
node.lChild = newNode
newNode.parent = node
else: #not external
if someNumber > node.data:
if node.rChild is not None:
self.insertWithNode(node.rChild, someNumber)
else: #if empty node
newNode = Node(someNumber)
node.rChild = newNode
newNode.parent = node
else:
if node.lChild is not None:
self.insertWithNode(node.lChild, someNumber)
else:
newNode = Node(someNumber)
node.lChild = newNode
newNode.parent = node
def printTree(self,someNode):
if someNode is None:
pass
else:
self.printTree(someNode.lChild)
print someNode.data
self.printTree(someNode.rChild)
def main():
t = Tree()
t.insert(5)
t.insert(3)
t.insert(7)
t.insert(4)
t.insert(2)
t.insert(1)
t.insert(6)
t.printTree(t.root)
if __name__ == '__main__':
main()
My solution.
class BST:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val
def __str__(self):
return "[%s, %s, %s]" % (self.left, str(self.val), self.right)
def isEmpty(self):
return self.left == self.right == self.val == None
def insert(self, val):
if self.isEmpty():
self.val = val
elif val < self.val:
if self.left is None:
self.left = BST(val)
else:
self.left.insert(val)
else:
if self.right is None:
self.right = BST(val)
else:
self.right.insert(val)
a = BST(1)
a.insert(2)
a.insert(3)
a.insert(0)
print a
The Op's Tree.insert method qualifies for the "Gross Misnomer of the Week" award -- it doesn't insert anything. It creates a node which is not attached to any other node (not that there are any nodes to attach it to) and then the created node is trashed when the method returns.
For the edification of #Hugh Bothwell:
>>> class Foo(object):
... bar = None
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar
>>> a.bar = 42
>>> b.bar
>>> b.bar = 666
>>> a.bar
42
>>> b.bar
666
>>>
The accepted answer neglects to set a parent attribute for each node inserted, without which one cannot implement a successor method which finds the successor in an in-order tree walk in O(h) time, where h is the height of the tree (as opposed to the O(n) time needed for the walk).
Here is an implementation based on the pseudocode given in Cormen et al., Introduction to Algorithms, including assignment of a parent attribute and a successor method:
class Node(object):
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.parent = None
class Tree(object):
def __init__(self, root=None):
self.root = root
def insert(self, z):
y = None
x = self.root
while x is not None:
y = x
if z.key < x.key:
x = x.left
else:
x = x.right
z.parent = y
if y is None:
self.root = z # Tree was empty
elif z.key < y.key:
y.left = z
else:
y.right = z
#staticmethod
def minimum(x):
while x.left is not None:
x = x.left
return x
#staticmethod
def successor(x):
if x.right is not None:
return Tree.minimum(x.right)
y = x.parent
while y is not None and x == y.right:
x = y
y = y.parent
return y
Here are some tests to show that the tree behaves as expected for the example given by DTing:
import pytest
#pytest.fixture
def tree():
t = Tree()
t.insert(Node(3))
t.insert(Node(1))
t.insert(Node(7))
t.insert(Node(5))
return t
def test_tree_insert(tree):
assert tree.root.key == 3
assert tree.root.left.key == 1
assert tree.root.right.key == 7
assert tree.root.right.left.key == 5
def test_tree_successor(tree):
assert Tree.successor(tree.root.left).key == 3
assert Tree.successor(tree.root.right.left).key == 7
if __name__ == "__main__":
pytest.main([__file__])
Just something to help you to start on.
A (simple idea of) binary tree search would be quite likely be implement in python according the lines:
def search(node, key):
if node is None: return None # key not found
if key< node.key: return search(node.left, key)
elif key> node.key: return search(node.right, key)
else: return node.value # found key
Now you just need to implement the scaffolding (tree creation and value inserts) and you are done.
I find the solutions a bit clumsy on the insert part. You could return the root reference and simplify it a bit:
def binary_insert(root, node):
if root is None:
return node
if root.data > node.data:
root.l_child = binary_insert(root.l_child, node)
else:
root.r_child = binary_insert(root.r_child, node)
return root
its easy to implement a BST using two classes, 1. Node and 2. Tree
Tree class will be just for user interface, and actual methods will be implemented in Node class.
class Node():
def __init__(self,val):
self.value = val
self.left = None
self.right = None
def _insert(self,data):
if data == self.value:
return False
elif data < self.value:
if self.left:
return self.left._insert(data)
else:
self.left = Node(data)
return True
else:
if self.right:
return self.right._insert(data)
else:
self.right = Node(data)
return True
def _inorder(self):
if self:
if self.left:
self.left._inorder()
print(self.value)
if self.right:
self.right._inorder()
class Tree():
def __init__(self):
self.root = None
def insert(self,data):
if self.root:
return self.root._insert(data)
else:
self.root = Node(data)
return True
def inorder(self):
if self.root is not None:
return self.root._inorder()
else:
return False
if __name__=="__main__":
a = Tree()
a.insert(16)
a.insert(8)
a.insert(24)
a.insert(6)
a.insert(12)
a.insert(19)
a.insert(29)
a.inorder()
Inorder function for checking whether BST is properly implemented.
Another Python BST with sort key (defaulting to value)
LEFT = 0
RIGHT = 1
VALUE = 2
SORT_KEY = -1
class BinarySearchTree(object):
def __init__(self, sort_key=None):
self._root = []
self._sort_key = sort_key
self._len = 0
def insert(self, val):
if self._sort_key is None:
sort_key = val // if no sort key, sort key is value
else:
sort_key = self._sort_key(val)
node = self._root
while node:
if sort_key < node[_SORT_KEY]:
node = node[LEFT]
else:
node = node[RIGHT]
if sort_key is val:
node[:] = [[], [], val]
else:
node[:] = [[], [], val, sort_key]
self._len += 1
def minimum(self):
return self._extreme_node(LEFT)[VALUE]
def maximum(self):
return self._extreme_node(RIGHT)[VALUE]
def find(self, sort_key):
return self._find(sort_key)[VALUE]
def _extreme_node(self, side):
if not self._root:
raise IndexError('Empty')
node = self._root
while node[side]:
node = node[side]
return node
def _find(self, sort_key):
node = self._root
while node:
node_key = node[SORT_KEY]
if sort_key < node_key:
node = node[LEFT]
elif sort_key > node_key:
node = node[RIGHT]
else:
return node
raise KeyError("%r not found" % sort_key)
Here is a compact, object oriented, recursive implementation:
class BTreeNode(object):
def __init__(self, data):
self.data = data
self.rChild = None
self.lChild = None
def __str__(self):
return (self.lChild.__str__() + '<-' if self.lChild != None else '') + self.data.__str__() + ('->' + self.rChild.__str__() if self.rChild != None else '')
def insert(self, btreeNode):
if self.data > btreeNode.data: #insert left
if self.lChild == None:
self.lChild = btreeNode
else:
self.lChild.insert(btreeNode)
else: #insert right
if self.rChild == None:
self.rChild = btreeNode
else:
self.rChild.insert(btreeNode)
def main():
btreeRoot = BTreeNode(5)
print 'inserted %s:' %5, btreeRoot
btreeRoot.insert(BTreeNode(7))
print 'inserted %s:' %7, btreeRoot
btreeRoot.insert(BTreeNode(3))
print 'inserted %s:' %3, btreeRoot
btreeRoot.insert(BTreeNode(1))
print 'inserted %s:' %1, btreeRoot
btreeRoot.insert(BTreeNode(2))
print 'inserted %s:' %2, btreeRoot
btreeRoot.insert(BTreeNode(4))
print 'inserted %s:' %4, btreeRoot
btreeRoot.insert(BTreeNode(6))
print 'inserted %s:' %6, btreeRoot
The output of the above main() is:
inserted 5: 5
inserted 7: 5->7
inserted 3: 3<-5->7
inserted 1: 1<-3<-5->7
inserted 2: 1->2<-3<-5->7
inserted 4: 1->2<-3->4<-5->7
inserted 6: 1->2<-3->4<-5->6<-7
Here is a working solution.
class BST:
def __init__(self,data):
self.root = data
self.left = None
self.right = None
def insert(self,data):
if self.root == None:
self.root = BST(data)
elif data > self.root:
if self.right == None:
self.right = BST(data)
else:
self.right.insert(data)
elif data < self.root:
if self.left == None:
self.left = BST(data)
else:
self.left.insert(data)
def inordertraversal(self):
if self.left != None:
self.left.inordertraversal()
print (self.root),
if self.right != None:
self.right.inordertraversal()
t = BST(4)
t.insert(1)
t.insert(7)
t.insert(3)
t.insert(6)
t.insert(2)
t.insert(5)
t.inordertraversal()
A simple, recursive method with only 1 function and using an array of values:
class TreeNode(object):
def __init__(self, value: int, left=None, right=None):
super().__init__()
self.value = value
self.left = left
self.right = right
def __str__(self):
return str(self.value)
def create_node(values, lower, upper) -> TreeNode:
if lower > upper:
return None
index = (lower + upper) // 2
value = values[index]
node = TreeNode(value=value)
node.left = create_node(values, lower, index - 1)
node.right = create_node(values, index + 1, upper)
return node
def print_bst(node: TreeNode):
if node:
# Simple pre-order traversal when printing the tree
print("node: {}".format(node))
print_bst(node.left)
print_bst(node.right)
if __name__ == '__main__':
vals = [0, 1, 2, 3, 4, 5, 6]
bst = create_node(vals, lower=0, upper=len(vals) - 1)
print_bst(bst)
As you can see, we really only need 1 method, which is recursive: create_node. We pass in the full values array in each create_node method call, however, we update the lower and upper index values every time that we make the recursive call.
Then, using the lower and upper index values, we calculate the index value of the current node and capture it in value. This value is the value for the current node, which we use to create a node.
From there, we set the values of left and right by recursively calling the function, until we reach the end state of the recursion call when lower is greater than upper.
Important: we update the value of upper when creating the left side of the tree. Conversely, we update the value of lower when creating the right side of the tree.
Hopefully this helps!
The following code is basic on #DTing‘s answer and what I learn from class, which uses a while loop to insert (indicated in the code).
class Node:
def __init__(self, val):
self.l_child = None
self.r_child = None
self.data = val
def binary_insert(root, node):
y = None
x = root
z = node
#while loop here
while x is not None:
y = x
if z.data < x.data:
x = x.l_child
else:
x = x.r_child
z.parent = y
if y == None:
root = z
elif z.data < y.data:
y.l_child = z
else:
y.r_child = z
def in_order_print(root):
if not root:
return
in_order_print(root.l_child)
print(root.data)
in_order_print(root.r_child)
r = Node(3)
binary_insert(r, Node(7))
binary_insert(r, Node(1))
binary_insert(r, Node(5))
in_order_print(r)
The problem, or at least one problem with your code is here:-
def insert(self,node,someNumber):
if node is None:
node = Node(someNumber)
else:
if node.data > someNumber:
self.insert(node.rchild,someNumber)
else:
self.insert(node.rchild, someNumber)
return
You see the statement "if node.data > someNumber:" and the associated "else:" statement both have the same code after them. i.e you do the same thing whether the if statement is true or false.
I'd suggest you probably intended to do different things here, perhaps one of these should say self.insert(node.lchild, someNumber) ?
Another Python BST solution
class Node(object):
def __init__(self, value):
self.left_node = None
self.right_node = None
self.value = value
def __str__(self):
return "[%s, %s, %s]" % (self.left_node, self.value, self.right_node)
def insertValue(self, new_value):
"""
1. if current Node doesnt have value then assign to self
2. new_value lower than current Node's value then go left
2. new_value greater than current Node's value then go right
:return:
"""
if self.value:
if new_value < self.value:
# add to left
if self.left_node is None: # reached start add value to start
self.left_node = Node(new_value)
else:
self.left_node.insertValue(new_value) # search
elif new_value > self.value:
# add to right
if self.right_node is None: # reached end add value to end
self.right_node = Node(new_value)
else:
self.right_node.insertValue(new_value) # search
else:
self.value = new_value
def findValue(self, value_to_find):
"""
1. value_to_find is equal to current Node's value then found
2. if value_to_find is lower than Node's value then go to left
3. if value_to_find is greater than Node's value then go to right
"""
if value_to_find == self.value:
return "Found"
elif value_to_find < self.value and self.left_node:
return self.left_node.findValue(value_to_find)
elif value_to_find > self.value and self.right_node:
return self.right_node.findValue(value_to_find)
return "Not Found"
def printTree(self):
"""
Nodes will be in sequence
1. Print LHS items
2. Print value of node
3. Print RHS items
"""
if self.left_node:
self.left_node.printTree()
print(self.value),
if self.right_node:
self.right_node.printTree()
def isEmpty(self):
return self.left_node == self.right_node == self.value == None
def main():
root_node = Node(12)
root_node.insertValue(6)
root_node.insertValue(3)
root_node.insertValue(7)
# should return 3 6 7 12
root_node.printTree()
# should return found
root_node.findValue(7)
# should return found
root_node.findValue(3)
# should return Not found
root_node.findValue(24)
if __name__ == '__main__':
main()
def BinaryST(list1,key):
start = 0
end = len(list1)
print("Length of List: ",end)
for i in range(end):
for j in range(0, end-i-1):
if(list1[j] > list1[j+1]):
temp = list1[j]
list1[j] = list1[j+1]
list1[j+1] = temp
print("Order List: ",list1)
mid = int((start+end)/2)
print("Mid Index: ",mid)
if(key == list1[mid]):
print(key," is on ",mid," Index")
elif(key > list1[mid]):
for rindex in range(mid+1,end):
if(key == list1[rindex]):
print(key," is on ",rindex," Index")
break
elif(rindex == end-1):
print("Given key: ",key," is not in List")
break
else:
continue
elif(key < list1[mid]):
for lindex in range(0,mid):
if(key == list1[lindex]):
print(key," is on ",lindex," Index")
break
elif(lindex == mid-1):
print("Given key: ",key," is not in List")
break
else:
continue
size = int(input("Enter Size of List: "))
list1 = []
for e in range(size):
ele = int(input("Enter Element in List: "))
list1.append(ele)
key = int(input("\nEnter Key for Search: "))
print("\nUnorder List: ",list1)
BinaryST(list1,key)
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
class BinaryTree:
def __init__(self, root=None):
self.root = root
def add_node(self, node, value):
"""
Node points to the left of value if node > value; right otherwise,
BST cannot have duplicate values
"""
if node is not None:
if value < node.value:
if node.left is None:
node.left = TreeNode(value)
else:
self.add_node(node.left, value)
else:
if node.right is None:
node.right = TreeNode(value)
else:
self.add_node(node.right, value)
else:
self.root = TreeNode(value)
def search(self, value):
"""
Value will be to the left of node if node > value; right otherwise.
"""
node = self.root
while node is not None:
if node.value == value:
return True # node.value
if node.value > value:
node = node.left
else:
node = node.right
return False
def traverse_inorder(self, node):
"""
Traverse the left subtree of a node as much as possible, then traverse
the right subtree, followed by the parent/root node.
"""
if node is not None:
self.traverse_inorder(node.left)
print(node.value)
self.traverse_inorder(node.right)
def main():
binary_tree = BinaryTree()
binary_tree.add_node(binary_tree.root, 200)
binary_tree.add_node(binary_tree.root, 300)
binary_tree.add_node(binary_tree.root, 100)
binary_tree.add_node(binary_tree.root, 30)
binary_tree.traverse_inorder(binary_tree.root)
print(binary_tree.search(200))
if __name__ == '__main__':
main()

Categories

Resources