-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTree.py
192 lines (162 loc) · 4.75 KB
/
Tree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
'''
Overview:
Linked List is a non-forking tree
Binary Tree = Node with 2 other nodes branching off
Full Tree = Node with every node either pointing to 0 or 2 nodes
Perfect Tree = Any level is completely filled all the way across
Complete Tree = Filled tree, left-to-right, with no gaps
Parent Node - Child Node
1 Parent for a node
Leaf = Childless Nodes
Binary Search Tree = Start at parent node, if larger value, go right, smaller, go left.
compare with each child node until at leaf.
As the tree grows, nodes = 2^levels - 1
Takes O(log(nodes)) = O(log n) steps to find/append/pop a particular node
Divide & Conquer because of left/right for lesser/greater
That's for most trees (Ideal case is Perfect Tree)
Worst Case, if tree never forks, all values on one side
It's a Linked List. O(n) lookup/insert/remove
Lookup: LL O(n), BST O(log n)
Remove: LL O(n), BST O(log n)
Insert: LL O(1), BST O(log n) cuz of traversal
LL is very quick with appending, no other DS beats it
'''
import Queue
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = None # Empty Tree Initialization
def insert(self, value):
new_node = Node(value)
if self.root is None:
self.root = new_node
return True
temp = self.root
while True:
if value == temp.value:
return False
if value < temp.value:
if temp.left:
temp = temp.left
else:
temp.left = new_node
return True
else:
if temp.right:
temp = temp.right
else:
temp.right = new_node
return True
def contains(self, value):
temp = self.root
while temp:
if temp.value == value:
return True
if value < temp.value:
temp = temp.left
else:
temp = temp.right
return False
def __r_contains(self, current_node, value):
if current_node is None:
return False
if value == current_node.value:
return True
if value < current_node.value:
return self.__r_contains(current_node.left, value)
else:
return self.__r_contains(current_node.right, value)
def r_contains(self, value):
return self.__r_contains(self.root, value)
def __r_insert(self, current_node, value):
if current_node is None:
return Node(value)
if value < current_node.value:
current_node.left = self.__r_insert(current_node.left, value)
elif value > current_node.value:
current_node.right = self.__r_insert(current_node.right, value)
return current_node
def r_insert(self, value):
if self.root is None:
self.root = Node(value)
self.__r_insert(self.root, value)
def min_value(self, current_node):
while current_node.left is not None:
current_node = current_node.left
return current_node.value
def __delete_node(self, current_node, value):
if current_node is None:
return None
if value < current_node.value:
current_node.left = self.__delete_node(current_node.left, value)
elif value > current_node.value:
current_node.right = self.__delete_node(current_node.right, value)
else:
if current_node.left is None and current_node.right is None:
return None
elif current_node.left is None:
current_node = current_node.right
elif current_node.right is None:
current_node = current_node.left
else:
sub_tree_min = self.min_value(current_node.right)
current_node.value = sub_tree_min
current_node.right = self.__delete_node(current_node.right, sub_tree_min)
return current_node
def delete_node(self, value):
self.root = self.__delete_node(self.root, value)
def bfs(self):
current_node = self.root
queue = Queue.Queue(current_node)
results = []
while queue.length:
current_node = queue.dequeue()
results.append(current_node.value)
if current_node.left:
queue.enqueue(current_node.left)
if current_node.right:
queue.enqueue(current_node.right)
return results
def dfs_preorder(self):
results = []
def traverse(current_node):
results.append(current_node.value)
if current_node.left:
traverse(current_node.left)
if current_node.right:
traverse(current_node.right)
traverse(self.root)
return results
def dfs_postorder(self):
results = []
def traverse(current_node):
if current_node.left:
traverse(current_node.left)
if current_node.right:
traverse(current_node.right)
results.append(current_node.value)
traverse(self.root)
return results
def dfs_inorder(self):
results = []
def traverse(current_node):
if current_node.left:
traverse(current_node.left)
results.append(current_node.value)
if current_node.right:
traverse(current_node.right)
traverse(self.root)
return results
bst = BinarySearchTree()
bst.r_insert(47)
bst.r_insert(21)
bst.r_insert(76)
bst.r_insert(18)
bst.r_insert(27)
bst.r_insert(52)
bst.r_insert(82)
print(bst.dfs_inorder())