├── AVL_Tree ├── Immutable_Stack.py ├── README.md ├── Stack.py ├── binary_search_tree_map.py ├── binary_trees.py ├── cons_list.py ├── double_linked_list ├── graphs_dfs.py ├── heap.py ├── immutable tree.py ├── n_ary_trees.py └── parse_tree.py /AVL_Tree: -------------------------------------------------------------------------------- 1 | # An AVL tree, python 2 | import random 3 | 4 | 5 | class TreeNode: 6 | def __init__(self, key, val, left=None, right=None, parent=None, bal=0): 7 | self.key = key 8 | self.payload = val 9 | self.leftChild = left 10 | self.rightChild = right 11 | self.parent = parent 12 | self.balanceFactor = bal 13 | 14 | def update_val(self, new_val): # added 15 | self.payload = new_val 16 | 17 | def hasLeftChild(self): 18 | return self.leftChild 19 | 20 | def hasRightChild(self): 21 | return self.rightChild 22 | 23 | def isLeftChild(self): 24 | return self.parent and self.parent.leftChild == self 25 | 26 | def isRightChild(self): 27 | return self.parent and self.parent.rightChild == self 28 | 29 | def isRoot(self): 30 | return not self.parent 31 | 32 | def isLeaf(self): 33 | return not (self.rightChild or self.leftChild) 34 | 35 | def hasAnyChildren(self): 36 | return self.rightChild or self.leftChild 37 | 38 | def hasBothChildren(self): 39 | return self.rightChild and self.leftChild 40 | 41 | def replaceNodeData(self, key, value, lc, rc): 42 | self.key = key 43 | self.payload = value 44 | self.leftChild = lc 45 | self.rightChild = rc 46 | if self.hasLeftChild(): 47 | self.leftChild.parent = self 48 | if self.hasRightChild(): 49 | self.rightChild.parent = self 50 | 51 | def findSuccessor(self): 52 | succ = None 53 | if self.hasRightChild(): 54 | succ = self.rightChild.findMin() 55 | else: 56 | if self.parent: 57 | if self.isLeftChild(): 58 | succ = self.parent 59 | else: 60 | self.parent.rightChild = None 61 | succ = self.parent.findSuccessor() 62 | self.parent.rightChild = self 63 | return succ 64 | 65 | def findMin(self): 66 | current = self 67 | while current.hasLeftChild(): 68 | current = current.leftChild 69 | return current 70 | 71 | def spliceOut(self): 72 | if self.isLeaf(): 73 | if self.isLeftChild(): 74 | self.parent.leftChild = None 75 | else: 76 | self.parent.rightChild = None 77 | elif self.hasAnyChildren(): 78 | if self.hasLeftChild(): 79 | if self.isLeftChild(): 80 | self.parent.leftChild = self.leftChild 81 | else: 82 | self.parent.rightChild = self.leftChild 83 | self.leftChild.parent = self.parent 84 | else: 85 | if self.isLeftChild(): 86 | self.parent.leftChild = self.rightChild 87 | else: 88 | self.parent.rightChild = self.rightChild 89 | self.rightChild.parent = self.parent 90 | 91 | 92 | class BinarySearchTree: 93 | def __init__(self): 94 | self.root = None 95 | self.size = 0 96 | 97 | def length(self): 98 | return self.size 99 | 100 | def __len__(self): 101 | return self.size 102 | 103 | def __getitem__(self, key): 104 | return self.get(key) 105 | 106 | def __setitem__(self, k, v): 107 | self.put(k, v) 108 | 109 | def put(self, key, val): 110 | if self.root: 111 | self._put(key, val, self.root) 112 | else: 113 | self.root = TreeNode(key, val) 114 | self.size = self.size + 1 115 | 116 | # start of overwritten section and balancing methods 117 | def _put(self, key, val, currentNode): 118 | # pdb.set_trace() 119 | if key == currentNode.key: 120 | currentNode.update_val(val) 121 | return 122 | if key < currentNode.key: 123 | if currentNode.hasLeftChild(): 124 | self._put(key, val, currentNode.leftChild) 125 | else: 126 | currentNode.leftChild = TreeNode(key, val, parent=currentNode) 127 | self.updateBalance(currentNode.leftChild) 128 | else: 129 | if currentNode.hasRightChild(): 130 | self._put(key, val, currentNode.rightChild) 131 | else: 132 | currentNode.rightChild = TreeNode(key, val, parent=currentNode) 133 | self.updateBalance(currentNode.rightChild) 134 | 135 | def rotateLeft(self, rotRoot): 136 | # pdb.set_trace() 137 | newRoot = rotRoot.rightChild 138 | rotRoot.rightChild = newRoot.leftChild 139 | if newRoot.leftChild != None: 140 | newRoot.leftChild.parent = rotRoot 141 | newRoot.parent = rotRoot.parent 142 | if rotRoot.isRoot(): 143 | self.root = newRoot 144 | else: 145 | if rotRoot.isLeftChild(): 146 | rotRoot.parent.leftChild = newRoot 147 | else: 148 | rotRoot.parent.rightChild = newRoot 149 | newRoot.leftChild = rotRoot 150 | rotRoot.parent = newRoot 151 | rotRoot.balanceFactor = rotRoot.balanceFactor + 1 - min(newRoot.balanceFactor, 0) 152 | newRoot.balanceFactor = newRoot.balanceFactor + 1 + max(rotRoot.balanceFactor, 0) 153 | 154 | def rotateRight(self, rotRoot): 155 | # pdb.set_trace() 156 | newRoot = rotRoot.leftChild 157 | rotRoot.leftChild = newRoot.rightChild 158 | if newRoot.rightChild != None: 159 | newRoot.rightChild.parent = rotRoot 160 | newRoot.parent = rotRoot.parent 161 | if rotRoot.isRoot(): 162 | self.root = newRoot 163 | else: 164 | if rotRoot.isLeftChild(): 165 | rotRoot.parent.leftChild = newRoot 166 | else: 167 | rotRoot.parent.rightChild = newRoot 168 | newRoot.rightChild = rotRoot 169 | rotRoot.parent = newRoot 170 | rotRoot.balanceFactor = rotRoot.balanceFactor - 1 - max(newRoot.balanceFactor, 0) 171 | newRoot.balanceFactor = newRoot.balanceFactor - 1 + min(0, rotRoot.balanceFactor) 172 | 173 | def updateBalance(self, node): 174 | # pdb.set_trace() 175 | if node.balanceFactor > 1 or node.balanceFactor < -1: 176 | self.rebalance(node) 177 | return 178 | if node.parent != None: 179 | if node.isLeftChild(): 180 | node.parent.balanceFactor += 1 181 | elif node.isRightChild(): 182 | node.parent.balanceFactor -= 1 183 | 184 | if node.parent.balanceFactor != 0: 185 | self.updateBalance(node.parent) 186 | 187 | def rebalance(self, node): 188 | # pdb.set_trace() 189 | if node.balanceFactor < 0: 190 | if node.rightChild.balanceFactor > 0: 191 | self.rotateRight(node.rightChild) 192 | self.rotateLeft(node) 193 | else: 194 | self.rotateLeft(node) 195 | elif node.balanceFactor > 0: 196 | if node.leftChild.balanceFactor < 0: 197 | self.rotateLeft(node.leftChild) 198 | self.rotateRight(node) 199 | else: 200 | self.rotateRight(node) 201 | 202 | # end of overwritten and balancing methods 203 | 204 | def get(self, key): 205 | if self.root: 206 | res = self._get(key, self.root) 207 | if res: 208 | return res.payload 209 | else: 210 | return None 211 | else: 212 | return None 213 | 214 | def _get(self, key, currentNode): 215 | if not currentNode: 216 | return None 217 | elif currentNode.key == key: 218 | return currentNode 219 | elif key < currentNode.key: 220 | return self._get(key, currentNode.leftChild) 221 | else: 222 | return self._get(key, currentNode.rightChild) 223 | 224 | def __delitem__(self, key): 225 | self.delete(key) 226 | 227 | def delete(self, key): 228 | if self.size > 1: 229 | nodeToRemove = self._get(key, self.root) 230 | if nodeToRemove: 231 | self.remove(nodeToRemove) 232 | self.size = self.size - 1 233 | else: 234 | raise KeyError('Error, key not in tree') 235 | elif self.size == 1 and self.root.key == key: 236 | self.root = None 237 | self.size = self.size - 1 238 | else: 239 | raise KeyError('Error, key not in tree') 240 | 241 | def remove(self, currentNode): 242 | if currentNode.isLeaf(): # this is leaf 243 | if currentNode == currentNode.parent.leftChild: 244 | currentNode.parent.leftChild = None 245 | currentNode.parent.balanceFactor -= 1 246 | if currentNode.parent.balanceFactor < -1: 247 | self.updateBalance(currentNode.parent) 248 | else: 249 | currentNode.parent.rightChild = None 250 | currentNode.parent.balanceFactor += 1 251 | if currentNode.parent.balanceFactor > 1: 252 | self.updateBalance(currentNode.parent) 253 | elif currentNode.hasBothChildren(): # this is interior node 254 | succ = currentNode.findSuccessor() 255 | succ.spliceOut() 256 | if succ.isLeftChild(): 257 | succ.parent.balanceFactor -= 1 258 | self.updateBalance(succ.parent) 259 | elif succ.isRightChild(): 260 | succ.parent.balanceFactor += 1 261 | self.updateBalance(succ.parent) 262 | currentNode.key = succ.key 263 | currentNode.payload = succ.payload 264 | 265 | else: # this node has one child 266 | if currentNode.hasLeftChild(): 267 | if currentNode.isLeftChild(): 268 | currentNode.leftChild.parent = currentNode.parent 269 | currentNode.parent.leftChild = currentNode.leftChild 270 | currentNode.parent.balanceFactor -= 1 271 | self.updateBalance(currentNode.parent) 272 | elif currentNode.isRightChild(): 273 | currentNode.leftChild.parent = currentNode.parent 274 | currentNode.parent.rightChild = currentNode.leftChild 275 | currentNode.parent.balanceFactor += 1 276 | self.updateBalance(currentNode.parent) 277 | else: 278 | currentNode.replaceNodeData(currentNode.leftChild.key, 279 | currentNode.leftChild.payload, 280 | currentNode.leftChild.leftChild, 281 | currentNode.leftChild.rightChild) 282 | else: 283 | if currentNode.isLeftChild(): 284 | currentNode.rightChild.parent = currentNode.parent 285 | currentNode.parent.leftChild = currentNode.rightChild 286 | currentNode.parent.balanceFactor -= 1 287 | self.updateBalance(currentNode.parent) 288 | elif currentNode.isRightChild(): 289 | currentNode.rightChild.parent = currentNode.parent 290 | currentNode.parent.rightChild = currentNode.rightChild 291 | currentNode.parent.balanceFactor += 1 292 | self.updateBalance(currentNode.parent) 293 | else: 294 | currentNode.replaceNodeData(currentNode.rightChild.key, 295 | currentNode.rightChild.payload, 296 | currentNode.rightChild.leftChild, 297 | currentNode.rightChild.rightChild) 298 | 299 | 300 | # end of tree code 301 | 302 | 303 | # functions on tree: 304 | def inorder_traversal(tree): 305 | cur = tree.root 306 | 307 | def helper(current): 308 | if current: 309 | helper(current.leftChild) 310 | print(current.key, current.payload) 311 | helper(current.rightChild) 312 | return helper(cur) 313 | 314 | 315 | def height_node(tree_node): 316 | if not tree_node: 317 | return 0 318 | else: 319 | return 1 + max(height_node(tree_node.leftChild), height_node(tree_node.rightChild)) 320 | 321 | 322 | def is_balanced(tree_node): 323 | return abs(height_node(tree_node.leftChild) - height_node(tree_node.rightChild)) <= 1 324 | 325 | 326 | def list_print(tree_node): 327 | def top_height(tree_node): 328 | if not tree_node: 329 | return 0 330 | else: 331 | return 1 + top_height(tree_node.parent) 332 | 333 | if not tree_node: 334 | return [] 335 | else: 336 | size = height_node(tree_node.root) 337 | l1 = [[] for x in range(size)] 338 | 339 | def travel_list(current): 340 | if current: 341 | travel_list(current.leftChild) 342 | l1[top_height(current) - 1].append(current.key) 343 | travel_list(current.rightChild) 344 | return l1 345 | 346 | l = travel_list(tree_node.root) 347 | for x in range(len(l)): 348 | print(l[x]) 349 | 350 | 351 | # tests in a loop: 352 | for f in range(100): 353 | mytree1 = BinarySearchTree() 354 | for x in range(1000): 355 | mytree1.put(random.randint(-10000, 10000), "a") 356 | for i in range(100): 357 | if mytree1.get(i): 358 | mytree1.delete(i) 359 | if not is_balanced(mytree1.root): 360 | print("not good") 361 | h = height_node(mytree1.root) 362 | print("height: ", h) 363 | list_print(mytree1) 364 | break 365 | del (mytree1) 366 | 367 | print("OK") 368 | -------------------------------------------------------------------------------- /Immutable_Stack.py: -------------------------------------------------------------------------------- 1 | class Stack: 2 | 3 | def __init__(self, elem = None, lst = None): 4 | if lst is not None: 5 | self.stack = Create_from_list(elem, lst) 6 | else: 7 | self.stack = Create_list([]) 8 | 9 | def push(self, elem): 10 | return Stack(elem, self.stack) 11 | 12 | 13 | def pop(self): 14 | if self.stack.tail is not Nil: 15 | return Stack(nth(1, self.stack), lself.stack.tail.tail) 16 | else: 17 | return Nil() 18 | 19 | def is_empty(self): 20 | return empty(self.stack) 21 | 22 | def peek(self): 23 | return nth(0, self.stack) 24 | 25 | def __str__(self): 26 | if self.stack is Nil: 27 | return '()' 28 | else: 29 | return self.stack.__str__() 30 | ''' 31 | s1 = Stack() 32 | s2 = s1.push(1) 33 | print(s2.is_empty()) 34 | print(s2) 35 | 36 | outcome -> 37 | False 38 | (1) 39 | ''' 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python-Data-Structures -------------------------------------------------------------------------------- /Stack.py: -------------------------------------------------------------------------------- 1 | # Stacks 2 | 3 | # ----- LIFO Stack: 4 | 5 | class Stack: 6 | def __init__(self): 7 | self.stack = [] 8 | 9 | def push(self, x): 10 | self.stack.append(x) 11 | 12 | def pop(self): 13 | self.stack.pop() 14 | 15 | def size(self): 16 | return len(self.stack) 17 | 18 | def is_empty(self): 19 | return self.size() == 0 20 | 21 | def __str__(self): 22 | return str(self.stack) 23 | 24 | def peek(self): 25 | return self.stack[-1] 26 | 27 | def __eq__(self, other): 28 | return self.stack == other.stack 29 | 30 | s1 = Stack() 31 | s1.push(2) 32 | s1.push(3) 33 | print(s1) 34 | 35 | -------------------------------------------------------------------------------- /binary_search_tree_map.py: -------------------------------------------------------------------------------- 1 | # map (symbol table) implementation using binary search tree 2 | import random 3 | 4 | 5 | class Binary_search_tree: 6 | 7 | def __init__(self): 8 | self.root = None 9 | self.size = 0 10 | 11 | def length(self): 12 | return self.size 13 | 14 | def __len__(self): 15 | return self.size 16 | 17 | def __iter__(self): 18 | return self.root.__iter__() 19 | 20 | def __setitem__(self, k, v): 21 | self.put(k, v) 22 | 23 | def __getitem__(self, key): 24 | return self.get(key) 25 | 26 | def __contains__(self, key): 27 | if self._get(key, self.root): 28 | return True 29 | else: 30 | return False 31 | 32 | def put(self, key, val): 33 | if self.root: 34 | self._put(key, val, self.root) 35 | else: 36 | self.root = Tree_node(key, val) 37 | self.size += 1 38 | 39 | def get(self, key): 40 | if self.root: 41 | res = self._get(key, self.root) 42 | if res: 43 | return res.payload 44 | else: 45 | return None 46 | else: 47 | return None 48 | 49 | # deletion part beginning 50 | def delete(self, key): 51 | if self.size > 1: 52 | node_removed = self._get(key, self.root) 53 | if node_removed: 54 | self._remove(node_removed) 55 | self.size -= 1 56 | else: 57 | raise KeyError('Error, key not in tree') 58 | elif self.size == 1 and self.root.key == key: 59 | self.root = None 60 | self.size = self.size - 1 61 | else: 62 | raise KeyError('Error, key not in tree') 63 | 64 | def __delitem__(self, key): 65 | self.delete(key) 66 | 67 | def _remove(self, current): 68 | if current.isLeaf(): # is a leaf 69 | if current == current.parent.leftChild: 70 | current.parent.leftChild = None 71 | else: 72 | current.parent.rightChild = None 73 | elif current.hasBothChildren(): # is interior in a tree 74 | next_node = current._find_next() 75 | next_node._splice() 76 | current.key = next_node.key 77 | current.payload = next_node.payload 78 | 79 | else: # has only one child (left or right) 80 | if current.hasLeftChild(): 81 | if current.isLeftChild(): 82 | current.leftChild.parent = current.parent 83 | current.parent.leftChild = current.leftChild 84 | elif current.isRightChild(): 85 | current.leftChild.parent = current.parent 86 | current.parent.rightChild = current.leftChild 87 | else: 88 | current.replaceNodeData(current.leftChild.key, current.leftChild.payload, 89 | current.leftChild.leftChild, 90 | current.leftChild.rightChild) 91 | else: 92 | if current.isLeftChild(): 93 | current.rightChild.parent = current.parent 94 | current.parent.leftChild = current.rightChild 95 | elif current.isRightChild(): 96 | current.rightChild.parent = current.parent 97 | current.parent.rightChild = current.rightChild 98 | else: 99 | current.replaceNodeData(current.rightChild.key, 100 | current.rightChild.payload, 101 | current.rightChild.leftChild, 102 | current.rightChild.rightChild) 103 | 104 | # end of deleting section 105 | 106 | def _get(self, key, current): 107 | if not current: 108 | return None 109 | elif current.key == key: 110 | return current 111 | elif key < current.key: 112 | return self._get(key, current.leftChild) 113 | else: 114 | return self._get(key, current.rightChild) 115 | 116 | def _put(self, key, val, currentNode): 117 | if key < currentNode.key: 118 | if currentNode.hasLeftChild(): 119 | self._put(key, val, currentNode.leftChild) 120 | else: 121 | currentNode.leftChild = Tree_node(key, val, parent=currentNode) 122 | 123 | elif key > currentNode.key: 124 | if currentNode.hasRightChild(): 125 | self._put(key, val, currentNode.rightChild) 126 | else: 127 | currentNode.rightChild = Tree_node(key, val, parent=currentNode) 128 | else: 129 | currentNode.replaceNodeData(key, val, lc=currentNode.leftChild, rc=currentNode.rightChild) 130 | 131 | def __repr__(self): 132 | cur = self.root 133 | s = [] 134 | 135 | def helper(current): 136 | if current: 137 | helper(current.leftChild) 138 | s.append(("key: " + str(current.key), "val: " + str(current.payload) + " ")) 139 | helper(current.rightChild) 140 | 141 | helper(cur) 142 | s = "".join(str(e) for e in s) 143 | return "sorted tree: \n" + s 144 | 145 | 146 | class Tree_node: 147 | def __init__(self, key, val, left=None, right=None, 148 | parent=None): 149 | self.key = key 150 | self.payload = val 151 | self.leftChild = left 152 | self.rightChild = right 153 | self.parent = parent 154 | 155 | def hasLeftChild(self): 156 | return self.leftChild 157 | 158 | def hasRightChild(self): 159 | return self.rightChild 160 | 161 | def isLeftChild(self): 162 | return self.parent and self.parent.leftChild == self 163 | 164 | def isRightChild(self): 165 | return self.parent and self.parent.rightChild == self 166 | 167 | def isRoot(self): 168 | return not self.parent 169 | 170 | def isLeaf(self): 171 | return not (self.rightChild or self.leftChild) 172 | 173 | def hasAnyChildren(self): 174 | return self.rightChild or self.leftChild 175 | 176 | def hasBothChildren(self): 177 | return self.rightChild and self.leftChild 178 | 179 | def replaceNodeData(self, key, value, lc, rc): 180 | self.key = key 181 | self.payload = value 182 | self.leftChild = lc 183 | self.rightChild = rc 184 | if self.hasLeftChild(): 185 | self.leftChild.parent = self 186 | if self.hasRightChild(): 187 | self.rightChild.parent = self 188 | 189 | # deletion part beginning 190 | def _find_next(self): 191 | res = None 192 | if self.hasRightChild(): 193 | res = self.rightChild._find_min() 194 | else: 195 | if self.parent: 196 | if self.isLeftChild(): 197 | res = self.parent 198 | else: 199 | self.parent.rightChild = None 200 | res = self.parent._find_next() 201 | self.parent.rightChild = self 202 | return res 203 | 204 | def _find_min(self): 205 | current = self 206 | while current.hasLeftChild(): 207 | current = current.leftChild 208 | return current 209 | 210 | def _splice(self): 211 | if self.isLeaf(): 212 | if self.isLeftChild(): 213 | self.parent.leftChild = None 214 | else: 215 | self.parent.rightChild = None 216 | elif self.hasAnyChildren(): 217 | if self.hasLeftChild(): 218 | if self.isLeftChild(): 219 | self.parent.leftChild = self.leftChild 220 | else: 221 | self.parent.rightChild = self.leftChild 222 | self.leftChild.parent = self.parent 223 | else: 224 | if self.isLeftChild(): 225 | self.parent.leftChild = self.rightChild 226 | else: 227 | self.parent.rightChild = self.rightChild 228 | self.rightChild.parent = self.parent 229 | 230 | # end of deleting section 231 | 232 | def __iter__(self): 233 | if self: 234 | if self.hasLeftChild(): 235 | for item in self.leftChiLd: 236 | yield item 237 | yield self.key 238 | if self.hasRightChild(): 239 | for item in self.rightChild: 240 | yield item 241 | 242 | 243 | def inorder_traversal(tree): 244 | cur = tree.root 245 | 246 | def helper(current): 247 | if current: 248 | helper(current.leftChild) 249 | print(current.key, current.payload) 250 | helper(current.rightChild) 251 | 252 | return helper(cur) 253 | 254 | 255 | def make_min_from_array(tree, xs): 256 | if len(xs) > 1: 257 | m = len(xs) // 2 258 | left = xs[:m] 259 | right = xs[m:] 260 | tree.put(xs[m], 0) 261 | make_min_from_array(tree, left) 262 | make_min_from_array(tree, right) 263 | 264 | else: 265 | tree.put(xs[0], 1) 266 | 267 | 268 | def height(tree): 269 | if tree: 270 | l_height = height(tree.leftChild) 271 | r_height = height(tree.rightChild) 272 | if l_height > r_height: 273 | return l_height + 1 274 | else: 275 | return r_height + 1 276 | else: 277 | return 0 278 | 279 | 280 | def height_node(tree_node): 281 | if not tree_node: 282 | return 0 283 | else: 284 | l_height = height_node(tree_node.leftChild) 285 | r_height = height_node(tree_node.rightChild) 286 | if l_height > r_height: 287 | return l_height + 1 288 | else: 289 | return r_height + 1 290 | 291 | 292 | def is_balanced(tree_node): 293 | return abs(height_node(tree_node.root.leftChild) - height_node(tree_node.root.rightChild)) <= 1 294 | 295 | 296 | def maxdepth(treenode): 297 | if treenode: 298 | return 1 + max(maxdepth(treenode.leftChild), maxdepth(treenode.rightChild)) 299 | else: 300 | return 0 301 | 302 | 303 | def mindepth(treenode): 304 | if treenode: 305 | return 1 + min(mindepth(treenode.leftChild), mindepth(treenode.rightChild)) 306 | else: 307 | return 0 308 | 309 | 310 | def is_balanced2(treenode): 311 | return maxdepth(treenode.root) - mindepth(treenode.root) <= 1 312 | 313 | 314 | def top_height(tree_node): 315 | if not tree_node: 316 | return 0 317 | else: 318 | return 1 + top_height(tree_node.parent) 319 | 320 | 321 | def make_list(tree_node): 322 | """ make a list from a bin tree""" 323 | if not tree_node: 324 | return [] 325 | else: 326 | size = height_node(tree_node.root) 327 | l1 = [[] for x in range(size)] 328 | 329 | def travel_list(current): 330 | if current: 331 | travel_list(current.leftChild) 332 | l1[top_height(current) - 1].append(current.key) 333 | travel_list(current.rightChild) 334 | return l1 335 | 336 | l = travel_list(tree_node.root) 337 | for x in range(len(l)): 338 | print(l[x]) 339 | 340 | # helpers to tests 341 | def swap(alist, i, j): 342 | """swaps input lists i, j elements""" 343 | alist[i], alist[j] = alist[j], alist[i] 344 | 345 | 346 | def shuffle(data): 347 | """randomly shuffles element in the input data""" 348 | n = len(data) 349 | for token in range(n - 1): 350 | swap(data, token, random.randrange(token, n)) 351 | 352 | 353 | def main(): 354 | tree = Binary_search_tree() 355 | ar = [] 356 | for i in range(10000): 357 | ar.append(i) 358 | shuffle(ar) 359 | for i in range(10000): 360 | tree.put(ar[i], "B") 361 | for k in ar: 362 | tree.delete(k) 363 | print(tree) 364 | 365 | 366 | if __name__ == '__main__': 367 | main() 368 | 369 | 370 | -------------------------------------------------------------------------------- /binary_trees.py: -------------------------------------------------------------------------------- 1 | # binary tree 2 | import Stack as st 3 | def preorder_traversal(tree): 4 | if tree: 5 | print(tree.getRootVal()) 6 | preorder_traversal(tree.getLeftChild()) 7 | preorder_traversal(tree.getRightChild()) 8 | 9 | 10 | def postorder_traversal(tree): 11 | if tree: 12 | postorder_traversal(tree.getLeftChild()) 13 | postorder_traversal(tree.getRightChild()) 14 | print(tree.getRootVal()) 15 | 16 | 17 | def inorder_traversal(tree): 18 | if tree: 19 | inorder_traversal(tree.getLeftChild()) 20 | print(tree.getRootVal()) 21 | inorder_traversal(tree.getRightChild()) 22 | 23 | def inorder_traversal_check(tree, diff = 0): 24 | "Check if binary tree is balanced" 25 | if tree: 26 | inorder_traversal_check(tree.getLeftChild()) 27 | if abs(height(tree.getLeftChild()) - height(tree.getRightChild())) > 1: 28 | diff = 1 29 | inorder_traversal_check(tree.getRightChild()) 30 | if diff == 1: 31 | return False 32 | else: 33 | return True 34 | else: 35 | return True 36 | 37 | def size(tree): 38 | if tree: 39 | return size(tree.getLeftChild()) + 1 + size(tree.getRightChild()) 40 | else: 41 | return 0 42 | 43 | def height(tree): 44 | if tree: 45 | l_height = height(tree.getLeftChild()) 46 | r_height = height(tree.getRightChild()) 47 | if l_height > r_height: 48 | return l_height + 1 49 | else: 50 | return r_height + 1 51 | else: 52 | return 0 53 | 54 | 55 | class BinaryTree: 56 | 57 | def __init__(self, rootObj): 58 | self.key = rootObj 59 | self.parent = None 60 | self.leftChild = None 61 | self.rightChild = None 62 | 63 | def insertLeft(self, newNode): 64 | if self.leftChild == None: 65 | t = BinaryTree(newNode) 66 | self.leftChild = t 67 | t.parent = self 68 | # self.leftChild = BinaryTree(newNode) 69 | else: 70 | t = BinaryTree(newNode) 71 | t.parent = self 72 | t.leftChild = self.leftChild 73 | self.leftChild.parent = t 74 | self.leftChild = t 75 | 76 | def insertRight(self, newNode): 77 | if self.rightChild == None: 78 | t = BinaryTree(newNode) 79 | self.rightChild = t 80 | t.parent = self 81 | # self.rightChild = BinaryTree(newNode) 82 | else: 83 | t = BinaryTree(newNode) 84 | t.parent = self 85 | t.rightChild = self.rightChild 86 | self.rightChild.parent = t 87 | self.rightChild = t 88 | 89 | def getRightChild(self): 90 | return self.rightChild 91 | 92 | def getLeftChild(self): 93 | return self.leftChild 94 | 95 | def getParent(self): 96 | return self.parent 97 | 98 | def setRootVal(self, obj): 99 | self.key = obj 100 | 101 | def getRootVal(self): 102 | return self.key 103 | 104 | def preorder(self): 105 | print(self.key) 106 | if self.leftChild: 107 | self.leftChild.preorder() 108 | if self.rightChild: 109 | self.rightChild.preorder() 110 | 111 | 112 | def inorder_iter(tree): 113 | current = tree 114 | s = st.Stack() 115 | is_done = False 116 | while not is_done: 117 | if current: 118 | s.push(current) 119 | current = current.leftChild 120 | else: 121 | if not s.is_empty(): 122 | current = s.pop() 123 | print(current.key) 124 | current = current.rightChild 125 | else: 126 | is_done = True 127 | 128 | tr1 = BinaryTree("a") 129 | print("root->",tr1.getRootVal()) 130 | tr1.insertLeft("b") 131 | print("root->left ", tr1.getLeftChild().getRootVal()) 132 | tr1.getLeftChild().insertRight("d") 133 | print("rot->left->right ", tr1.getLeftChild().getRightChild().getRootVal()) 134 | tr1.insertRight("c") 135 | tr1.getRightChild().insertLeft("e") 136 | tr1.getRightChild().insertRight("f") 137 | tr1.getRightChild().getRightChild().insertRight("g") 138 | #tr1.getRightChild().getRightChild().getRightChild().insertRight("h") 139 | inorder_iter(tr1) 140 | (inorder_traversal_check(tr1.getRightChild())) 141 | ''' 142 | root-> a 143 | root->left b 144 | rot->left->right d 145 | b 146 | d 147 | a 148 | e 149 | c 150 | f 151 | g 152 | ''' 153 | -------------------------------------------------------------------------------- /cons_list.py: -------------------------------------------------------------------------------- 1 | from _collections_abc import ABCMeta, abstractmethod 2 | # immutable cons list and methods: 3 | class Nil: 4 | """class Nil, the empty list""" 5 | 6 | def is_empty(self): 7 | return True 8 | 9 | def head(self): 10 | return Exception("Empty") 11 | 12 | def tail(self): 13 | return Exception("Empty") 14 | 15 | def get_next(self): 16 | return None 17 | 18 | def __str__(self): 19 | return "()" 20 | 21 | 22 | class Cons: 23 | """Class cons, the non empty list: (head, list)""" 24 | 25 | def __init__(self, _head, _tail): 26 | self.head = _head 27 | self.tail = _tail 28 | 29 | def is_empty(self): 30 | return False 31 | 32 | def get_next(self): 33 | return self.tail 34 | 35 | def __str__(self): 36 | current = self.tail 37 | out = "(" + str(self.head) 38 | while current != Nil: 39 | out += ' ' + str(current.head) 40 | current = current.get_next() 41 | return out + ')' 42 | 43 | 44 | class List(metaclass=ABCMeta): 45 | @abstractmethod 46 | def is_empty(): 47 | pass 48 | 49 | def head(): 50 | pass 51 | 52 | def tail(): 53 | pass 54 | 55 | 56 | List.register(Nil); 57 | List.register(Cons) 58 | 59 | def concat(xs, ys): 60 | """Concatenates two lists""" 61 | if xs is Nil: 62 | return ys 63 | else: 64 | return cons(xs.head, concat(xs.tail, ys)) 65 | 66 | 67 | def nth(n , xs): 68 | """Returns nt-h (0 based indexing) elemt of the list, 69 | throws an exception when out of range""" 70 | if empty(xs): 71 | return Exception("Out Of Bound") 72 | if n == 0: 73 | return xs.head 74 | else: 75 | return nth(n - 1, xs.tail) 76 | 77 | def length(xs): 78 | """Returns length of a list O(n)""" 79 | if xs is Nil: 80 | return 0 81 | else: 82 | return 1 + length(xs.tail) 83 | def empty(xs): 84 | if xs is Nil: 85 | return True 86 | else: 87 | return False 88 | 89 | def cons(elem ,xs): 90 | """Cons element elem to the list""" 91 | return Cons(elem, xs) 92 | 93 | 94 | #------ helper function:--------------- 95 | def subs_in_expr(new, old, xs): # this helper function works put single list element which maybe list itself 96 | if xs is not Cons: 97 | if xs == old: 98 | return new 99 | else: 100 | return xs 101 | else: 102 | return subst(new, old, xs) 103 | 104 | def subst(new, old, xs): 105 | """substitutes new as old in a list(possible nested)""" 106 | if xs is Nil: 107 | return Nil 108 | else: 109 | return cons(subs_in_expr(new, old, xs.head) , subst(new ,old, xs.tail)) 110 | 111 | def Create_list(args): 112 | """Crates immutable list from any iterable args""" 113 | if args is None: 114 | return Nil() 115 | tmp = len(args) - 1 116 | def helper(xs, cnt, limit): 117 | if cnt > limit: 118 | return Nil 119 | else: 120 | return Cons(xs[cnt], helper(xs, cnt + 1, limit)) 121 | return helper(args, 0, tmp) 122 | 123 | def Create_from_list(elem = None, lst = None): 124 | if elem is not None: 125 | return Cons(elem, lst) 126 | else: 127 | return Nil() 128 | 129 | 130 | def duplicate(n, xs): 131 | """return n duplicates n times expression xs""" 132 | if n == 0: 133 | return Nil 134 | else: 135 | return cons(xs, duplicate(n - 1, xs)) 136 | 137 | def to_list(*args): 138 | """Create a single element cons list from an argument/s""" 139 | if args is None: 140 | return Nil() 141 | else: 142 | return Cons(args, Nil) 143 | 144 | 145 | def my_map(f, xs): # my_map to not cover map from std 146 | """Standart map, map a function onto a list""" 147 | if xs is Nil: 148 | return Nil 149 | else: 150 | return f(xs.head) |c| my_map(f, xs.tail) 151 | 152 | def my_filter(pred, xs): # to not cover filter from std 153 | """Filter on list""" 154 | if xs is Nil: 155 | #pdb.set_trace() 156 | return Nil 157 | else: 158 | if pred(xs.head): 159 | return cons(xs.head, my_filter(pred, xs.tail)) 160 | else: 161 | return my_filter(pred, xs.tail) 162 | 163 | def remove_nth(n, xs): 164 | """Removes the n-th elem from the list, throw an Exception 165 | if index out of bounds""" 166 | if isinstance(xs, Nil): 167 | return Exception("Out of Bounds") 168 | else: 169 | if n == 0: 170 | if xs.tail is not Nil: 171 | return cons(xs.tail.head, xs.tail.tail) 172 | else: 173 | return Nil 174 | else: 175 | return cons([xs.head, remove_nth(n - 1, xs.tail)]) 176 | 177 | def down(xs): 178 | """Wrap parenthesis every each top level expression""" 179 | return my_map(lambda x: Cons(x, Nil), xs) 180 | 181 | 182 | 183 | def list_set(xs, n, elem): 184 | """Returns list with n - th element updated to elem""" 185 | if isinstance(xs, Nil): 186 | return Exception("Out of Bounds") 187 | else: 188 | if n == 0: 189 | return cons(elem, xs.tail) 190 | else: 191 | return cons(xs.head, list_set(xs.tail, n - 1, elem)) 192 | 193 | 194 | #-------helper function:----------------------- 195 | def count_occurencies_nested(x, xs): 196 | """ cont_ocurencies helper, returns number of occurencies in an expression""" 197 | if not isinstance(xs, Cons): 198 | if xs == x: 199 | return 1 200 | else: 201 | return 0 202 | else: 203 | return count_occurencies(x, xs) 204 | 205 | def count_occurencies(x, xs): 206 | """Count occurencies of x in xs (possible nested)""" 207 | if xs is Nil: 208 | return 0 209 | else: 210 | return count_occurencies_nested(x, xs.head) + count_occurencies(x, xs.tail) 211 | 212 | #----------helper function:------------- 213 | def product_helper(x, ys): 214 | """Building a list of pairs - multiplies elem x times list ys """ 215 | if ys is Nil: 216 | return Nil 217 | else: 218 | return cons(Cons(x, ys.head), product_helper(x, ys.tail)) 219 | 220 | 221 | def product(xs, ys): 222 | """Returns cartesian product of two lists (lists are without 223 | repetitions).""" 224 | if xs is Nil: 225 | return Nil 226 | else: 227 | return cons(product_helper(xs.head, ys), product(xs.tail, ys)) 228 | 229 | def reverse(xs, ys): 230 | """reverse a list""" 231 | if empty(ys): 232 | return xs 233 | else: 234 | return reverse(cons(ys.head, xs), ys.tail) 235 | 236 | def reduce(f, ys, start): 237 | """Reduce left, start is the neutral element of f""" 238 | def helper(f, xs, acc): 239 | if xs is Nil: 240 | return acc 241 | else: 242 | return helper(f, xs.tail, f(acc, xs.head)) 243 | return helper(f, ys, start) 244 | 245 | def insert(elem, n, xs): 246 | """Inserts elem in a position after index n""" 247 | if xs is Nil: 248 | return Exception("Out of bounds") 249 | else: 250 | if n == 0: 251 | return cons(xs.head, Cons(elem, xs.tail)) 252 | else: 253 | return cons(xs.head, insert(elem, n - 1, xs.tail)) 254 | -------------------------------------------------------------------------------- /double_linked_list: -------------------------------------------------------------------------------- 1 | class DoubleLinkedlist: 2 | class Node: 3 | def __init__(self, initdata): 4 | self.data = initdata 5 | self.next = None 6 | self.prev = None 7 | 8 | def getData(self): 9 | return self.data 10 | 11 | def getNext(self): 12 | return self.next 13 | 14 | def getPrev(self): 15 | return self.prev 16 | 17 | def setData(self, newdata): 18 | self.data = newdata 19 | 20 | def setNext(self, newnext): 21 | self.next = newnext 22 | 23 | def setPrev(self, newprev): 24 | self.prev = newprev 25 | 26 | def __init__(self): 27 | self.head = None 28 | self.last = None 29 | self.N = 0 30 | 31 | def is_empty(self): 32 | return self.head == None 33 | 34 | def push(self, x): 35 | temp = self.Node(x) 36 | if self.head == None: 37 | self.head = temp 38 | self.last = temp 39 | else: 40 | temp2 = self.head 41 | temp.setNext(self.head) 42 | self.head = temp 43 | temp2.setPrev(temp) 44 | self.N += 1 45 | 46 | def append(self, x): # add at the end of the list 47 | temp = self.Node(x) 48 | if self.head == None: 49 | self.head = temp 50 | self.last = temp 51 | else: 52 | temp2 = self.last 53 | temp.setPrev(self.last) 54 | self.last = temp 55 | temp2.setNext(temp) 56 | self.N += 1 57 | 58 | def __len__(self): 59 | return self.size() 60 | 61 | def size(self): 62 | return self.N 63 | 64 | def search(self, item): # returns (don't remove) item from the list 65 | current = self.head 66 | found = False 67 | while current != None and not found: 68 | if current.getData() == item: 69 | found = True 70 | else: 71 | current = current.getNext() 72 | return found 73 | 74 | def __getitem__(self, index): 75 | return self.get(index) 76 | 77 | def __setitem__(self, i, v): 78 | return self.update(v, i) 79 | 80 | def get(self, i=0): # returns item with index i 81 | current = self.head 82 | found = False 83 | cnt = 0 84 | while not cnt > i and not found: 85 | if cnt == i: 86 | found = True 87 | else: 88 | current = current.getNext() 89 | cnt += 1 90 | return current.getData() 91 | 92 | def update(self, new_item, i): # takes index and new item and update list element 93 | current = self.head 94 | cnt = 0 95 | found = False 96 | while not found: 97 | if cnt == i: 98 | current.setData(new_item) 99 | found = True 100 | else: 101 | current = current.getNext() 102 | cnt += 1 103 | 104 | def index(self, item): # return first item index in the list 105 | current = self.head 106 | found = False 107 | cnt = 0 108 | while current != None and not found: 109 | if current.getData() == item: 110 | found = True 111 | else: 112 | cnt += 1 113 | current = current.getNext() 114 | return cnt 115 | 116 | def slice(self, start, stop): # create a python style slice 117 | tempList = DoubleLinkedlist() 118 | current = self.head 119 | cnt = 0 120 | while cnt != start: 121 | cnt += 1 122 | current = current.getNext() 123 | while cnt < stop: 124 | t = current.getData() 125 | tempList.append(t) 126 | cnt += 1 127 | current = current.getNext() 128 | return tempList 129 | 130 | def remove(self, item): # delete the first occurence of an item 131 | current = self.head 132 | previous = None 133 | found = False 134 | while not found: 135 | if current.getData() == item: 136 | found = True 137 | else: 138 | previous = current 139 | current = current.getNext() 140 | 141 | if previous == None: 142 | self.head = current.getNext() 143 | else: 144 | 145 | current.setPrev(current.getPrev) 146 | previous.setNext(current.getNext()) 147 | self.N -= 1 148 | 149 | def pop(self, i=0): 150 | current = self.head 151 | previous = None 152 | found = False 153 | cnt = 0 154 | while not found: 155 | if cnt == i: 156 | found = True 157 | else: 158 | previous = current 159 | current = current.getNext() 160 | cnt += 1 161 | if previous == None: 162 | self.head = current.getNext() 163 | else: 164 | 165 | current.setPrev(current.getPrev) 166 | previous.setNext(current.getNext()) 167 | self.N -= 1 168 | 169 | def __str__(self): # enables print(list) 170 | if self.head != None: 171 | current = self.head 172 | out = '[' + str(current.getData()) 173 | while current.getNext() != None: 174 | current = current.getNext() 175 | out += ', ' + str(current.getData()) 176 | return out + ']' 177 | return '[]' 178 | 179 | def __add__(self, list_item): # magic method enables concat: l1 + l2 180 | self.last.setNext(list_item.head) 181 | list_item.head.setPrev(self.last) 182 | self.last = list_item.last 183 | self.N += list_item.size() 184 | 185 | def iterate(self): # returns iterator over the list 186 | current = self.head 187 | while current != None: 188 | yield current 189 | current = current.getNext() 190 | 191 | def __eq__(self, other): # defines equality, enables to use == as a value equality 192 | if self.size() != other.size(): 193 | return False 194 | current = self.head 195 | current2 = other.head 196 | while current != None: 197 | if current.getData() != current2.getData(): 198 | return False 199 | else: 200 | current = current.getNext() 201 | current2 = current2.getNext() 202 | return True 203 | -------------------------------------------------------------------------------- /graphs_dfs.py: -------------------------------------------------------------------------------- 1 | # Simple graph API in Python, implementation uses adjacent lists. 2 | # look also here: 3 | # Classes: Graph, Depth_first_search, Depth_first_paths 4 | # Usage: 5 | # Creating new graph: gr1 = Graph(v) - creates new graph with no edges and v vertices; 6 | 7 | # Search object: gr2 = Depth_first_search(graph, vertex) - creates search object, 8 | # gr2.marked_vertex(vertex) - returns true if given vertex is reachable from source(above) 9 | 10 | # Path object: gr3 = Depth_first_paths(graph, vertex)- creates a new path object, 11 | # gr3.has_path(vertex) - thee same as above 12 | # gr3.path_to(vertex) - returns path from source vertex (to the given) 13 | from collections import deque 14 | 15 | 16 | class Graph: 17 | """Class graph, creates a graph - described by integers - number 18 | of vertices - V : v0, v1, ..., v(V-1)""" 19 | 20 | def __init__(self, v_in): 21 | """constructor - takes number of vertices and creates a graph 22 | with no edges (E = 0) and an empty adjacent lists of vertices""" 23 | self.V = v_in 24 | self.E = 0 25 | self.adj = [] 26 | for i in range(v_in): 27 | self.adj.append([]) 28 | 29 | def V(self): 30 | """returns number of vertices""" 31 | return self.V 32 | 33 | def E(self): 34 | """returns number of edges""" 35 | return self.E 36 | 37 | def add_edge(self, v, w): 38 | """adds an edge to the graph, takes two integers (two vertices) 39 | and creates an edge v,w - by modifying appropriate adjacent lists """ 40 | self.adj[v].append(w) 41 | self.adj[w].append(v) 42 | self.E += 1 43 | 44 | def adj_list(self, v): 45 | """Takes an integer - a graph vertex and returns the adjacency lists of it""" 46 | return self.adj[v] 47 | 48 | def __str__(self): 49 | """to string method, prints the graph""" 50 | s = str(self.V) + " vertices, " + str(self.E) + " edges\n" 51 | for v in range(self.V): 52 | s += str(v) + ": " 53 | for w in self.adj[v]: 54 | s += str(w) + " " 55 | s += "\n" 56 | return s 57 | 58 | 59 | class Depth_first_search: 60 | """class depth forst search, creates an object, 61 | constructor takes graph and a vertex""" 62 | 63 | def __init__(self, gr_obj, v_obj): 64 | self.marked = [False] * gr_obj.V 65 | self.cnt = 0 66 | self.__dfs(gr_obj, v_obj) 67 | 68 | def __dfs(self, gr, v): 69 | """private depth first search, proceed recursively, 70 | mutates marked - marks the all possible to reach 71 | from given (v) vertices; also mutates cnt - number of visited vert""" 72 | self.marked[v] = True 73 | self.cnt += 1 74 | for w in gr.adj_list(v): 75 | if self.marked[w] == False: 76 | self.__dfs(gr, w) 77 | 78 | def marked_vertex(self, w): 79 | """Takes an integer - a graph vertex and returns True if it's reachable 80 | from vertex v (source)""" 81 | return self.marked[w] 82 | 83 | def count(self): 84 | """returns number of visited verticles 85 | (from given in the constructor vertex)""" 86 | return self.cnt 87 | 88 | 89 | class Depth_first_paths: 90 | """class depth first paths, solves 91 | single paths problem: given graph and a vertex (source vertex), find 92 | a path to another vertex.""" 93 | 94 | def __init__(self, gr_obj, v_obj): 95 | self.marked = [False] * gr_obj.V 96 | self.edge_to = [0] * gr_obj.V 97 | self.s = v_obj 98 | self.__dfs(gr_obj, v_obj) 99 | 100 | def __dfs(self, gr, v): 101 | """private recursive depth first search, mutates array marked, 102 | mutates counter (cnt), and creates a path (filling an array edge_to)""" 103 | self.marked[v] = True 104 | for w in gr.adj_list(v): 105 | if self.marked[w] == False: 106 | self.edge_to[w] = v 107 | self.__dfs(gr, w) 108 | 109 | def has_path(self, v): 110 | """Takes an integer - a graph vertex and returns true if there is a path from the source 111 | vertex to the given, else false""" 112 | return self.marked[v] 113 | 114 | def path_to(self, v): 115 | """Takes an integer - a graph vertex and returns path from source[vertex] to it""" 116 | if self.has_path(v) == False: 117 | return None 118 | path = deque() 119 | x = v 120 | while x != self.s: 121 | path.appendleft(x) 122 | x = self.edge_to[x] 123 | path.appendleft(self.s) 124 | return path 125 | 126 | 127 | cnt = 0 128 | 129 | 130 | def dfs(gr, v): 131 | """depth first search as a function""" 132 | marked = [False] * gr.V 133 | 134 | def df(grap, w): 135 | """central dfs recursive method""" 136 | global cnt 137 | cnt += 1 138 | marked[w] = True 139 | for x in grap.adj_list(w): 140 | if marked[x] == False: 141 | df(grap, x) 142 | 143 | df(gr, v) 144 | return marked, cnt 145 | 146 | 147 | if __name__ == '__main__': 148 | gr1 = Graph(4) 149 | print(gr1) 150 | print(gr1.adj_list(1)) 151 | gr1.add_edge(2, 3) 152 | print(gr1) 153 | print(gr1.E) 154 | print(gr1.adj_list(2)) 155 | print(gr1.adj_list(0)) 156 | print("---------dfs------------") 157 | gr2 = Graph(6) 158 | gr2.add_edge(0, 5) 159 | # gr2.add_edge(2, 4) 160 | gr2.add_edge(2, 3) 161 | gr2.add_edge(1, 2) 162 | gr2.add_edge(0, 1) 163 | # gr2.add_edge(3, 4) 164 | gr2.add_edge(3, 5) 165 | gr2.add_edge(0, 2) 166 | print(gr2) 167 | print(dfs(gr2, 0)) 168 | df = dfs(gr2, 0) 169 | print("---------class Depth_first_search---------") 170 | df1 = Depth_first_search(gr2, 0) 171 | print(df1.count()) 172 | print("------------class Depth_first_paths-----------") 173 | dfp1 = Depth_first_paths(gr2, 0) 174 | print(dfp1.path_to(3)) 175 | -------------------------------------------------------------------------------- /heap.py: -------------------------------------------------------------------------------- 1 | # binary heap - min heap 2 | 3 | class Bin_heap: 4 | def __init__(self): 5 | self.heap_list = [0] 6 | self.__current_size = 0 7 | 8 | def build_heap(self, xs): 9 | i = len(xs) // 2 10 | self.__current_size = len(xs) 11 | self.heap_list = [0] + xs[:] 12 | while i > 0: 13 | self.__pop_down(i) 14 | i = i - 1 15 | 16 | def del_min(self): 17 | res = self.heap_list[1] 18 | self.heap_list[1] = self.heap_list[self.__current_size] 19 | self.__current_size -= 1 20 | self.heap_list.pop() 21 | self.__pop_down(1) 22 | return res 23 | 24 | def insert(self, x): 25 | self.heap_list.append(x) 26 | self.__current_size += 1 27 | self.__pos_item(self.__current_size) 28 | 29 | def find_min(self): 30 | return self.heap_list[1] 31 | 32 | def size(self): 33 | return self.__current_size 34 | 35 | def __str__(self): 36 | return str(print(self.heap_list[1:])) 37 | 38 | def __len__(self): 39 | return self.size() 40 | 41 | # private methods 42 | 43 | def __pos_item(self, i): 44 | while i // 2 > 0: 45 | if self.heap_list[i] < self.heap_list[i // 2]: 46 | tmp = self.heap_list[i // 2] 47 | self.heap_list[i // 2] = self.heap_list[i] 48 | self.heap_list[i] = tmp 49 | i //= 2 50 | 51 | def __pop_down(self, i): 52 | while i * 2 <= self.__current_size: 53 | min_ch = self.__min_child(i) 54 | if self.heap_list[i] > self.heap_list[min_ch]: 55 | tmp = self.heap_list[i] 56 | self.heap_list[i] = self.heap_list[min_ch] 57 | self.heap_list[min_ch] = tmp 58 | i = min_ch 59 | 60 | def __min_child(self, i): 61 | if i * 2 + 1 > self.__current_size: 62 | return i * 2 63 | else: 64 | if self.heap_list[i * 2] < self.heap_list[i * 2 + 1]: 65 | return i * 2 66 | else: 67 | return i * 2 + 1 68 | 69 | if __name__ == "__main__": 70 | h1 = Bin_heap() 71 | h1.build_heap([8, 23, 5, 6, 77, 1, -98]) 72 | print(h1) 73 | print(h1.find_min()) 74 | print(h1) 75 | h1.del_min() 76 | print(h1) 77 | h1.insert(-909) 78 | print(h1) 79 | print(len(h1)) 80 | ''' 81 | output -> 82 | [-98, 6, 1, 23, 77, 8, 5] 83 | None 84 | -98 85 | [-98, 6, 1, 23, 77, 8, 5] 86 | None 87 | [1, 6, 5, 23, 77, 8] 88 | None 89 | [-909, 6, 1, 23, 77, 8, 5] 90 | None 91 | 7 92 | ''' 93 | -------------------------------------------------------------------------------- /immutable tree.py: -------------------------------------------------------------------------------- 1 | # Recursive definition of binary search tree (immutable) 2 | # I follows a grammar: 3 | # Binary-search-tree :: = () | (Val Binary-search-tree Binary-search-tree) Val should support >, <, = 4 | # is empty or it's a list of Int and two binary trees 5 | # there's gonna be right and left subtree 6 | # The interface strictly follow this definition 7 | 8 | class Nil_tree: 9 | """class Nil_tree, the empty tree""" 10 | 11 | def is_empty(self): 12 | return True 13 | def left(self): 14 | return Exception("Empty") 15 | def right(self): 16 | return Exception("Empty") 17 | def __str__(self): 18 | return "()" 19 | 20 | class Binary_tree: 21 | """Class Binary_tree, the non empty tree: ( val, left, right)""" 22 | 23 | def __init__(self, _item, _left, _right): 24 | self.item = _item 25 | self.left = _left 26 | self.right = _right 27 | 28 | def is_empty(self): 29 | return False 30 | 31 | 32 | 33 | class Tree(metaclass=ABCMeta): 34 | 35 | @abstractmethod 36 | def is_empty(self): 37 | pass 38 | def item(self): 39 | pass 40 | def left(self): 41 | pass 42 | def right(self): 43 | pass 44 | 45 | Tree.register(Nil_tree); 46 | Tree.register(Binary_tree) 47 | 48 | # few tree methods: 49 | def inorder(tree): 50 | """Inorder traversal""" 51 | if tree is Nil_tree: 52 | return Nil_tree 53 | else: 54 | inorder(tree.left) 55 | print(tree.item) 56 | inorder(tree.right) 57 | 58 | def make_tree(item, left_branch, right_branch): 59 | """Makes a tree, item is any python value 60 | left and right branches are trees, possible empty""" 61 | return Binary_tree(item, left_branch, right_branch) 62 | 63 | def is_element(elem, tree): 64 | """Check if elem is in binary tree""" 65 | if tree is Nil_tree: 66 | return False 67 | elif elem < tree.item: 68 | return is_element(elem, tree.left) 69 | elif elem > tree.item: 70 | return is_element(elem, tree.right) 71 | else: 72 | return True 73 | 74 | def join_tree(elem, tree): 75 | """Add eleme to the binary tree returns tree if 76 | elem is already there""" 77 | if tree is Nil_tree: 78 | return make_tree(elem, Nil_tree, Nil_tree) 79 | elif elem < tree.item: 80 | return make_tree(tree.item, join_tree(elem, tree.left), tree.right) 81 | elif elem > tree.item: 82 | return make_tree(tree.item, tree.left, join_tree(elem, tree.right)) 83 | else: 84 | return tree 85 | -------------------------------------------------------------------------------- /n_ary_trees.py: -------------------------------------------------------------------------------- 1 | 2 | class NaryTree: 3 | def __init__(self, rootObj): 4 | self.key = rootObj 5 | self.parent = None 6 | self.kids = None 7 | 8 | def insert(self, newNode): 9 | if self.kids: 10 | t = NaryTree(newNode) 11 | self.kids.append(t) 12 | t.parent = self 13 | else: 14 | t = NaryTree(newNode) 15 | self.kids = [] 16 | self.kids.append(t) 17 | t.parent = self 18 | 19 | def setRootVal(self, obj): 20 | self.key.append(obj) 21 | 22 | def getRootVal(self): 23 | return self.key 24 | 25 | def getParent(self): 26 | return self.parent 27 | 28 | def getNthKid(self, i=-1): # return a child index i, the last one if i not specified 29 | return self.kids[i] 30 | 31 | def traverse(tree): # tree traversal, DFS 32 | if tree: 33 | stk = [] 34 | stk.append(tree) 35 | while len(stk) > 0: 36 | top = stk.pop() 37 | if top.kids: 38 | for child in top.kids: 39 | stk.append(child) 40 | print(top.getRootVal()) 41 | 42 | else: 43 | return None -------------------------------------------------------------------------------- /parse_tree.py: -------------------------------------------------------------------------------- 1 | from binary_trees import BinaryTree, preorder_traversal, postorder_traversal, inorder_traversal 2 | 3 | import operator as op 4 | 5 | 6 | 7 | def build_parse_tree(exp): 8 | exp_list = exp.replace('(', ' ( ').replace(')', ' ) ').split() 9 | e_tree = BinaryTree('') 10 | current_tree = e_tree 11 | for token in exp_list: 12 | if token == '(': 13 | current_tree.insertLeft('') 14 | current_tree = current_tree.getLeftChild() 15 | elif token in ['+','-','/','*']: 16 | current_tree.setRootVal(token) 17 | current_tree.insertRight('') 18 | current_tree = current_tree.getRightChild() 19 | elif token not in ['+','-','/','*', '(', ')']: 20 | current_tree.setRootVal(int(token)) 21 | current_tree = current_tree.getParent() 22 | elif token == ')': 23 | current_tree = current_tree.getParent() 24 | else: 25 | raise ValueError 26 | 27 | return e_tree 28 | 29 | def evaluate_parse_tree(tree): 30 | opers = {'+': op.add, '-':op.sub, '*':op.mul, '/':op.truediv} 31 | 32 | leftT = tree.getLeftChild() 33 | rightT = tree.getRightChild() 34 | 35 | if leftT and rightT: 36 | fn = opers[tree.getRootVal()] 37 | return fn(evaluate_parse_tree(leftT), evaluate_parse_tree(rightT)) 38 | else: 39 | return tree.getRootVal() 40 | 41 | 42 | pt = BinaryTree('') 43 | pt = build_parse_tree("((34 * 5)+(3 + 5))") 44 | print("pt->root", pt.getRootVal()) 45 | print("pt->root->right->right <-parent: rootVal", pt.getRightChild().getRightChild().getParent().getRootVal()) 46 | pt.preorder() 47 | print("--------------------------------------") 48 | postorder_traversal(pt) 49 | print(evaluate_parse_tree(pt)) 50 | inorder_traversal(pt) 51 | print("--------------------------------------") 52 | 53 | print(evaluate_parse_tree(pt)) --------------------------------------------------------------------------------