mirror of
https://github.com/autistic-symposium/master-algorithms-py.git
synced 2025-04-29 20:26:07 -04:00
fix few details, binary search trees
This commit is contained in:
parent
5a7a97b25f
commit
f77b8eaaf2
Binary file not shown.
@ -1,68 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BT import BT
|
||||
|
||||
class BST(BT):
|
||||
def __init__(self, value=None):
|
||||
self.value = value
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
def insert_left(self, new_node):
|
||||
self.insert(value)
|
||||
|
||||
def insert_right(self, new_node):
|
||||
self.insert(value)
|
||||
|
||||
|
||||
def insert(self, value):
|
||||
if self.value == None:
|
||||
self.value = value
|
||||
else:
|
||||
if value > self.value:
|
||||
self.right = self.right and self.right.insert(value) or BST(value)
|
||||
else:
|
||||
self.left = self.left and self.left.insert(value) or BST(value)
|
||||
return self
|
||||
|
||||
def find(self, value):
|
||||
if value == self.value:
|
||||
return self
|
||||
elif value > self.value and self.right:
|
||||
return self.right.find(value)
|
||||
elif self.left:
|
||||
return self.left.find(value)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
BST
|
||||
4
|
||||
2 6
|
||||
1 3 5 7
|
||||
"""
|
||||
tree = BST()
|
||||
tree.insert(4)
|
||||
tree.insert(2)
|
||||
tree.insert(6)
|
||||
tree.insert(1)
|
||||
tree.insert(3)
|
||||
tree.insert(7)
|
||||
tree.insert(5)
|
||||
print(tree.get_right())
|
||||
print(tree.get_right().get_left())
|
||||
print(tree.get_right().get_right())
|
||||
print(tree.get_left())
|
||||
print(tree.get_left().get_left())
|
||||
print(tree.get_left().get_right() == 1)
|
||||
assert(tree.find(30) == None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -1,66 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
class Node(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
def __repr__(self):
|
||||
return '{}'.format(self.value)
|
||||
|
||||
|
||||
class BSTwithNodes(object):
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
|
||||
|
||||
def insert(self, value):
|
||||
if self.root == None:
|
||||
self.root = Node(value)
|
||||
else:
|
||||
current = self.root
|
||||
while True:
|
||||
if value < current.value:
|
||||
if current.left:
|
||||
current = current.left
|
||||
else:
|
||||
current.left = Node(value)
|
||||
break;
|
||||
|
||||
elif value > current.value:
|
||||
if current.right:
|
||||
current = current.right
|
||||
else:
|
||||
current.right = Node(value)
|
||||
break;
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
BST
|
||||
4
|
||||
2 6
|
||||
1 3 5 7
|
||||
"""
|
||||
tree = BSTwithNodes()
|
||||
l1 = [4, 2, 6, 1, 3, 7, 5]
|
||||
for i in l1: tree.insert(i)
|
||||
print(tree.root)
|
||||
print(tree.root.right)
|
||||
print(tree.root.right.left)
|
||||
print(tree.root.right.right)
|
||||
print(tree.root.left)
|
||||
print(tree.root.left.left)
|
||||
print(tree.root.left.right)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -1,72 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
class BT(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
|
||||
def get_right(self):
|
||||
return self.right
|
||||
|
||||
def get_left(self):
|
||||
return self.left
|
||||
|
||||
def is_leaf(self):
|
||||
return self.left is None and self.right is None
|
||||
|
||||
def set_root(self, obj):
|
||||
self.value = obj
|
||||
|
||||
def get_root(self):
|
||||
return self.value
|
||||
|
||||
def insert_left(self, new_node):
|
||||
if self.left == None:
|
||||
self.left = BT(new_node)
|
||||
else:
|
||||
t = BT(self.left)
|
||||
t.left = new_node
|
||||
self.left = t
|
||||
|
||||
def insert_right(self, new_node):
|
||||
if self.right == None:
|
||||
self.right = BT(new_node)
|
||||
else:
|
||||
t = BT(self.right)
|
||||
t.right = new_node
|
||||
self.right = t
|
||||
|
||||
def __repr__(self):
|
||||
return '{}'.format(self.value)
|
||||
|
||||
|
||||
|
||||
def tests_BT():
|
||||
"""
|
||||
1
|
||||
2 3
|
||||
4 5 6 7
|
||||
"""
|
||||
tree = BT(1)
|
||||
tree.insert_left(2)
|
||||
tree.insert_right(3)
|
||||
tree.get_left().insert_left(4)
|
||||
tree.get_left().insert_right(5)
|
||||
tree.get_right().insert_left(6)
|
||||
tree.get_right().insert_right(7)
|
||||
print(tree.get_right().get_right())
|
||||
tree.get_right().get_right().set_root(8)
|
||||
print(tree.get_right().get_right())
|
||||
assert(tree.get_right().is_leaf() == False)
|
||||
assert(tree.get_right().get_right().is_leaf() == True)
|
||||
print("Tests Passed!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tests_BT()
|
||||
|
@ -1,61 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def BinaryTreeList(r):
|
||||
''' constructs a list with a root and 2 empty sublists for the children. To add a left subtree to the root of a tree, we need to insert a new list into the second position of the root list '''
|
||||
return [r, [], []]
|
||||
|
||||
|
||||
def insertLeft(root, newBranch):
|
||||
t = root.pop(1)
|
||||
if len(t) > 1:
|
||||
root.insert(1,[newBranch,t,[]])
|
||||
else:
|
||||
root.insert(1,[newBranch, [], []])
|
||||
return root
|
||||
|
||||
|
||||
def insertRight(root, newBranch):
|
||||
t = root.pop(2)
|
||||
if len(t) > 1:
|
||||
root.insert(2,[newBranch,[],t])
|
||||
else:
|
||||
root.insert(2,[newBranch,[],[]])
|
||||
return root
|
||||
|
||||
def getRootVal(root):
|
||||
return root[0]
|
||||
|
||||
def setRootVal(root, newVal):
|
||||
root[0] = newVal
|
||||
|
||||
def getLeftChild(root):
|
||||
return root[1]
|
||||
|
||||
def getRightChild(root):
|
||||
return root[2]
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
'''
|
||||
3
|
||||
[5, [4, [], []], []]
|
||||
[7, [], [6, [], []]]
|
||||
'''
|
||||
|
||||
r = BinaryTreeList(3)
|
||||
insertLeft(r,4)
|
||||
insertLeft(r,5)
|
||||
insertRight(r,6)
|
||||
insertRight(r,7)
|
||||
print(getRootVal(r))
|
||||
print(getLeftChild(r))
|
||||
print(getRightChild(r))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -1,140 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST_with_Nodes import BSTwithNodes, Node
|
||||
|
||||
|
||||
class AVL(BSTwithNodes):
|
||||
"""AVL binary search tree implementation.
|
||||
Supports insert, find, and delete-min operations in O(lg n) time.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
|
||||
def left_rotate(self, x):
|
||||
y = x.right
|
||||
y.value = x.value
|
||||
if y.value is None:
|
||||
self.root = y
|
||||
else:
|
||||
if y.value.left is x:
|
||||
y.value.left = y
|
||||
elif y.value.right is x:
|
||||
y.value.right = y
|
||||
x.right = y.left
|
||||
if x.right is not None:
|
||||
x.right.value = x
|
||||
y.left = x
|
||||
x.value = y
|
||||
update_height(x)
|
||||
update_height(y)
|
||||
|
||||
def right_rotate(self, x):
|
||||
y = x.left
|
||||
y.value = x.value
|
||||
if y.value is None:
|
||||
self.root = y
|
||||
else:
|
||||
if y.value.left is x:
|
||||
y.value.left = y
|
||||
elif y.value.right is x:
|
||||
y.value.right = y
|
||||
x.left = y.right
|
||||
if x.left is not None:
|
||||
x.left.value = x
|
||||
y.right = x
|
||||
x.value = y
|
||||
update_height(x)
|
||||
update_height(y)
|
||||
|
||||
def insert_item(self, value):
|
||||
if self.root == None:
|
||||
self.root = Node(value)
|
||||
else:
|
||||
current = self.root
|
||||
while True:
|
||||
if value < current.value:
|
||||
if current.left:
|
||||
current = current.left
|
||||
else:
|
||||
current.left = Node(value)
|
||||
break;
|
||||
|
||||
elif value > current.value:
|
||||
if current.right:
|
||||
current = current.right
|
||||
else:
|
||||
current.right = Node(value)
|
||||
break;
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
def insert(self, value):
|
||||
node = self.insert_item(value)
|
||||
self.rebalance(node)
|
||||
|
||||
|
||||
def rebalance(self, node):
|
||||
while node is not None:
|
||||
update_height(node)
|
||||
if height(node.left) >= 2 + height(node.right):
|
||||
if height(node.left.left) >= height(node.left.right):
|
||||
self.right_rotate(node)
|
||||
else:
|
||||
self.left_rotate(node.left)
|
||||
self.right_rotate(node)
|
||||
elif height(node.right) >= 2 + height(node.left):
|
||||
if height(node.right.right) >= height(node.right.left):
|
||||
self.left_rotate(node)
|
||||
else:
|
||||
self.right_rotate(node.right)
|
||||
self.left_rotate(node)
|
||||
node = node.value
|
||||
|
||||
|
||||
def inorder(self, node):
|
||||
if node is not None:
|
||||
self.inorder(node.left)
|
||||
print(node.value)
|
||||
self.inorder(node.right)
|
||||
|
||||
def preorder(self, node):
|
||||
if node is not None:
|
||||
print(node.value)
|
||||
self.preorder(node.left)
|
||||
self.preorder(node.right)
|
||||
|
||||
def postorder(self, node):
|
||||
if node is not None:
|
||||
self.postorder(node.left)
|
||||
self.postorder(node.right)
|
||||
print(node.value)
|
||||
|
||||
|
||||
def height(node):
|
||||
if node is None: return -1
|
||||
else: return node.height
|
||||
|
||||
def update_height(node):
|
||||
node.height = max(height(node.left), height(node.right)) + 1
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
tree = AVL()
|
||||
tree.insert(4)
|
||||
tree.insert(2)
|
||||
tree.insert(6)
|
||||
tree.insert(1)
|
||||
tree.insert(3)
|
||||
tree.insert(7)
|
||||
tree.insert(5)
|
||||
print('Inorder Traversal:')
|
||||
tree.inorder(tree.root)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,102 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch 2013
|
||||
|
||||
from binary_tree import BinaryTree, NodeBT
|
||||
|
||||
''' Implementation of a binary search tree and its properties.
|
||||
We use the Binary Tree class and its Node class as superclasses, and we modify the methods
|
||||
that are needeed to create a BST (polymorphism). For example, the following bst:
|
||||
|
||||
7 ---> level 0
|
||||
4 9 ---> level 1
|
||||
2 5 8 10 ---> level 2
|
||||
1 6 ---> level 3
|
||||
|
||||
has the following properties:
|
||||
|
||||
- SIZE OR NUMBER OF NODES: n = 10
|
||||
- NUMBER OF BRANCHES OR INTERNAL NODES: b = n-1 = 9
|
||||
- VALUE OF ROOT = 7
|
||||
- MAX_DEPTH OR HEIGHT: h = 3
|
||||
- IS BALANCED? YES
|
||||
- IS BST? YES
|
||||
- INORDER DFT: 1, 2, 4, 5, 6, 7, 8, 9, 10
|
||||
- POSTORDER DFT: 1, 2, 6, 5, 4, 8, 10, 9, 7
|
||||
- PREORDER DFT: 7, 4, 2, 1, 5, 6, 9, 8, 10
|
||||
- BFT: 7, 4, 9, 2, 5, 8, 10, 1, 6
|
||||
'''
|
||||
|
||||
|
||||
class NodeBST(NodeBT):
|
||||
|
||||
def _addNextNode(self, value, level_here=1):
|
||||
''' Aux for self.addNode(value): for BST, best O(1), worst O(log n) '''
|
||||
self.traversal = []
|
||||
new_node = NodeBST(value, level_here)
|
||||
if not self.item:
|
||||
self.item = new_node
|
||||
elif value < self.item:
|
||||
self.left = self.left and self.left._addNextNode(value, level_here+1) or new_node
|
||||
else:
|
||||
self.right = self.right and self.right._addNextNode(value, level_here+1) or new_node
|
||||
return self
|
||||
|
||||
def _searchForNode(self, value):
|
||||
''' Traverse the tree looking for the node. For BST it is O(logn) if the
|
||||
tree is balanced, otherwise it can be O(n) '''
|
||||
if self.item == value: return self
|
||||
elif value > self.item and self.right: return self.right._findNode(value)
|
||||
elif value < self.item and self.left: return self.left._findNode(value)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class BinarySearchTree(BinaryTree):
|
||||
'''
|
||||
>>> bst = BinarySearchTree()
|
||||
>>> l1 = [7, 4, 5, 9, 2, 8, 1, 6, 10]
|
||||
>>> for i in l1: bst.addNode(i)
|
||||
>>> bst.hasNode(3)
|
||||
False
|
||||
>>> bst.hasNode(10)
|
||||
True
|
||||
>>> bst.printTree('pre')
|
||||
[7, 4, 2, 1, 5, 6, 9, 8, 10]
|
||||
>>> bst.printTree('post')
|
||||
[1, 2, 6, 5, 4, 8, 10, 9, 7]
|
||||
>>> bst.printTree('in')
|
||||
[1, 2, 4, 5, 6, 7, 8, 9, 10]
|
||||
>>> bst.printTree('bft')
|
||||
[7, 4, 9, 2, 5, 8, 10, 1, 6]
|
||||
>>> bst.getHeight()
|
||||
3
|
||||
>>> bst.isBST()
|
||||
True
|
||||
>>> bst.isBalanced()
|
||||
False
|
||||
>>> bst.isBalanced(2)
|
||||
False
|
||||
>>> bst.getAncestor(2, 9)
|
||||
7
|
||||
>>> bst.getAncestor(2, 9, 'bst')
|
||||
7
|
||||
>>> bst.getAncestor(2, 9, 'pre-post')
|
||||
7
|
||||
>>> bst.getAncestor(2, 9, 'post-in')
|
||||
7
|
||||
'''
|
||||
|
||||
|
||||
def addNode(self, value):
|
||||
''' Add new node to the tree, by the left first, O(n).
|
||||
The only difference from the Binary Tree class is the node class is
|
||||
NodeBST and not NodeBT '''
|
||||
if not self.root: self.root = NodeBST(value)
|
||||
else: self.root._addNextNode(value)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
@ -1,56 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
from BT import BT
|
||||
|
||||
def is_bst(root, min=float('-inf'), max=float('inf')):
|
||||
left, right, value = root.left, root.right, root.value
|
||||
if min < value < max:
|
||||
if left and right:
|
||||
return is_bst(left, min, value) and is_bst(right, value, max)
|
||||
elif left:
|
||||
return is_bst(left, min, value)
|
||||
elif right:
|
||||
return is_bst(right, value, max)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
BST
|
||||
4
|
||||
2 6
|
||||
1 3 5 7
|
||||
|
||||
BT
|
||||
4
|
||||
2 6
|
||||
1 8 5 7
|
||||
"""
|
||||
bst = BT(4)
|
||||
bst.insert_left(2)
|
||||
bst.insert_right(6)
|
||||
bst.get_left().insert_left(1)
|
||||
bst.get_left().insert_right(3)
|
||||
bst.get_right().insert_left(5)
|
||||
bst.get_right().insert_right(7)
|
||||
print('is_bst(bst) =', is_bst(bst))
|
||||
|
||||
bt = BT(4)
|
||||
bt.insert_left(2)
|
||||
bt.insert_right(6)
|
||||
bt.get_left().insert_left(1)
|
||||
bt.get_left().insert_right(8)
|
||||
bt.get_right().insert_left(5)
|
||||
bt.get_right().insert_right(7)
|
||||
print('is_bst(bt) =', is_bst(bt))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
|
73
src/trees/binary_search_tree.py
Normal file
73
src/trees/binary_search_tree.py
Normal file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Mari Wahl"
|
||||
__email__ = "marina.w4hl@gmail.com"
|
||||
|
||||
|
||||
from binary_tree import NodeBT, BinaryTree
|
||||
|
||||
|
||||
class NodeBST(NodeBT):
|
||||
|
||||
def __init__(self, item=None, level=0):
|
||||
self.item = item
|
||||
self.level = level
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
|
||||
def _addNextNode(self, value, level_here=1):
|
||||
new_node = NodeBST(value, level_here)
|
||||
if not self.item:
|
||||
self.item = new_node
|
||||
else:
|
||||
if value > self.item:
|
||||
self.right = self.right and self.right._addNextNode(value, level_here+1) or new_node
|
||||
elif value < self.item:
|
||||
self.left = self.left and self.left._addNextNode(value, level_here+1) or new_node
|
||||
else:
|
||||
print("BSTs do not support repeated items.")
|
||||
return self # this is necessary!!!
|
||||
|
||||
|
||||
|
||||
def _searchForNode(self, value):
|
||||
if self.item == value:
|
||||
return self
|
||||
elif self.left and value < self.item:
|
||||
return self.left._searchForNode(value)
|
||||
elif self.right and value > self.item:
|
||||
return self.right._searchForNode(value)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
class BinarySearchTree(BinaryTree):
|
||||
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
|
||||
def addNode(self, value):
|
||||
if not self.root:
|
||||
self.root = NodeBST(value)
|
||||
else:
|
||||
self.root._addNextNode(value)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
bst = BinarySearchTree()
|
||||
print "Adding nodes 1 to 10 in the tree..."
|
||||
for i in range(1, 10):
|
||||
bst.addNode(i)
|
||||
print "Is 8 a leaf? ", bst.isLeaf(8)
|
||||
print "Whats the level of node 8? ", bst.getNodeLevel(8)
|
||||
print "Is node 10 a root? ", bst.isRoot(10)
|
||||
print "Is node 1 a root? ", bst.isRoot(1)
|
||||
print "Whats the tree height? ", bst.getHeight()
|
||||
print "Is this tree BST? ", bst.isBST()
|
||||
print "Is this tree balanced? ", bst.isBalanced()
|
||||
|
||||
|
@ -1,64 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Mari Wahl"
|
||||
__email__ = "marina.w4hl@gmail.com"
|
||||
|
||||
|
||||
''' constructs a list with a root and 2 empty sublists for the children. To add a left subtree to the root of a tree, we need to insert a new list into the second position of the root list '''
|
||||
|
||||
|
||||
def BinaryTreeList(r):
|
||||
return [r, [], []]
|
||||
|
||||
|
||||
def insertLeft(root, newBranch):
|
||||
t = root.pop(1)
|
||||
if len(t) > 1:
|
||||
root.insert(1,[newBranch,t,[]])
|
||||
else:
|
||||
root.insert(1,[newBranch, [], []])
|
||||
return root
|
||||
|
||||
|
||||
def insertRight(root, newBranch):
|
||||
t = root.pop(2)
|
||||
if len(t) > 1:
|
||||
root.insert(2,[newBranch,[],t])
|
||||
else:
|
||||
root.insert(2,[newBranch,[],[]])
|
||||
return root
|
||||
|
||||
def getRootVal(root):
|
||||
return root[0]
|
||||
|
||||
def setRootVal(root, newVal):
|
||||
root[0] = newVal
|
||||
|
||||
def getLeftChild(root):
|
||||
return root[1]
|
||||
|
||||
def getRightChild(root):
|
||||
return root[2]
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
'''
|
||||
3
|
||||
[5, [4, [], []], []]
|
||||
[7, [], [6, [], []]]
|
||||
'''
|
||||
|
||||
r = BinaryTreeList(3)
|
||||
insertLeft(r,4)
|
||||
insertLeft(r,5)
|
||||
insertRight(r,6)
|
||||
insertRight(r,7)
|
||||
print(getRootVal(r))
|
||||
print(getLeftChild(r))
|
||||
print(getRightChild(r))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user