Skip to content

Commit

Permalink
least common ancestor
Browse files Browse the repository at this point in the history
  • Loading branch information
a2un committed Oct 11, 2017
1 parent 74a7a58 commit fc3a64f
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 0 deletions.
1 change: 1 addition & 0 deletions bst_input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
79 77 91 87 68 5 51 42 58 39 44 60 29 43 37 101 110 103 97 94 63 75 59 73
59 changes: 59 additions & 0 deletions find_least_common_parent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from python_bst import *
import os,sys,random

def preorderTravese(preorderlist,node):
if node is None:
return
nodevalue(preorderlist,node)
preorderTravese(preorderlist,node.left)
preorderTravese(preorderlist,node.right)


def nodevalue(preorderlist,node):
preorderlist.append(node.key)

def allAncestors(root,node):
ancestorsList = list()
while node is not None and node.parent is not None:
ancestorsList.append(node.parent)
node = node.parent
return ancestorsList

def findLeastCommonParent(root,node1Ancestors,node2Ancestors):
if type(node1Ancestors) is list and type(node2Ancestors) is list:
for node1ancestoritem in node1Ancestors:
for node2ancestoritem in node2Ancestors:
if node1ancestoritem.key == node2ancestoritem.key:
return node1ancestoritem
else:
return root

def findin(tree):
if tree is not None:
preorderlist=list()
print 'root:' + str(tree.root.key)
nodekey1 = raw_input('enter the two nodes to check: ')
nodekey2 = raw_input()
node1 = tree.find(int(nodekey1))
node2 = tree.find(int(nodekey2))
if(node1 is not None and node2 is not None):
print 'all is well'
node1Ancestors = allAncestors(tree.root,node1)
node2Ancestors = allAncestors(tree.root,node2)
leastCommonParent = findLeastCommonParent(tree.root,node1Ancestors,node2Ancestors)

print 'least common parent ' + str(leastCommonParent.key)
else:
print 'invalid nodekey1 or nodekey2 value'
else:
print 'please input valid tree'

def runTest(args=None,BSTtype=BST):
tree = BSTtype()
with open('./bst_input.txt') as f:
args = f.read().split()

tree = test(args)
findin(tree)

if __name__ == '__main__': runTest()
234 changes: 234 additions & 0 deletions python_bst.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
class BSTnode(object):
"""
Representation of a node in a binary search tree.
Has a left child, right child, and key value, and stores its subtree size.
"""
def __init__(self, parent, t):
"""Create a new leaf with key t."""
self.key = t
self.parent = parent
self.left = None
self.right = None
self.size = 1

def update_stats(self):
"""Updates this node's size based on its children's sizes."""
self.size = (0 if self.left is None else self.left.size) + (0 if self.right is None else self.right.size)

def insert(self, t, NodeType):
"""Insert key t into the subtree rooted at this node (updating subtree size)."""
self.size += 1
if t < self.key:
if self.left is None:
self.left = NodeType(self, t)
return self.left
else:
return self.left.insert(t, NodeType)
else:
if self.right is None:
self.right = NodeType(self, t)
return self.right
else:
return self.right.insert(t, NodeType)

def find(self, t):
"""Return the node for key t if it is in this tree, or None otherwise."""
if t == self.key:
return self
elif t < self.key:
if self.left is None:
return None
else:
return self.left.find(t)
else:
if self.right is None:
return None
else:
return self.right.find(t)

def rank(self, t):
"""Return the number of keys <= t in the subtree rooted at this node."""
left_size = 0 if self.left is None else self.left.size
if t == self.key:
return left_size + 1
elif t < self.key:
if self.left is None:
return 0
else:
return self.left.rank(t)
else:
if self.right is None:
return left_size + 1
else:
return self.right.rank(t) + left_size + 1

def minimum(self):
"""Returns the node with the smallest key in the subtree rooted by this node."""
current = self
while current.left is not None:
current = current.left
return current


def successor(self):
"""Returns the node with the smallest key larger than this node's key, or None if this has the largest key in the tree."""
if self.right is not None:
return self.right.minimum()
current = self
while current.parent is not None and current.parent.right is current:
current = current.parent
return current.parent

