My python Binary Tree
Here she is, I tested the crap out of it, An edge case error in delete took me a few hours to find. I'll highlight where I fixed it with yellow.
That's part of why delete has so many (#print)'s in it. I left them in so if someone has a similar issue... "Your size is not dropping, although your items are being deleted."
I'm still learning, if you see something drop me a comment! I'd love to make it better.
--- Start code block --
from random import randint # for manual testing
class BinaryTreeNode(object):
def __init__(self, key, value, left, right):
self.key = key
self.value = value
self.left = left
self.right = right
def __repr__(self):
nleft = self.left and self.left.value or None
nright = self.right and self.right.value or None
return f"{nleft} <--- ( {self.key} : {self.value} ) ---> {nright}"
class BinaryTree(object):
def __init__(self, median):
self.median = median
self.root_node = BinaryTreeNode(self.median, 'binary_root_node', None, None)
self._size = 0
def set(self, akey, value):
if akey < self.median:
east = self.root_node.left
if not east:
# [None<---- newnode _---> None][<--left-- root --right-->]
newnode = BinaryTreeNode(akey, value, None, None)
self.root_node.left = newnode
self._size += 1
else:
while east:
if akey == east.key:
east.value = value
break
elif east.key < akey:
if east.right == None:
newnode = BinaryTreeNode(akey, value, None, None)
east.right = newnode
self._size += 1
break
else:
east = east.right
else:
if east.left == None:
newnode = BinaryTreeNode(akey, value, None, None)
east.left = newnode
self._size += 1
break
else:
east = east.left
if akey > self.median:
west = self.root_node.right
if not west:
# [<---- root --right-->][None<---- newnode _---> None]
newnode = BinaryTreeNode(akey, value, None, None)
self.root_node.right = newnode
self._size += 1
else:
while west:
########################
if akey == west.key:
west.value = value
break
elif west.key < akey:
if west.right == None:
newnode = BinaryTreeNode(akey, value, None, None)
west.right = newnode
self._size += 1
break
else:
west = west.right
else:
if west.left == None:
newnode = BinaryTreeNode(akey, value, None, None)
west.left = newnode
self._size += 1
break
else:
west = west.left
def get(self, akey):
node = self.root_node
if akey < self.median:
node = node.left
while node:
if akey == node.key:
return node.value
else:
if akey < node.key:
node = node.left
else:
node = node.right
else:
node = node.right
while node:
if akey == node.key:
return node.value
else:
if akey < node.key:
node = node.left
else:
node = node.right
def delete(self, akey):
if akey < self.median:
east = self.root_node.left
if not east:
# do nothing
return None
else:
root = True
temp = None
#print(f" AKEY = {akey}")
while east:
left_child = east.left
right_child = east.right
#print(f"{east.key}")
if east.key == akey:
# find the first center child/leaf that is none (left or right, I chose left)
# make that the holder for the oposing child, and the one you didn't use #becomes parent node
# center branches are @east.left go right ---> (x) <--@east.right go left
if not left_child and not right_child:
print(right_child)
if not root:
#print(" temp east")
#print(temp.left)
temp_left = temp.left
temp_right = temp.right
#print(temp.right)
#print(east)
#print(f"DELETE LEAF NODE {east}")
done = False
while not done:
if temp_right:
if temp_right.key == akey:
temp.right = None
print("temp.right = None")
print(temp)
self._size -= 1
done = True
break
elif temp_left:
if temp_left.key == akey:
temp.left = None
print("temp.left = None")
print(temp)
self._size -= 1
done = True
break
else:
#the temp has to have a right or left. that is where
# the akey was found.
print("this should not happen")
break
else:
self.root_node.left = None
self._size -= 1
break
else:
# it has a child link
left_child = east.left
right_child = east.right
if left_child and right_child:
new_left_child = east.left
#print(east)
#print(right_child)
# because parent node dictates the greatest value of
# the left's, right branch; x in branch will not be
# greater then the parent...
# we can be sure that however far down the branch we
# go, the right_child which is greater then the parent_node,
#can go after the preceeding nodes in the chain.
# It will be greater then them. Searching for numbers larger
# then right.key will still lead to the right_child,
# but it may be a longer path to it and it's child nodes
while new_left_child:
if new_left_child.right == None:
new_left_child.right = right_child
east.key = left_child.key
east.value = left_child.value
east.left = left_child.left
east.right = left_child.right
self._size -= 1
#print(new_left_child.right)
break
else:
new_left_child = new_left_child.right
break
elif left_child and not right_child:
east.key = left_child.key
east.value = left_child.value
east.left = left_child.left
east.right = left_child.right
self._size -= 1
break
elif right_child and not left_child:
east.key = right_child.key
east.value = right_child.value
east.left = right_child.left
east.right = right_child.right
self._size -= 1
break
else:
print("error in while loop for :while east: delete(akey)")
break
elif akey > east.key:
temp = east
root = False
east = east.right
else:
temp = east
root = False
east = east.left
else:
# akey is > self.median
# median should always be set to a float, such as 20.5 so that it can not
# be duplicated assuming all entered key's are whole numbers.
# and all keys go to proper side for example, if self.median 20.5,
# 20 will go left. or if 20 gets deleted, root is not involved.
west = self.root_node.right
root = True
temp = None
if not west:
return None
else:
while west:
left_child = west.left
right_child = west.right
if akey == west.key:
# we've found the node to remove
if not left_child and not right_child:
if not root:
temp_left = temp.left
temp_right = temp.right
done = False
while not done:
if temp_right:
if temp_right.key == akey:
temp.right = None
self._size -= 1
#print("temp.right = None")
#print(temp.right)
done = True
break
if temp_left:
print("running check left temp")
if temp_left.key == akey:
temp.left = None
#print("temp.left = None")
#print(temp.left)
self._size -= 1
done = True
break
else:
## the temp value if it is not root, should be what was previous
## to the current east. Therefore it cannot have no left or right.
print("This should not happen.")
break
else:
self.root_node.right = None
self._size -= 1
break
elif left_child and not right_child:
west.key = left_child.key
west.value = left_child.value
west.left = left_child.left
west.right = left_child.right
self._size -= 1
break
elif right_child and not left_child:
west.key = right_child.key
west.value = right_child.value
west.left = right_child.left
west.right = right_child.right
self._size -= 1
break
elif right_child and left_child:
new_left_child = west.left
#print(right_child)
while new_left_child:
if new_left_child.right == None:
new_left_child.right = right_child
west.key = left_child.key
west.value = left_child.value
west.left = left_child.left
west.right = left_child.right
#print(new_left_child)
self._size -= 1
break
else:
new_left_child = new_left_child.right
break
else:
print("error in while loop for :while west: delete(akey)")
elif akey > west.key:
temp = west
west = west.right
root = False
else:
temp = west
west = west.left
root = False
def dump(self):
west = self.root_node.right
east = self.root_node.left
if east:
print(f"East branch: {east}")
self.recursDump(east)
print("********** END EAST************")
if west:
print(f"West branch: {west}")
self.recursDump(west)
print("********** END WEST************")
def recursDump(self, branch):
if branch == None:
print(" ")
else:
left_child = branch.left
right_child = branch.right
if left_child:
print(left_child)
if right_child:
print(right_child)
self.recursDump(right_child)
self.recursDump(left_child)
return branch
def count(self):
trunk = self.root_node
keyslist = []
result = self.recurs_helper(trunk, keyslist)
#print(result)
count = len(result)
return count
def make_key_list(self):
# same as count different return
trunk = self.root_node
keyslist = []
result = self.recurs_helper(trunk, keyslist)
#print(result)
return result
def recurs_helper(self, branch, alist):
if branch == None:
pass
else:
left_sprout = branch.left
right_sprout = branch.right
if left_sprout:
self.list_add(left_sprout, alist)
if right_sprout:
self.list_add(right_sprout, alist)
self.recurs_helper(left_sprout, alist)
self.recurs_helper(right_sprout, alist)
return alist
def list_add(self, something, alist):
if something:
alist.append(something.key)
-- End code block ---That's part of why delete has so many (#print)'s in it. I left them in so if someone has a similar issue... "Your size is not dropping, although your items are being deleted."
I'm still learning, if you see something drop me a comment! I'd love to make it better.
--- Start code block --
from random import randint # for manual testing
class BinaryTreeNode(object):
def __init__(self, key, value, left, right):
self.key = key
self.value = value
self.left = left
self.right = right
def __repr__(self):
nleft = self.left and self.left.value or None
nright = self.right and self.right.value or None
return f"{nleft} <--- ( {self.key} : {self.value} ) ---> {nright}"
class BinaryTree(object):
def __init__(self, median):
self.median = median
self.root_node = BinaryTreeNode(self.median, 'binary_root_node', None, None)
self._size = 0
def set(self, akey, value):
if akey < self.median:
east = self.root_node.left
if not east:
# [None<---- newnode _---> None][<--left-- root --right-->]
newnode = BinaryTreeNode(akey, value, None, None)
self.root_node.left = newnode
self._size += 1
else:
while east:
if akey == east.key:
east.value = value
break
elif east.key < akey:
if east.right == None:
newnode = BinaryTreeNode(akey, value, None, None)
east.right = newnode
self._size += 1
break
else:
east = east.right
else:
if east.left == None:
newnode = BinaryTreeNode(akey, value, None, None)
east.left = newnode
self._size += 1
break
else:
east = east.left
if akey > self.median:
west = self.root_node.right
if not west:
# [<---- root --right-->][None<---- newnode _---> None]
newnode = BinaryTreeNode(akey, value, None, None)
self.root_node.right = newnode
self._size += 1
else:
while west:
########################
if akey == west.key:
west.value = value
break
elif west.key < akey:
if west.right == None:
newnode = BinaryTreeNode(akey, value, None, None)
west.right = newnode
self._size += 1
break
else:
west = west.right
else:
if west.left == None:
newnode = BinaryTreeNode(akey, value, None, None)
west.left = newnode
self._size += 1
break
else:
west = west.left
def get(self, akey):
node = self.root_node
if akey < self.median:
node = node.left
while node:
if akey == node.key:
return node.value
else:
if akey < node.key:
node = node.left
else:
node = node.right
else:
node = node.right
while node:
if akey == node.key:
return node.value
else:
if akey < node.key:
node = node.left
else:
node = node.right
def delete(self, akey):
if akey < self.median:
east = self.root_node.left
if not east:
# do nothing
return None
else:
root = True
temp = None
#print(f" AKEY = {akey}")
while east:
left_child = east.left
right_child = east.right
#print(f"{east.key}")
if east.key == akey:
# find the first center child/leaf that is none (left or right, I chose left)
# make that the holder for the oposing child, and the one you didn't use #becomes parent node
# center branches are @east.left go right ---> (x) <--@east.right go left
if not left_child and not right_child:
print(right_child)
if not root:
#print(" temp east")
#print(temp.left)
temp_left = temp.left
temp_right = temp.right
#print(temp.right)
#print(east)
#print(f"DELETE LEAF NODE {east}")
done = False
while not done:
if temp_right:
if temp_right.key == akey:
temp.right = None
print("temp.right = None")
print(temp)
self._size -= 1
done = True
break
elif temp_left:
if temp_left.key == akey:
temp.left = None
print("temp.left = None")
print(temp)
self._size -= 1
done = True
break
else:
#the temp has to have a right or left. that is where
# the akey was found.
print("this should not happen")
break
else:
self.root_node.left = None
self._size -= 1
break
else:
# it has a child link
left_child = east.left
right_child = east.right
if left_child and right_child:
new_left_child = east.left
#print(east)
#print(right_child)
# because parent node dictates the greatest value of
# the left's, right branch; x in branch will not be
# greater then the parent...
# we can be sure that however far down the branch we
# go, the right_child which is greater then the parent_node,
#can go after the preceeding nodes in the chain.
# It will be greater then them. Searching for numbers larger
# then right.key will still lead to the right_child,
# but it may be a longer path to it and it's child nodes
while new_left_child:
if new_left_child.right == None:
new_left_child.right = right_child
east.key = left_child.key
east.value = left_child.value
east.left = left_child.left
east.right = left_child.right
self._size -= 1
#print(new_left_child.right)
break
else:
new_left_child = new_left_child.right
break
elif left_child and not right_child:
east.key = left_child.key
east.value = left_child.value
east.left = left_child.left
east.right = left_child.right
self._size -= 1
break
elif right_child and not left_child:
east.key = right_child.key
east.value = right_child.value
east.left = right_child.left
east.right = right_child.right
self._size -= 1
break
else:
print("error in while loop for :while east: delete(akey)")
break
elif akey > east.key:
temp = east
root = False
east = east.right
else:
temp = east
root = False
east = east.left
else:
# akey is > self.median
# median should always be set to a float, such as 20.5 so that it can not
# be duplicated assuming all entered key's are whole numbers.
# and all keys go to proper side for example, if self.median 20.5,
# 20 will go left. or if 20 gets deleted, root is not involved.
west = self.root_node.right
root = True
temp = None
if not west:
return None
else:
while west:
left_child = west.left
right_child = west.right
if akey == west.key:
# we've found the node to remove
if not left_child and not right_child:
if not root:
temp_left = temp.left
temp_right = temp.right
done = False
while not done:
if temp_right:
if temp_right.key == akey:
temp.right = None
self._size -= 1
#print("temp.right = None")
#print(temp.right)
done = True
break
if temp_left:
print("running check left temp")
if temp_left.key == akey:
temp.left = None
#print("temp.left = None")
#print(temp.left)
self._size -= 1
done = True
break
else:
## the temp value if it is not root, should be what was previous
## to the current east. Therefore it cannot have no left or right.
print("This should not happen.")
break
else:
self.root_node.right = None
self._size -= 1
break
elif left_child and not right_child:
west.key = left_child.key
west.value = left_child.value
west.left = left_child.left
west.right = left_child.right
self._size -= 1
break
elif right_child and not left_child:
west.key = right_child.key
west.value = right_child.value
west.left = right_child.left
west.right = right_child.right
self._size -= 1
break
elif right_child and left_child:
new_left_child = west.left
#print(right_child)
while new_left_child:
if new_left_child.right == None:
new_left_child.right = right_child
west.key = left_child.key
west.value = left_child.value
west.left = left_child.left
west.right = left_child.right
#print(new_left_child)
self._size -= 1
break
else:
new_left_child = new_left_child.right
break
else:
print("error in while loop for :while west: delete(akey)")
elif akey > west.key:
temp = west
west = west.right
root = False
else:
temp = west
west = west.left
root = False
def dump(self):
west = self.root_node.right
east = self.root_node.left
if east:
print(f"East branch: {east}")
self.recursDump(east)
print("********** END EAST************")
if west:
print(f"West branch: {west}")
self.recursDump(west)
print("********** END WEST************")
def recursDump(self, branch):
if branch == None:
print(" ")
else:
left_child = branch.left
right_child = branch.right
if left_child:
print(left_child)
if right_child:
print(right_child)
self.recursDump(right_child)
self.recursDump(left_child)
return branch
def count(self):
trunk = self.root_node
keyslist = []
result = self.recurs_helper(trunk, keyslist)
#print(result)
count = len(result)
return count
def make_key_list(self):
# same as count different return
trunk = self.root_node
keyslist = []
result = self.recurs_helper(trunk, keyslist)
#print(result)
return result
def recurs_helper(self, branch, alist):
if branch == None:
pass
else:
left_sprout = branch.left
right_sprout = branch.right
if left_sprout:
self.list_add(left_sprout, alist)
if right_sprout:
self.list_add(right_sprout, alist)
self.recurs_helper(left_sprout, alist)
self.recurs_helper(right_sprout, alist)
return alist
def list_add(self, something, alist):
if something:
alist.append(something.key)
Comments
Post a Comment