Skip to content

Commit c17c023

Browse files
authored
Merge pull request #152 from ashwek/ms1
Added Binary Search Tree, Stack using Linked List
2 parents 863e434 + 6abb96e commit c17c023

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed
+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""
2+
A binary search tree is a rooted binary tree, whose internal nodes each
3+
store a key (and optionally, an associated value) and each have two
4+
distinguished sub-trees, commonly denoted left and right.
5+
6+
The tree additionally satisfies the binary search property, which states that
7+
the key in each node must be greater than or equal to any key stored in the
8+
left sub-tree, and less than or equal to any key stored in the right sub-tree.
9+
10+
https://en.wikipedia.org/wiki/Binary_search_tree
11+
12+
"""
13+
14+
from random import randint
15+
16+
class Node: # class to create nodes
17+
def __init__(self, Parent = None, Value = None, Left = None, Right = None):
18+
self.parent = Parent # points to parent of Node
19+
self.value = Value # value in Node
20+
self.left = Left # points to left child
21+
self.right = Right # points to right child
22+
23+
def __str__(self):
24+
return str(self.value)
25+
26+
class BST:
27+
28+
def __init__(self):
29+
self.__root = None # initially root = None
30+
31+
def is_empty(self):
32+
return self.__root == None
33+
34+
def insert(self, val):
35+
if( self.is_empty() ): # if root = None (no nodes added to tree)
36+
self.__root = Node(Value = val) # create new node & assign to root
37+
else:
38+
current = self.__root # current node = root (initially)
39+
while( current != None ):
40+
parent = current
41+
current = current.left if( val <= current.value ) else current.right # if val < current.value, goto left child, else goto right child
42+
43+
if( val <= parent.value ): # if val < parent.value
44+
parent.left = Node(parent, val) # assign new node as Left child
45+
else:
46+
parent.right = Node(parent, val) # assign new node as Right child
47+
48+
def preorder(self, current = -1):
49+
if (current == -1 ): current = self.__root # if current == -1 (no argument passed), current = root
50+
51+
# Pre-Order = (Root, Left, Right)
52+
Ret = []
53+
if(current != None):
54+
Ret.append(current.value) # Root (value)
55+
Ret.extend(self.preorder(current.left)) # Left (subtree)
56+
Ret.extend(self.preorder(current.right)) # Right (subtree)
57+
return Ret
58+
59+
def inorder(self, current = -1):
60+
if (current == -1 ): current = self.__root # if current == -1 (no argument passed), set current = root
61+
62+
# In-Order = (Left, Root, Right)
63+
Ret = []
64+
if(current != None):
65+
Ret.extend(self.inorder(current.left)) # Left (subtree)
66+
Ret.append(current.value) # Root (value)
67+
Ret.extend(self.inorder(current.right)) # Right (subtree)
68+
return Ret
69+
70+
def postorder(self, current = -1):
71+
if (current == -1 ): current = self.__root # if current == -1 (no argument passed), set current = root
72+
73+
# Post-Order = (Left, Right, Root)
74+
Ret = []
75+
if(current != None):
76+
Ret.extend(self.postorder(current.left)) # Left (subtree)
77+
Ret.extend(self.postorder(current.right)) # Right (subtree)
78+
Ret.append(current.value) # Root (value)
79+
return Ret
80+
81+
def levelorder(self, current = -1):
82+
83+
Ret = []
84+
85+
if( self.is_empty() ): return Ret # if tree is empty, return empty list
86+
87+
if( current == -1 ):
88+
current = [self.__root] # if current == -1 (no argument passed), set current = [root]
89+
Ret.append(self.__root.value) # append root.value to Ret
90+
91+
next_level = [] # list of all nodes on Next Level
92+
93+
for each in current: # current -> list of all nodes on any particular level
94+
95+
if( each.left != None ): # if node on current level has left child
96+
Ret.append(each.left.value) # insert its value to Ret
97+
next_level.append(each.left) # add left child to next_level
98+
99+
if( each.right != None ): # if node on current level has right child
100+
Ret.append(each.right.value) # insert its value to Ret
101+
next_level.append(each.right) # add right child to next_level
102+
103+
if( next_level ): # if there are any nodes in the next_level
104+
Ret.extend(self.levelorder(next_level)) # process nodes in next_level
105+
106+
return Ret
107+
108+
def search(self, find):
109+
current = self.__root
110+
111+
while current and current.value != find : # while current (current != None) and value is not found
112+
current = current.right if(current.value < find) else current.left # if "find" is larger than current.value, traverse Right sub-tree, else left sub-tree
113+
114+
return current # return Node (None if value not found)
115+
116+
def maximum(self, current = -1):
117+
if current == -1: # find maximum of current sub tree, if argument is not passed, use root
118+
current = self.__root
119+
120+
while current and current.right != None : # while current != None & current has a right child
121+
current = current.right
122+
return current
123+
124+
def minimum(self, current = -1):
125+
if current == -1: # find minimum of current sub tree, if argument is not passed, use root
126+
current = self.__root
127+
128+
while current and current.left != None : # while current != None & current has a left child
129+
current = current.left
130+
return current
131+
132+
def successor(self, node):
133+
134+
if node.right == None: # if node does not have right child
135+
while node.parent != None and node.parent.right == node : # traverse to parent while Parent != None & node is right child of parent
136+
node = node.parent
137+
return node.parent
138+
else:
139+
return self.minimum(node.right) # return Minimum from right subtree
140+
141+
def predecessor(self, node):
142+
143+
if node.left == None:
144+
while node.parent != None and node.parent.left == node :
145+
node = node.parent
146+
return node.parent
147+
else:
148+
return self.maximum(node.left) # return Maximum from left subtree
149+
150+
if __name__ == "__main__":
151+
152+
T1 = BST()
153+
154+
# insert random 10 numbers in the tree
155+
for i in range(10):
156+
T1.insert(randint(1, 50))
157+
158+
print("Level-Order = ", T1.levelorder())
159+
print(" Pre-Order = ", T1.preorder())
160+
print(" Post-Order = ", T1.postorder())
161+
print(" In-Order = ", T1.inorder())
162+
163+
find = 10
164+
Found_Node = T1.search(find)
165+
if(Found_Node):
166+
print("Successor of", find, " = ", T1.successor(Found_Node))
167+
print("Predecessor of", find, " = ", T1.predecessor(Found_Node))
168+
print("\nValue Found, Parent = ", Found_Node.parent, "left = ", Found_Node.left, "right = ", Found_Node.right)
169+
else:
170+
print("\n", find, "not found in tree")
171+
172+
print("\nMaximum = ", T1.maximum())
173+
print("Minimum = ", T1.minimum())
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
class Node: # Class to create Nodes
2+
def __init__(self, Value, Next=None):
3+
self.value = Value # value in Node
4+
self.next = Next # points to next node
5+
6+
class Stack_LL:
7+
def __init__(self):
8+
self.__top = None # initially top = None
9+
self.__len = 0 # initially length of stack = 0
10+
11+
def is_empty(self):
12+
return self.__top == None
13+
14+
def push(self, value):
15+
self.__top = Node(value, self.__top) # Create Node with value = "value" & next = "top". Make new node as top
16+
self.__len += 1 # increment length
17+
18+
def pop(self):
19+
if(self.is_empty()): raise IndexError("Stack is Empty") # check if stack is empty
20+
else:
21+
temp = self.__top # temp = top
22+
self.__top = self.__top.next # top = next element
23+
temp.next = None # (previous top) temp.next -> None (break the link)
24+
self.__len -= 1 # decrement length
25+
return temp.value # return poped value
26+
27+
def __len__(self):
28+
return self.__len
29+
30+
def __str__(self): # return str form of linked list i.e., val1 -> val2 -> None
31+
temp = self.__top
32+
Values = []
33+
while temp:
34+
Values.append(str(temp.value)) # add values to "Values"
35+
temp = temp.next
36+
Values.append("None")
37+
return " -> ".join(Values) # return all Values as string
38+
39+
# __next__ and __iter__ methods are used to iterate through the object
40+
41+
# __next__ is used to get the next element in the iterable object
42+
def __next__(self):
43+
temp = self.__i
44+
if (temp == None): raise StopIteration() # if temp = None, temp has reached the end, raise StopIteration to stop iteration
45+
self.__i = self.__i.next
46+
return temp.value
47+
48+
# __iter__ returns an iterable object (self) & sets i = top, to iterate through top to end
49+
def __iter__(self):
50+
self.__i = self.__top
51+
return self
52+
53+
if __name__ == '__main__':
54+
S1 = Stack_LL()
55+
56+
for i in range(5, 21, 5):
57+
print("push", i, "to stack")
58+
S1.push(i)
59+
60+
print("\nStack : ", S1)
61+
62+
print("\nPop stack, popped value = ", S1.pop())

0 commit comments

Comments
 (0)