def delete(self):
""""Delete this node from the tree."""
if self.left is None or self.right is None:
if self is self.parent.left:
self.parent.left = self.left or self.right
if self.parent.left is not None:
self.parent.left.parent = self.parent
else:
self.parent.right = self.left or self.right
if self.parent.right is not None:
self.parent.right.parent = self.parent
current = self.parent
while current.key is not None:
current.update_stats()
current = current.parent
return self
else:
s = self.successor()
self.key, s.key = s.key, self.key
return s.delete()

def check(self, lokey, hikey):
"""Checks that the subtree rooted at t is a valid BST and all keys are between (lokey, hikey)."""
if lokey is not None and self.key <= lokey:
raise "BST RI violation"
if hikey is not None and self.key >= hikey:
raise "BST RI violation"
if self.left is not None:
if self.left.parent is not self:
raise "BST RI violation"
self.left.check(lokey, self.key)
if self.right is not None:
if self.right.parent is not self:
raise "BST RI violation"
self.right.check(self.key, hikey)
if self.size != 1 + (0 if self.left is None else self.left.size) + (0 if self.right is None else self.right.size):
raise "BST RI violation"

def __repr__(self):
return "<BST Node, key:" + str(self.key) + ">"

class BST(object):
"""
Simple binary search tree implementation, augmented with subtree sizes.
This BST supports insert, find, and delete-min operations.
Each tree contains some (possibly 0) BSTnode objects, representing nodes,
and a pointer to the root.
"""

def __init__(self, NodeType=BSTnode):
self.root = None
self.NodeType = NodeType
self.psroot = self.NodeType(None, None)

def reroot(self):
self.root = self.psroot.left

def insert(self, t):
"""Insert key t into this BST, modifying it in-place."""
if self.root is None:
self.psroot.left = self.NodeType(self.psroot, t)
self.reroot()
return self.root
else:
return self.root.insert(t, self.NodeType)

def find(self, t):
"""Return the node for key t if is in the tree, or None otherwise."""
if self.root is None:
return None
else:
return self.root.find(t)

def rank(self, t):
"""The number of keys <= t in the tree."""
if self.root is None:
return 0
else:
return self.root.rank(t)

def delete(self, t):
"""Delete the node for key t if it is in the tree."""
node = self.find(t)
deleted = self.root.delete()
self.reroot()
return deleted

def check(self):
if self.root is not None:
self.root.check(None, None)

def __str__(self):
if self.root is None: return '<empty tree>'
def recurse(node):
if node is None: return [], 0, 0
label = str(node.key)
left_lines, left_pos, left_width = recurse(node.left)
right_lines, right_pos, right_width = recurse(node.right)
middle = max(right_pos + left_width - left_pos + 1, len(label), 2)
pos = left_pos + middle // 2
width = left_pos + middle + right_width - right_pos
while len(left_lines) < len(right_lines):
left_lines.append(' ' * left_width)
while len(right_lines) < len(left_lines):
right_lines.append(' ' * right_width)
if (middle - len(label)) % 2 == 1 and node.parent is not None and \
node is node.parent.left and len(label) < middle:
label += '.'
label = label.center(middle, '.')
if label[0] == '.': label = ' ' + label[1:]
if label[-1] == '.': label = label[:-1] + ' '
lines = [' ' * left_pos + label + ' ' * (right_width - right_pos),
' ' * left_pos + '/' + ' ' * (middle-2) +
'\\' + ' ' * (right_width - right_pos)] + \
[left_line + ' ' * (width - left_width - right_width) +
right_line
for left_line, right_line in zip(left_lines, right_lines)]
return lines, pos, width
return '\n'.join(recurse(self.root) [0])

test1 = range(0, 100, 10)
test2 = [31, 41, 59, 26, 53, 58, 97, 93, 23]
test3 = "algorithms"

def printsizes(node):
if node is None:
print "node is nil"
else:
print "node", node.key, "has a subtree of size", node.size

def test(args=None, BSTtype=BST):
import random, sys
if not args:
args = sys.argv[1:]
if not args:
print 'usage: %s <number-of-random-items | item item item ...>' % \
sys.argv[0]
sys.exit()
elif len(args) == 1:
items = (random.randrange(100) for i in xrange(int(args[0])))
else:
items = [int(i) for i in args]

tree = BSTtype()
#print tree
for item in items:
tree.insert(item)
print
#print tree
print tree
return tree

if __name__ == '__main__': test()
Binary file added python_bst.pyc
Binary file not shown.
1 change: 1 addition & 0 deletions random15.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
15

0 comments on commit fc3a64f

Please sign in to comment.