mirror of
https://github.com/autistic-symposium/master-algorithms-py.git
synced 2025-05-23 00:41:19 -04:00
fixes
This commit is contained in:
parent
aa5010594e
commit
7b9e953f5a
194 changed files with 28 additions and 34 deletions
0
src/graphs_and_trees/trees/__init__.py
Normal file
0
src/graphs_and_trees/trees/__init__.py
Normal file
68
src/graphs_and_trees/trees/binary_trees/BST.py
Normal file
68
src/graphs_and_trees/trees/binary_trees/BST.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
#!/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()
|
||||
|
66
src/graphs_and_trees/trees/binary_trees/BST_with_Nodes.py
Normal file
66
src/graphs_and_trees/trees/binary_trees/BST_with_Nodes.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
#!/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()
|
||||
|
72
src/graphs_and_trees/trees/binary_trees/BT.py
Normal file
72
src/graphs_and_trees/trees/binary_trees/BT.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
#!/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()
|
||||
|
61
src/graphs_and_trees/trees/binary_trees/BT_lists.py
Normal file
61
src/graphs_and_trees/trees/binary_trees/BT_lists.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/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()
|
||||
|
0
src/graphs_and_trees/trees/binary_trees/__init__.py
Normal file
0
src/graphs_and_trees/trees/binary_trees/__init__.py
Normal file
140
src/graphs_and_trees/trees/binary_trees/avl.py
Normal file
140
src/graphs_and_trees/trees/binary_trees/avl.py
Normal file
|
@ -0,0 +1,140 @@
|
|||
#!/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()
|
56
src/graphs_and_trees/trees/binary_trees/veritfy_if_BST.py
Normal file
56
src/graphs_and_trees/trees/binary_trees/veritfy_if_BST.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
#!/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()
|
||||
|
||||
|
||||
|
0
src/graphs_and_trees/trees/simple_trees/__init__.py
Normal file
0
src/graphs_and_trees/trees/simple_trees/__init__.py
Normal file
23
src/graphs_and_trees/trees/simple_trees/bunchclass.py
Normal file
23
src/graphs_and_trees/trees/simple_trees/bunchclass.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
class BunchClass(dict):
|
||||
def __init__(self, *args, **kwds):
|
||||
super(BunchClass, self).__init__(*args, **kwds)
|
||||
self.__dict__ = self
|
||||
|
||||
|
||||
def main():
|
||||
''' {'right': {'right': 'Xander', 'left': 'Willow'}, 'left': {'right': 'Angel', 'left': 'Buffy'}}'''
|
||||
bc = BunchClass # notice the absence of ()
|
||||
tree = bc(left = bc(left="Buffy", right="Angel"), right = bc(left="Willow", right="Xander"))
|
||||
print(tree)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
|
||||
|
36
src/graphs_and_trees/trees/simple_trees/tree.py
Normal file
36
src/graphs_and_trees/trees/simple_trees/tree.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
class SimpleTree(object):
|
||||
def __init__(self, value, children = None):
|
||||
if children == None: children = []
|
||||
self.children = children
|
||||
self.value = value
|
||||
|
||||
def __repr__(self, level=0):
|
||||
ret = "\t"*level+repr(self.value)+"\n"
|
||||
for child in self.children:
|
||||
ret += child.__repr__(level+1)
|
||||
return ret
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
'a'
|
||||
'b'
|
||||
'd'
|
||||
'e'
|
||||
'c'
|
||||
'h'
|
||||
'g'
|
||||
"""
|
||||
st = SimpleTree('a', [SimpleTree('b', [SimpleTree('d'), SimpleTree('e')] ), SimpleTree('c', [SimpleTree('h'), SimpleTree('g')]) ])
|
||||
print(st)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
68
src/graphs_and_trees/trees/traversals/BST.py
Normal file
68
src/graphs_and_trees/trees/traversals/BST.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
#!/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()
|
||||
|
46
src/graphs_and_trees/trees/traversals/BST_ancestor.py
Normal file
46
src/graphs_and_trees/trees/traversals/BST_ancestor.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST_traversal import TranversalBST
|
||||
|
||||
def find_ancestor(path, low_value, high_value):
|
||||
''' find the lowest ancestor in a BST '''
|
||||
while path:
|
||||
current_value = path[0]
|
||||
if current_value < low_value:
|
||||
try:
|
||||
path = path[2:]
|
||||
except:
|
||||
return current_value
|
||||
elif current_value > high_value:
|
||||
try:
|
||||
path = path[1:]
|
||||
except:
|
||||
return current_value
|
||||
elif low_value <= current_value <= high_value:
|
||||
return current_value
|
||||
return None
|
||||
|
||||
|
||||
def test_find_ancestor():
|
||||
"""
|
||||
10
|
||||
5 15
|
||||
1 6 11 50
|
||||
"""
|
||||
t = TranversalBST()
|
||||
l1 = [10, 5, 15, 1, 6, 11, 50]
|
||||
for i in l1: t.insert(i)
|
||||
path = t.preorder()
|
||||
assert(find_ancestor(path, 1, 6) == 5)
|
||||
assert(find_ancestor(path, 1, 11) == 10)
|
||||
assert(find_ancestor(path, 11, 50) == 15)
|
||||
assert(find_ancestor(path, 5, 15) == 10)
|
||||
|
||||
|
||||
print("Tests passsed!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_find_ancestor()
|
||||
|
88
src/graphs_and_trees/trees/traversals/BST_traversal.py
Normal file
88
src/graphs_and_trees/trees/traversals/BST_traversal.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST import BST
|
||||
|
||||
class TranversalBST(object):
|
||||
def __init__(self):
|
||||
self.bst = BST(None)
|
||||
self.nodes = []
|
||||
|
||||
def insert(self, value):
|
||||
if not self.bst.value:
|
||||
self.bst.value = value
|
||||
else:
|
||||
self.bst.insert(value)
|
||||
|
||||
def contains(self, value):
|
||||
return bool(self.bst.find(value))
|
||||
|
||||
def get(self, index):
|
||||
for i, value in enumerate(self.inorder()):
|
||||
if i == index:
|
||||
return value
|
||||
|
||||
def inorder(self):
|
||||
current = self.bst
|
||||
self.nodes = []
|
||||
stack = []
|
||||
while len(stack) > 0 or current is not None:
|
||||
if current is not None:
|
||||
stack.append(current)
|
||||
current = current.left
|
||||
else:
|
||||
current = stack.pop()
|
||||
self.nodes.append(current.value)
|
||||
current = current.right
|
||||
return self.nodes
|
||||
|
||||
|
||||
def preorder(self):
|
||||
self.nodes = []
|
||||
stack = [self.bst]
|
||||
while len(stack) > 0:
|
||||
curr = stack.pop()
|
||||
if curr is not None:
|
||||
self.nodes.append(curr.value)
|
||||
stack.append(curr.right)
|
||||
stack.append(curr.left)
|
||||
return self.nodes
|
||||
|
||||
|
||||
def preorder2(self):
|
||||
self.nodes = []
|
||||
current = self.bst
|
||||
stack = []
|
||||
while len(stack) > 0 or current is not None:
|
||||
if current is not None:
|
||||
self.nodes.append(current.value)
|
||||
stack.append(current)
|
||||
current = current.left
|
||||
else:
|
||||
current = stack.pop()
|
||||
current = current.right
|
||||
return self.nodes
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
10
|
||||
5 15
|
||||
1 6 11 50
|
||||
"""
|
||||
t = TranversalBST()
|
||||
t.insert(10)
|
||||
t.insert(5)
|
||||
t.insert(15)
|
||||
t.insert(1)
|
||||
t.insert(6)
|
||||
t.insert(11)
|
||||
t.insert(50)
|
||||
print(t.preorder())
|
||||
print(t.preorder2())
|
||||
print(t.inorder())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST_with_Nodes import BSTwithNodes, Node
|
||||
|
||||
class BSTTraversal(BSTwithNodes):
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
self.nodes_BFS = []
|
||||
self.nodes_DFS_pre = []
|
||||
self.nodes_DFS_post = []
|
||||
self.nodes_DFS_in = []
|
||||
|
||||
def BFS(self):
|
||||
self.root.level = 0
|
||||
queue = [self.root]
|
||||
current_level = self.root.level
|
||||
|
||||
while len(queue) > 0:
|
||||
current_node = queue.pop(0)
|
||||
if current_node.level > current_level:
|
||||
current_level += 1
|
||||
self.nodes_BFS.append(current_node.value)
|
||||
|
||||
if current_node.left:
|
||||
current_node.left.level = current_level + 1
|
||||
queue.append(current_node.left)
|
||||
|
||||
if current_node.right:
|
||||
current_node.right.level = current_level + 1
|
||||
queue.append(current_node.right)
|
||||
|
||||
return self.nodes_BFS
|
||||
|
||||
def DFS_inorder(self, node):
|
||||
if node is not None:
|
||||
self.DFS_inorder(node.left)
|
||||
self.nodes_DFS_in.append(node.value)
|
||||
self.DFS_inorder(node.right)
|
||||
return self.nodes_DFS_in
|
||||
|
||||
def DFS_preorder(self, node):
|
||||
if node is not None:
|
||||
self.nodes_DFS_pre.append(node.value)
|
||||
self.DFS_preorder(node.left)
|
||||
self.DFS_preorder(node.right)
|
||||
return self.nodes_DFS_pre
|
||||
|
||||
def DFS_postorder(self, node):
|
||||
if node is not None:
|
||||
self.DFS_postorder(node.left)
|
||||
self.DFS_postorder(node.right)
|
||||
self.nodes_DFS_post.append(node.value)
|
||||
return self.nodes_DFS_post
|
||||
|
||||
def main():
|
||||
tree = BSTTraversal()
|
||||
l1 = [10, 5, 15, 1, 6, 11, 50]
|
||||
for i in l1: tree.insert(i)
|
||||
|
||||
print('Breadth-First Traversal: ', tree.BFS())
|
||||
print('Inorder Traversal: ', tree.DFS_inorder(tree.root))
|
||||
print('Preorder Traversal: ', tree.DFS_preorder(tree.root))
|
||||
print('Postorder Traversal: ', tree.DFS_postorder(tree.root))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST_traversal import TranversalBST
|
||||
from BST import BST
|
||||
|
||||
class BSTwithExtra(TranversalBST):
|
||||
def __init__(self):
|
||||
self.bst = BST(None)
|
||||
self.nodes = []
|
||||
|
||||
def get_inorder(self, k):
|
||||
for i, value in enumerate(self.inorder()):
|
||||
if value == k:
|
||||
return i
|
||||
|
||||
def get_preorder(self, k):
|
||||
for i, value in enumerate(self.preorder()):
|
||||
if value == k:
|
||||
return i
|
||||
|
||||
|
||||
def is_balanced(self, threshold=1):
|
||||
maxd = self.get_max_depth()
|
||||
mind = self.get_min_depth()
|
||||
print('Max depth: ' + str(maxd))
|
||||
print('Min depth: ' + str(mind))
|
||||
return maxd -mind
|
||||
|
||||
def get_min_depth(self, node=None, initial=1):
|
||||
if node is None and initial == 1:
|
||||
node = self.bst
|
||||
if node.left and node.right:
|
||||
return 1 + min(self.get_min_depth(node.left, 0),
|
||||
self.get_min_depth(node.right, 0))
|
||||
else:
|
||||
if node.left:
|
||||
return 1 + self.get_max_depth(node.left, 0)
|
||||
elif node.right:
|
||||
return 1 + self.get_max_depth(node.right, 0)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_max_depth(self, node=None, initial=1):
|
||||
if node is None and initial == 1:
|
||||
node = self.bst
|
||||
if node.left and node.right:
|
||||
return 1 + max(self.get_max_depth(node.left, 0),
|
||||
self.get_max_depth(node.right, 0))
|
||||
else:
|
||||
if node.left:
|
||||
return 1 + self.get_max_depth(node.left, 0)
|
||||
elif node.right:
|
||||
return 1 + self.get_max_depth(node.right, 0)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def main():
|
||||
"""
|
||||
10
|
||||
5 15
|
||||
1 6 11 50
|
||||
60
|
||||
70
|
||||
80
|
||||
"""
|
||||
t = BSTwithExtra()
|
||||
l1 = [10, 5, 15, 1, 6, 11, 50, 60, 70, 80]
|
||||
for i in l1: t.insert(i)
|
||||
print(t.inorder())
|
||||
print(t.preorder())
|
||||
assert(t.get_max_depth() == 5)
|
||||
assert(t.get_min_depth() == 2)
|
||||
assert(t.is_balanced() == 3)
|
||||
assert(t.get_inorder(10) == 3)
|
||||
assert(t.get_preorder(10) == 0)
|
||||
|
||||
|
||||
"""
|
||||
1
|
||||
2 3
|
||||
4 5 6 7
|
||||
"""
|
||||
t2 = BSTwithExtra()
|
||||
l2 = [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
for i in l2: t2.insert(i)
|
||||
print(t2.inorder())
|
||||
print(t2.preorder())
|
||||
assert(t2.is_balanced() == 0)
|
||||
|
||||
print("Tests Passed!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
src/graphs_and_trees/trees/traversals/__init__.py
Normal file
0
src/graphs_and_trees/trees/traversals/__init__.py
Normal file
102
src/graphs_and_trees/trees_graphs/binary_search_tree.py
Normal file
102
src/graphs_and_trees/trees_graphs/binary_search_tree.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
#!/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()
|
||||
|
464
src/graphs_and_trees/trees_graphs/binary_tree.py
Normal file
464
src/graphs_and_trees/trees_graphs/binary_tree.py
Normal file
|
@ -0,0 +1,464 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch 2013
|
||||
# http://astro.sunysb.edu/steinkirch
|
||||
|
||||
|
||||
|
||||
|
||||
''' Implementation of a binary tree and its properties. For example, the following bt:
|
||||
|
||||
1 ---> level 0
|
||||
2 3 ---> level 1
|
||||
4 5 ---> level 2
|
||||
6 7 ---> level 3
|
||||
8 9 ---> level 4
|
||||
|
||||
has the following properties:
|
||||
|
||||
- SIZE OR NUMBER OF NODES: n = 9
|
||||
- NUMBER OF BRANCHES OR INTERNAL NODES: b = n-1 = 8
|
||||
- VALUE OF ROOT = 1
|
||||
- MAX_DEPTH OR HEIGHT: h = 4
|
||||
- IS BALANCED? NO
|
||||
- IS BST? NO
|
||||
- INORDER DFT: 8, 6, 9, 4, 7, 2, 5, 1, 3
|
||||
- POSTORDER DFT: 8, 9, 6, 7, 4, 5, 2, 3, 1
|
||||
- PREORDER DFT: 1, 2, 4, 6, 8, 9, 7, 5, 3
|
||||
- BFT: 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
'''
|
||||
|
||||
from collections import deque
|
||||
class NodeBT(object):
|
||||
def __init__(self, item=None, level=0):
|
||||
''' Construtor for a Node in the Tree '''
|
||||
self.item = item
|
||||
self.level = level
|
||||
self.left = None
|
||||
self.right = None
|
||||
self.traversal = []
|
||||
#self.parent = None # not used here but can be necessary for some problems
|
||||
|
||||
'''
|
||||
METHODS TO MODIFY NODES
|
||||
'''
|
||||
|
||||
def _addNextNode(self, value, level_here=1):
|
||||
''' Aux for self.addNode(value)'''
|
||||
self.traversal = []
|
||||
new_node = NodeBT(value, level_here)
|
||||
if not self.item:
|
||||
self.item = new_node
|
||||
elif not self.left:
|
||||
self.left = new_node
|
||||
elif not self.right:
|
||||
self.right = new_node
|
||||
else:
|
||||
self.left = self.left._addNextNode(value, level_here+1)
|
||||
return self
|
||||
|
||||
|
||||
|
||||
'''
|
||||
METHODS TO PRINT/SHOW NODES' ATTRIBUTES
|
||||
'''
|
||||
|
||||
def __repr__(self):
|
||||
''' Private method for this class'string representation'''
|
||||
return '{}'.format(self.item)
|
||||
|
||||
def _getDFTpreOrder(self, node):
|
||||
''' Traversal Pre-Order, O(n)'''
|
||||
if node:
|
||||
if node.item: self.traversal.append(node.item)
|
||||
self._getDFTpreOrder(node.left)
|
||||
self._getDFTpreOrder(node.right)
|
||||
return self
|
||||
|
||||
def _printDFTpreOrder(self, noderoot):
|
||||
''' Fill the pre-order traversal array '''
|
||||
self.traversal = []
|
||||
self._getDFTpreOrder(noderoot)
|
||||
return self.traversal
|
||||
|
||||
def _getDFTinOrder(self, node):
|
||||
''' Traversal in-Order, O(n)'''
|
||||
if node:
|
||||
self._getDFTinOrder(node.left)
|
||||
if node.item: self.traversal.append(node.item)
|
||||
self._getDFTinOrder(node.right)
|
||||
return self
|
||||
|
||||
def _printDFTinOrder(self, noderoot):
|
||||
''' Fill the in-order traversal array '''
|
||||
self.traversal = []
|
||||
self._getDFTinOrder(noderoot)
|
||||
return self.traversal
|
||||
|
||||
def _getDFTpostOrder(self, node):
|
||||
''' Traversal post-Order, O(n)'''
|
||||
if node:
|
||||
self._getDFTpostOrder(node.left)
|
||||
self._getDFTpostOrder(node.right)
|
||||
if node.item: self.traversal.append(node.item)
|
||||
return self
|
||||
|
||||
def _getBFT(self, node):
|
||||
''' Traversal bft, O(n)'''
|
||||
if node:
|
||||
queue = deque()
|
||||
queue.append(node)
|
||||
while len(queue) > 0:
|
||||
current = queue.popleft()
|
||||
if current.item: self.traversal.append(current)
|
||||
if current.left: queue.append(current.left)
|
||||
if current.right: queue.append(current.right)
|
||||
return self
|
||||
|
||||
def _printBFT(self, noderoot):
|
||||
''' Fill the in-order traversal array '''
|
||||
self.traversal = []
|
||||
self._getBFT(noderoot)
|
||||
return self.traversal
|
||||
|
||||
|
||||
def _printDFTpostOrder(self, noderoot):
|
||||
''' Fill the post-order traversal array '''
|
||||
self.traversal = []
|
||||
self._getDFTpostOrder(noderoot)
|
||||
return self.traversal
|
||||
|
||||
def _searchForNode(self, value):
|
||||
''' Traverse the tree looking for the node'''
|
||||
if self.item == value: return self
|
||||
else:
|
||||
found = None
|
||||
if self.left: found = self.left._searchForNode(value)
|
||||
if self.right: found = found or self.right._searchForNode(value)
|
||||
return found
|
||||
|
||||
def _findNode(self, value):
|
||||
''' Find whether a node is in the tree.
|
||||
if the traversal was calculated, it is just a membership
|
||||
checking, which is O(1), otherwise it is necessary to traverse
|
||||
the binary tree, so best case is O(1) and worst is O(n). '''
|
||||
if self.traversal: return value in self.traversal
|
||||
else: return self._searchForNode(value)
|
||||
|
||||
def _isLeaf(self):
|
||||
''' Return True if the node is a leaf '''
|
||||
return not self.right and not self.left
|
||||
|
||||
def _getMaxHeight(self):
|
||||
''' Get the max height at the node, O(n)'''
|
||||
levelr, levell = 0, 0
|
||||
if self.right:
|
||||
levelr = self.right._getMaxHeight() + 1
|
||||
if self.left:
|
||||
levell = self.left._getMaxHeight() + 1
|
||||
return max(levelr, levell)
|
||||
|
||||
def _getMinHeight(self, level=0):
|
||||
''' Get the min height at the node, O(n)'''
|
||||
levelr, levell = -1, -1
|
||||
if self.right:
|
||||
levelr = self.right._getMinHeight(level +1)
|
||||
if self.left:
|
||||
levell = self.left._getMinHeight(level +1)
|
||||
return min(levelr, levell) + 1
|
||||
|
||||
def _isBalanced(self):
|
||||
''' Find whether the tree is balanced, by calculating heights first, O(n2) '''
|
||||
if self._getMaxHeight() - self._getMinHeight() < 2:
|
||||
return False
|
||||
else:
|
||||
if self._isLeaf():
|
||||
return True
|
||||
elif self.left and self.right:
|
||||
return self.left._isBalanced() and self.right._isBalanced()
|
||||
elif not self.left and self.right:
|
||||
return self.right._isBalanced()
|
||||
elif not self.right and self.left:
|
||||
return self.right._isBalanced()
|
||||
|
||||
|
||||
|
||||
def _isBalancedImproved(self):
|
||||
''' Find whehter the tree is balanced in each node, O(n) '''
|
||||
return 'To Be written'
|
||||
|
||||
''' There are two solutions to check whether a bt is a bst:
|
||||
(1) Do an inorder, check if the inorder is sorted. However inorder
|
||||
can't handle the difference between duplicate values on the left
|
||||
or on the right (if it is in the right, the tree is not bst).
|
||||
'''
|
||||
|
||||
|
||||
def _isBST(self):
|
||||
''' Find whether the tree is a BST, inorder '''
|
||||
if self.item:
|
||||
if self._isLeaf(): return True
|
||||
elif self.left:
|
||||
if self.left.item < self.item: return self.left._isBST()
|
||||
else: return False
|
||||
elif self.right:
|
||||
if self.right.item > self.item: return self.right._isBST()
|
||||
else: return False
|
||||
else:
|
||||
raise Exception('Tree is empty')
|
||||
|
||||
|
||||
def _getAncestorBST(self, n1, n2):
|
||||
''' Return the ancestor of two nodes if it is a bst.
|
||||
we are supposing the values in the tree are unique.'''
|
||||
if n1 == self.item or n2 == self.item : return self.item
|
||||
elif self.item < n1 and self.item < n2:
|
||||
self.right.getAncestorBST(n1, n2)
|
||||
elif self.item > n1 and self.item > n2:
|
||||
self.left.getAncestorBST(n1, n2)
|
||||
else:
|
||||
return self.item
|
||||
|
||||
|
||||
|
||||
|
||||
class BinaryTree(object):
|
||||
'''
|
||||
>>> bt = BinaryTree()
|
||||
>>> for i in range(1, 10): bt.addNode(i)
|
||||
>>> bt.hasNode(7)
|
||||
True
|
||||
>>> bt.hasNode(12)
|
||||
False
|
||||
>>> bt.printTree()
|
||||
[1, 2, 4, 6, 8, 9, 7, 5, 3]
|
||||
>>> bt.printTree('pre')
|
||||
[1, 2, 4, 6, 8, 9, 7, 5, 3]
|
||||
>>> bt.printTree('bft')
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
>>> bt.printTree('post')
|
||||
[8, 9, 6, 7, 4, 5, 2, 3, 1]
|
||||
>>> bt.printTree('in')
|
||||
[8, 6, 9, 4, 7, 2, 5, 1, 3]
|
||||
>>> bt.hasNode(9)
|
||||
True
|
||||
>>> bt.hasNode(11)
|
||||
False
|
||||
>>> bt.isLeaf(8)
|
||||
True
|
||||
>>> bt.getNodeLevel(1)
|
||||
0
|
||||
>>> bt.getNodeLevel(8)
|
||||
4
|
||||
>>> bt.getSizeTree()
|
||||
9
|
||||
>>> bt.isRoot(10)
|
||||
False
|
||||
>>> bt.isRoot(1)
|
||||
True
|
||||
>>> bt.getHeight()
|
||||
4
|
||||
>>> bt.isBST(1)
|
||||
False
|
||||
>>> bt.isBalanced()
|
||||
False
|
||||
>>> bt.isBalanced(2)
|
||||
False
|
||||
>>> bt.getAncestor(8, 5)
|
||||
2
|
||||
>>> bt.getAncestor(8, 5, 'pre-post')
|
||||
2
|
||||
>>> bt.getAncestor(8, 5, 'post-in')
|
||||
2
|
||||
'''
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
''' Construtor for the Binary Tree, which is a container of Nodes'''
|
||||
self.root = None
|
||||
|
||||
|
||||
'''
|
||||
METHODS TO MODIFY THE TREE
|
||||
'''
|
||||
|
||||
def addNode(self, value):
|
||||
''' Add new node to the tree, by the left first, O(n) '''
|
||||
if not self.root: self.root = NodeBT(value)
|
||||
else: self.root._addNextNode(value)
|
||||
|
||||
'''
|
||||
METHODS TO PRINT/SHOW TREES' ATTRIBUTES
|
||||
'''
|
||||
|
||||
def __repr__(self):
|
||||
''' Private method for this class'string representation'''
|
||||
return '{}'.format(self.item)
|
||||
|
||||
def printTree(self, order = 'pre'):
|
||||
''' Print Tree in the chosen order '''
|
||||
if self.root:
|
||||
if order == 'pre': return self.root._printDFTpreOrder(self.root)
|
||||
elif order == 'in': return self.root._printDFTinOrder(self.root)
|
||||
elif order == 'post': return self.root._printDFTpostOrder(self.root)
|
||||
elif order == 'bft': return self.root._printBFT(self.root)
|
||||
else: raise Exception('Tree is empty')
|
||||
|
||||
def hasNode(self, value):
|
||||
''' Verify whether the node is in the Tree '''
|
||||
return bool(self.root._findNode(value))
|
||||
|
||||
def isLeaf(self, value):
|
||||
''' Return True if the node is a Leaf '''
|
||||
node = self.root._searchForNode(value)
|
||||
return node._isLeaf()
|
||||
|
||||
def getNodeLevel(self, item):
|
||||
''' Return the level of the node, best O(1), worst O(n) '''
|
||||
node = self.root._searchForNode(item)
|
||||
if node: return node.level
|
||||
else: raise Exception('Node not found')
|
||||
|
||||
def getSizeTree(self):
|
||||
''' Return how many nodes in the tree, O(n) '''
|
||||
return len(self.root._printDFTpreOrder(self.root))
|
||||
|
||||
def isRoot(self, value):
|
||||
'''Return the root of the tree '''
|
||||
return self.root.item == value
|
||||
|
||||
def getHeight(self):
|
||||
''' Returns the height/depth of the tree, best/worst O(n) '''
|
||||
return self.root._getMaxHeight()
|
||||
|
||||
def isBalanced(self, method=1):
|
||||
''' Return True if the tree is balanced'''
|
||||
if method == 1:
|
||||
''' O(n2)'''
|
||||
return self.root._isBalanced()
|
||||
else:
|
||||
''' O(n)'''
|
||||
return self.root._isBalancedImproved()
|
||||
|
||||
|
||||
|
||||
''' The followin methods are for searching the lowest common ancestor
|
||||
in a BT. Since a simple BT does not have ordering, it can be O(n). If
|
||||
we have a link for the ancestors, the steps are:
|
||||
(1) search both trees in order to find the nodes separately
|
||||
(2) list all ancestors
|
||||
(3) find first that mach
|
||||
obs: if we do this too many times we can do a pre and use the methods here'''
|
||||
|
||||
def isBST(self, method=1):
|
||||
''' Return True if the tree is BST'''
|
||||
if method == 1:
|
||||
inorder = self.root._printDFTinOrder(self.root)
|
||||
return inorder == sorted(inorder)
|
||||
elif method == 2:
|
||||
return self.root._isBST()
|
||||
|
||||
|
||||
def _getAncestorPreIn(self, preorder, inorder, value1, value2):
|
||||
''' Return the ancestor of two nodes with pre and in'''
|
||||
root = preorder[0]
|
||||
preorder = preorder[1:]
|
||||
i = 0
|
||||
item = inorder[0]
|
||||
value1left, value2left = False, False
|
||||
while item != root and i < len(inorder):
|
||||
if item == value1: value1left = True
|
||||
elif item == value2: value2left = True
|
||||
i += 1
|
||||
item = inorder[i]
|
||||
if (value1left and not value2left) or (value2left and not value1left):
|
||||
return root
|
||||
else:
|
||||
return self._getAncestorPreIn(preorder, inorder[:i] + inorder[i+1:], value1, value2)
|
||||
|
||||
def _getAncestorPrePost(self, preorder, postorder, value1, value2):
|
||||
''' Return the ancestor of two nodes with pre and post'''
|
||||
root = preorder[0]
|
||||
preorder = preorder[1:]
|
||||
postorder = postorder[:-1]
|
||||
value1right, value2right = False, False
|
||||
i = len(postorder)-1
|
||||
itempre = preorder[0]
|
||||
itempos = postorder[i]
|
||||
while itempre != itempos and i > 0:
|
||||
if itempos == value1: value1right = True
|
||||
elif itempos == value2: value2right = True
|
||||
i -= 1
|
||||
itempos = postorder[i]
|
||||
|
||||
if (value1right and not value2right) or (value2right and not value1right):
|
||||
return root
|
||||
else:
|
||||
return self._getAncestorPrePost(preorder, postorder[:i] + postorder[i+1:], value1, value2)
|
||||
|
||||
def _getAncestorInPost(self, inorder, postorder, value1, value2):
|
||||
''' Return the ancestor of two nodes with in and post'''
|
||||
root = postorder[-1]
|
||||
postorder = postorder[:-1]
|
||||
value1left, value2left = False, False
|
||||
i = 0
|
||||
item = inorder[i]
|
||||
while item != root and i < len(inorder):
|
||||
if item == value1: value1left = True
|
||||
elif item == value2: value2left = True
|
||||
i += 1
|
||||
item = inorder[i]
|
||||
|
||||
if (value1left and not value2left) or (value2left and not value1left):
|
||||
return root
|
||||
else:
|
||||
return self._getAncestorInPost(postorder, inorder[:i] + inorder[i+1:], value1, value2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _getAncestorBST2(self, preorder, value1, value2):
|
||||
''' Return the ancestor of two nodes if it is a bst, using traversal'''
|
||||
while preorder:
|
||||
current = preorder[0]
|
||||
if current < value1:
|
||||
try: preorder = preorder[2:]
|
||||
except: return current
|
||||
elif current > value2:
|
||||
try: preorder = preorder[1:]
|
||||
except: return current
|
||||
elif value1 <= current <= value2:
|
||||
return current
|
||||
return None
|
||||
|
||||
def getAncestor(self, value1, value2, method='pre-in'):
|
||||
''' Return the commom ancestor for two nodes'''
|
||||
if method == 'pre-in':
|
||||
''' Using pre and inorder, best/worst O(n)'''
|
||||
preorder = self.root._printDFTpreOrder(self.root)
|
||||
inorder = self.root._printDFTinOrder(self.root)
|
||||
return self._getAncestorPreIn(preorder, inorder, value1, value2)
|
||||
if method == 'pre-post':
|
||||
''' Using pre and postorder, best/worst O(n)'''
|
||||
preorder = self.root._printDFTpreOrder(self.root)
|
||||
postorder = self.root._printDFTpostOrder(self.root)
|
||||
return self._getAncestorPrePost(preorder, postorder, value1, value2)
|
||||
if method == 'post-in':
|
||||
''' Using in and postorder, best/worst O(n)'''
|
||||
inorder = self.root._printDFTinOrder(self.root)
|
||||
postorder = self.root._printDFTpostOrder(self.root)
|
||||
return self._getAncestorInPost(inorder, postorder, value1, value2)
|
||||
if method == 'bst':
|
||||
if self.isBST():
|
||||
return self.root._getAncestorBST(value1, value2)
|
||||
|
||||
#preorder = self.root._printDFTpreOrder(self.root)
|
||||
#return self._getAncestorBST2(preorder, value1, value2)
|
||||
else:
|
||||
return Exception('The tree is not a BST')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
131
src/graphs_and_trees/trees_graphs/traversals.py
Normal file
131
src/graphs_and_trees/trees_graphs/traversals.py
Normal file
|
@ -0,0 +1,131 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from BST import BST
|
||||
|
||||
|
||||
from collections import deque
|
||||
class TranversalBST(object):
|
||||
def __init__(self):
|
||||
self.bst = BST(None)
|
||||
self.nodes = []
|
||||
|
||||
def insert(self, value):
|
||||
if not self.bst.value:
|
||||
self.bst.value = value
|
||||
else:
|
||||
self.bst.insert(value)
|
||||
|
||||
def contains(self, value):
|
||||
return bool(self.bst.find(value))
|
||||
|
||||
def get(self, index):
|
||||
for i, value in enumerate(self.inorder()):
|
||||
if i == index:
|
||||
return value
|
||||
|
||||
def inorder(self):
|
||||
current = self.bst
|
||||
self.nodes = []
|
||||
stack = []
|
||||
while len(stack) > 0 or current is not None:
|
||||
if current is not None:
|
||||
stack.append(current)
|
||||
current = current.left
|
||||
else:
|
||||
current = stack.pop()
|
||||
self.nodes.append(current.value)
|
||||
current = current.right
|
||||
return self.nodes
|
||||
|
||||
|
||||
def preorder(self):
|
||||
self.nodes = []
|
||||
stack = [self.bst]
|
||||
while len(stack) > 0:
|
||||
curr = stack.pop()
|
||||
if curr is not None:
|
||||
self.nodes.append(curr.value)
|
||||
stack.append(curr.right)
|
||||
stack.append(curr.left)
|
||||
return self.nodes
|
||||
|
||||
|
||||
def preorder2(self):
|
||||
self.nodes = []
|
||||
current = self.bst
|
||||
stack = []
|
||||
while len(stack) > 0 or current is not None:
|
||||
if current is not None:
|
||||
self.nodes.append(current.value)
|
||||
stack.append(current)
|
||||
current = current.left
|
||||
else:
|
||||
current = stack.pop()
|
||||
current = current.right
|
||||
return self.nodes
|
||||
|
||||
|
||||
|
||||
def preorder3(self):
|
||||
self.nodes = []
|
||||
node = self.bst
|
||||
if not node: return None
|
||||
stack = []
|
||||
stack.append(node)
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
self.nodes.append(node.value)
|
||||
if node.right: stack.append(node.right) # RIGHT FIRST!
|
||||
if node.left: stack.append(node.left)
|
||||
return self.nodes
|
||||
|
||||
|
||||
|
||||
|
||||
def BFT(self):
|
||||
self.nodes = []
|
||||
node = self.bst
|
||||
if not node: return None
|
||||
queue = deque()
|
||||
queue.append(node)
|
||||
while queue:
|
||||
node = queue.popleft()
|
||||
self.nodes.append(node.value)
|
||||
if node.left: queue.append(node.left) # LEFT FIRST!
|
||||
if node.right: queue.append(node.right)
|
||||
|
||||
return self.nodes
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
10
|
||||
5 15
|
||||
1 6 11 50
|
||||
"""
|
||||
t = TranversalBST()
|
||||
t.insert(10)
|
||||
t.insert(5)
|
||||
t.insert(15)
|
||||
t.insert(1)
|
||||
t.insert(6)
|
||||
t.insert(11)
|
||||
t.insert(50)
|
||||
print(t.preorder())
|
||||
print(t.preorder2())
|
||||
print(t.preorder3())
|
||||
print(t.inorder())
|
||||
print(t.BFT())
|
||||
'''
|
||||
[10, 5, 1, 6, 15, 11, 50]
|
||||
[10, 5, 1, 6, 15, 11, 50]
|
||||
[10, 5, 1, 6, 15, 11, 50]
|
||||
[1, 5, 6, 10, 11, 15, 50]
|
||||
[10, 5, 15, 1, 6, 11, 50]
|
||||
'''
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue