This commit is contained in:
Mari Wahl 2014-08-20 16:40:57 -04:00
parent aa5010594e
commit 7b9e953f5a
194 changed files with 28 additions and 34 deletions

View file

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View file

@ -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()

View file

@ -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()

View 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()

View 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()

View 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()