├── AVLTrees ├── solution_avl_tree.py ├── starter_avl_tree.py └── test_avl_tree.py ├── Binary-Search ├── iterativeBinarySearch.py └── recursiveBinarySearch.py ├── Linked-Lists ├── doublylinkedlist.py └── linkedlist.py ├── README.md └── Trie └── trie.py /AVLTrees/solution_avl_tree.py: -------------------------------------------------------------------------------- 1 | 2 | class Node(object): 3 | """Nodes in binary search tree, specifically for AVL tree""" 4 | def __init__(self, data): 5 | self.data = data 6 | self.height = 0 7 | self.parent = None 8 | self.left_child = None 9 | self.right_child = None 10 | 11 | def __repr__(self): 12 | """Return a string representation of this node""" 13 | return 'Node({})'.format(repr(self.data)) 14 | 15 | def balance_factor(self): 16 | return (self.left_child.height if self.left_child else -1) - (self.right_child.height if self.right_child else -1) 17 | 18 | def update_height(self): 19 | if not self.right_child and not self.left_child: 20 | self.height = 0 21 | elif not self.right_child: 22 | self.height = (self.left_child.height + 1) 23 | elif not self.left_child: 24 | self.height = (self.right_child.height + 1) 25 | else: 26 | self.height = (max(self.left_child.height, self.right_child.height) + 1) 27 | 28 | # # Recursive calculation of height -- can be removed 29 | # def calculate_height(self): 30 | # """Return the number of edges on the longest downward path from this 31 | # node to a descendant leaf node""" 32 | # # TODO: Check if left child has a value and if so calculate its height 33 | # left_height = self.left_child.height if self.left_child is not None else -1 34 | # # TODO: Check if right child has a value and if so calculate its height 35 | # right_height = self.right_child.height if self.right_child is not None else -1 36 | # # Return one more than the greater of the left height and right height 37 | # return 1 + max(left_height, right_height) 38 | 39 | 40 | 41 | class AVLTree(object): 42 | """AVLTree, a self balancing binary search tree where the heights of each child node do not differ by more than 1""" 43 | def __init__(self, iterable=None): 44 | self.root = None 45 | if iterable: 46 | for item in iterable: 47 | self.insert(item) 48 | 49 | def __repr__(self): 50 | """Return a string representation of this AVL tree""" 51 | return 'AVLTree({})'.format(self.items_level_order()) 52 | 53 | def is_empty(self): 54 | """Return True if this AVL tree contains no nodes""" 55 | return self.root is None 56 | 57 | def find(self, data): 58 | current = self.root 59 | while current is not None: 60 | if current.data == data: 61 | return current 62 | elif current.data > data: 63 | current = current.left_child 64 | continue 65 | elif current.data < data: 66 | current = current.right_child 67 | continue 68 | raise ValueError('%s not found in tree.' % (data)) 69 | 70 | def insert(self, data): 71 | # print('') 72 | # print('Inserting ({}) ...'.format(data)) 73 | 74 | n = Node(data) 75 | if self.root is None: 76 | self.root = n 77 | return 78 | 79 | current = self.root 80 | while current is not None: 81 | if current.data == data: 82 | # do nothing? raise error? 83 | raise ValueError('%s already in tree.' % (data)) 84 | elif current.data > data: 85 | if not current.left_child: 86 | current.left_child = n 87 | n.parent = current 88 | # update heights of parents and rotate if needed 89 | self.retrace_loop(n) 90 | return 91 | else: 92 | current = current.left_child 93 | continue 94 | elif current.data < data: 95 | if not current.right_child: 96 | current.right_child = n 97 | n.parent = current 98 | # update heights of parents and rotate if needed 99 | self.retrace_loop(n) 100 | return 101 | else: 102 | current = current.right_child 103 | continue 104 | 105 | def retrace_loop(self, node): 106 | # print('retrace_loop({})'.format(node)) 107 | 108 | current = node.parent 109 | while current is not None: 110 | # print('current: {}'.format(current)) 111 | 112 | current.update_height() 113 | 114 | balance_factor = current.balance_factor() 115 | # print('balance_factor: {}'.format(balance_factor)) 116 | 117 | if balance_factor < -1: 118 | # right heavy 119 | 120 | # check the right child of current to see if it's left heavy 121 | right_child_balance_factor = current.right_child.balance_factor() 122 | if right_child_balance_factor >= 1: 123 | # right rotation needed before left 124 | self.right_rotation(current.right_child) 125 | self.left_rotation(current) 126 | current = current.parent 127 | continue 128 | 129 | elif balance_factor > 1: 130 | # left heavy 131 | 132 | # check the left child of current to see if it's right heavy 133 | left_child_balance_factor = current.left_child.balance_factor() 134 | if left_child_balance_factor <= -1: 135 | # left rotation needed before right 136 | self.left_rotation(current.left_child) 137 | self.right_rotation(current) 138 | current = current.parent 139 | continue 140 | else: 141 | # balanced 142 | current = current.parent 143 | 144 | def update(self, node, data): 145 | try: 146 | n = self.find(node) 147 | n.data = data 148 | except ValueError: 149 | raise ValueError('%s not found in tree.' % (node)) 150 | 151 | def left_rotation(self, node): 152 | # print('left_rotation({})'.format(node)) 153 | 154 | # o // node 155 | # \ 156 | # o // node.right_child 157 | # \ 158 | # o 159 | 160 | # nodes right child becomes parent, node becomes left child 161 | new_left_child = node 162 | new_right_child_of_left_child = node.right_child.left_child 163 | new_parent = node.right_child 164 | new_parents_parent = node.parent 165 | 166 | if new_parents_parent is None: 167 | # new_parent is becoming the tree's root 168 | self.root = new_parent 169 | new_parent.parent = None 170 | else: 171 | # check to see if this is the left or right child of the parent node 172 | if node.data > new_parents_parent.data: 173 | new_parents_parent.right_child = new_parent 174 | else: 175 | new_parents_parent.left_child = new_parent 176 | new_parent.parent = new_parents_parent 177 | 178 | new_parent.left_child = new_left_child 179 | new_left_child.parent = new_parent 180 | new_left_child.right_child = new_right_child_of_left_child 181 | if new_right_child_of_left_child: 182 | new_right_child_of_left_child.parent = new_left_child 183 | new_left_child.update_height() 184 | new_parent.update_height() 185 | 186 | def right_rotation(self, node): 187 | # print('right_rotation({})'.format(node)) 188 | 189 | # o // node 190 | # / 191 | # o // node.left_child 192 | # / 193 | # o 194 | 195 | # nodes left child becomes parent, node becomes right child 196 | new_right_child = node 197 | new_left_child_of_right_child = node.left_child.right_child 198 | new_parent = node.left_child 199 | 200 | new_parents_parent = node.parent 201 | if new_parents_parent is None: 202 | # new_parent is becoming the tree's root 203 | self.root = new_parent 204 | new_parent.parent = None 205 | else: 206 | # check to see if this is the left or right child of the parent node 207 | if node.data > new_parents_parent.data: 208 | new_parents_parent.right_child = new_parent 209 | else: 210 | new_parents_parent.left_child = new_parent 211 | new_parent.parent = new_parents_parent 212 | 213 | new_parent.right_child = new_right_child 214 | new_right_child.parent = new_parent 215 | new_right_child.left_child = new_left_child_of_right_child 216 | if new_left_child_of_right_child: 217 | new_left_child_of_right_child.parent = new_right_child 218 | new_right_child.update_height() 219 | new_parent.update_height() 220 | 221 | def items_level_order(self): 222 | """Return a list of all items in this binary search tree found using 223 | level-order traversal""" 224 | # Create a queue to store nodes not yet traversed in level-order 225 | queue = list() 226 | # Create an items list 227 | items = list() 228 | # Enqueue the root node if this tree is not empty 229 | if not self.is_empty(): 230 | queue.append(self.root) 231 | # Loop until the queue is empty 232 | while len(queue) > 0: 233 | # Dequeue the node at the front of the queue 234 | node = queue.pop(0) 235 | # Add this node's data to the items list 236 | items.append(node.data) 237 | # Enqueue this node's left child if it exists 238 | if node.left_child is not None: 239 | queue.append(node.left_child) 240 | # Enqueue this node's right child if it exists 241 | if node.right_child is not None: 242 | queue.append(node.right_child) 243 | # Return the items list 244 | return items 245 | 246 | 247 | 248 | if __name__ == "__main__": 249 | 250 | # # Start with an empty AVL tree 251 | # avl_tree = AVLTree() 252 | # max_num = 3 253 | # for item in range(1, max_num + 1): 254 | # print('Inserting {} into tree...'.format(item)) 255 | # avl_tree.insert(item) 256 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 257 | # print('\n') 258 | 259 | 260 | # # Start with a balanced AVL tree with 3 nodes 261 | # avl_tree = AVLTree([2,1,3]) 262 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 263 | # print('Inserting {} into tree...'.format(4)) 264 | # avl_tree.insert(4) 265 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 266 | # print('') 267 | # print('Inserting {} into tree...'.format(5)) 268 | # avl_tree.insert(5) # Should trigger rebalance 269 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 270 | # print('') 271 | 272 | # # Start with an empty AVL tree for left-right right_rotation 273 | # data = [1, 4, 8, 12, 16, 20, 25, 30, 35, 28] 274 | data = [20, 10, 40, 30, 50, 55] 275 | print('Inserting: {}'.format(data)) 276 | avl_tree = AVLTree(data) 277 | print('items in level-order: {}'.format(avl_tree.items_level_order())) 278 | 279 | -------------------------------------------------------------------------------- /AVLTrees/starter_avl_tree.py: -------------------------------------------------------------------------------- 1 | 2 | class Node(object): 3 | """Nodes in binary search tree, specifically for AVL tree""" 4 | def __init__(self, data): 5 | self.data = data 6 | self.height = 0 7 | self.parent = None 8 | self.left_child = None 9 | self.right_child = None 10 | 11 | def __repr__(self): 12 | """Return a string representation of this node""" 13 | return 'Node({})'.format(repr(self.data)) 14 | 15 | def balance_factor(self): 16 | return (self.left_child.height if self.left_child else -1) - (self.right_child.height if self.right_child else -1) 17 | 18 | def update_height(self): 19 | if not self.right_child and not self.left_child: 20 | self.height = 0 21 | elif not self.right_child: 22 | self.height = (self.left_child.height + 1) 23 | elif not self.left_child: 24 | self.height = (self.right_child.height + 1) 25 | else: 26 | self.height = (max(self.left_child.height, self.right_child.height) + 1) 27 | 28 | 29 | class AVLTree(object): 30 | """AVLTree, a self balancing binary search tree where the heights of each child node do not differ by more than 1""" 31 | def __init__(self, iterable=None): 32 | self.root = None 33 | if iterable: 34 | for item in iterable: 35 | self.insert(item) 36 | 37 | def __repr__(self): 38 | """Return a string representation of this AVL tree""" 39 | return 'AVLTree({})'.format(self.items_level_order()) 40 | 41 | def is_empty(self): 42 | """Return True if this AVL tree contains no nodes""" 43 | pass 44 | 45 | def find(self, data): 46 | pass 47 | 48 | def insert(self, data): 49 | # print('') 50 | # print('Inserting ({}) ...'.format(data)) 51 | 52 | n = Node(data) 53 | 54 | if self.root is None: 55 | self.root = n 56 | return 57 | else: 58 | current = self.root 59 | while current is not None: 60 | if current.data == data: 61 | # your preference, raise error or do nothing 62 | raise ValueError('%s already in tree.' % (data)) 63 | elif current.data > data: 64 | if not current.left_child: 65 | current.left_child = n 66 | n.parent = current 67 | # update heights of parents and rotate if needed 68 | self.retrace_loop(n) 69 | return 70 | else: 71 | current = current.left_child 72 | continue 73 | elif current.data < data: 74 | if not current.right_child: 75 | current.right_child = n 76 | n.parent = current 77 | # update heights of parents and rotate if needed 78 | self.retrace_loop(n) 79 | return 80 | else: 81 | current = current.right_child 82 | continue 83 | 84 | def retrace_loop(self, node): 85 | # print('retrace_loop({})'.format(node)) 86 | 87 | current = node.parent 88 | while current is not None: 89 | # print('current: {}'.format(current)) 90 | 91 | current.update_height() 92 | balance_factor = current.balance_factor() 93 | # print('balance_factor: {}'.format(balance_factor)) 94 | 95 | if balance_factor < -1: 96 | # right heavy 97 | 98 | # check if right node is left heavy 99 | right_child_balance_factor = current.right_child.balance_factor() 100 | if right_child_balance_factor >= 1: 101 | # right rotation needed before left 102 | self.right_rotation(current.right_child) 103 | 104 | self.left_rotation(current) 105 | current = current.parent 106 | continue 107 | elif balance_factor > 1: 108 | # left heavy 109 | 110 | # check if left node is right heavy 111 | left_child_balance_factor = current.left_child.balance_factor() 112 | if left_child_balance_factor <= -1: 113 | # left rotation needed before right 114 | self.left_rotation(current.left_child) 115 | 116 | self.right_rotation(current) 117 | current = current.parent 118 | continue 119 | else: 120 | # balanced 121 | pass 122 | current = current.parent 123 | 124 | def update(self, node, data): 125 | pass 126 | 127 | def left_rotation(self, node): 128 | print('left_rotation({})'.format(node)) 129 | 130 | # o // node 131 | # \ 132 | # o // node.right_child 133 | # \ 134 | # o 135 | 136 | new_left_child = node 137 | new_right_child_of_left_child = node.right_child.left_child 138 | new_parent = node.right_child 139 | new_parents_parent = node.parent 140 | 141 | if new_parents_parent is None: 142 | # new_parent is becoming the tree's root 143 | self.root = new_parent 144 | new_parent.parent = None 145 | else: 146 | # check to see if this is the left or right child of the parent node 147 | if node.data > new_parents_parent.data: 148 | new_parents_parent.right_child = new_parent 149 | else: 150 | new_parents_parent.left_child = new_parent 151 | new_parent.parent = new_parents_parent 152 | 153 | new_parent.left_child = new_left_child 154 | new_left_child.parent = new_parent 155 | new_left_child.right_child = new_right_child_of_left_child 156 | if new_right_child_of_left_child: 157 | new_right_child_of_left_child.parent = new_left_child 158 | new_left_child.update_height() 159 | new_parent.update_height() 160 | 161 | 162 | def right_rotation(self, node): 163 | print('right_rotation({})'.format(node)) 164 | 165 | # o // node 166 | # / 167 | # o // node.left_child 168 | # / 169 | # o 170 | 171 | new_right_child = node 172 | new_left_child_of_right_child = node.left_child.right_child 173 | new_parent = node.left_child 174 | 175 | new_parents_parent = node.parent 176 | if new_parents_parent is None: 177 | # new_parent is becoming the tree's root 178 | self.root = new_parent 179 | new_parent.parent = None 180 | else: 181 | # check to see if this is the left or right child of the parent node 182 | if node.data > new_parents_parent.data: 183 | new_parents_parent.right_child = new_parent 184 | else: 185 | new_parents_parent.left_child = new_parent 186 | new_parent.parent = new_parents_parent 187 | 188 | new_parent.right_child = new_right_child 189 | new_right_child.parent = new_parent 190 | new_right_child.left_child = new_left_child_of_right_child 191 | if new_left_child_of_right_child: 192 | new_left_child_of_right_child.parent = new_right_child 193 | new_right_child.update_height() 194 | new_parent.update_height() 195 | 196 | def items_level_order(self): 197 | """Return a list of all items in this binary search tree found using 198 | level-order traversal""" 199 | # Create a queue to store nodes not yet traversed in level-order 200 | queue = list() 201 | # Create an items list 202 | items = list() 203 | # Enqueue the root node if this tree is not empty 204 | if not self.is_empty(): 205 | queue.append(self.root) 206 | # Loop until the queue is empty 207 | while len(queue) > 0: 208 | # Avoid infinite loop if tree has duplicate child pointers 209 | # if len(items) > 10: 210 | # print(items) 211 | # return 212 | # Dequeue the node at the front of the queue 213 | node = queue.pop(0) 214 | # Add this node's data to the items list 215 | items.append(node.data) 216 | # Enqueue this node's left child if it exists 217 | if node.left_child is not None: 218 | queue.append(node.left_child) 219 | # Enqueue this node's right child if it exists 220 | if node.right_child is not None: 221 | queue.append(node.right_child) 222 | # Return the items list 223 | return items 224 | 225 | 226 | 227 | if __name__ == "__main__": 228 | 229 | # # Start with an empty AVL tree 230 | # avl_tree = AVLTree() 231 | # max_num = 3 232 | # for item in range(1, max_num + 1): 233 | # print('Inserting {} into tree...'.format(item)) 234 | # avl_tree.insert(item) 235 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 236 | # print('\n') 237 | 238 | avl_tree = AVLTree() 239 | data = [3, 2, 1] 240 | for item in data: 241 | print('Inserting {} into tree...'.format(item)) 242 | avl_tree.insert(item) 243 | print('items in level-order: {}'.format(avl_tree.items_level_order())) 244 | print('\n') 245 | 246 | # # Start with a balanced AVL tree with 3 nodes 247 | # avl_tree = AVLTree([2,1,3]) 248 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 249 | # print('Inserting {} into tree...'.format(4)) 250 | # avl_tree.insert(4) 251 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 252 | # print('') 253 | # print('Inserting {} into tree...'.format(5)) 254 | # avl_tree.insert(5) # Should trigger rebalance 255 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 256 | # print('') 257 | 258 | # # Start with an empty AVL tree for left-right right_rotation 259 | # data = [1, 4, 8, 12, 16, 20, 25, 30, 35, 28] 260 | # data = [20, 10, 40, 30, 50, 55] 261 | # print('Inserting: {}'.format(data)) 262 | # avl_tree = AVLTree(data) 263 | # print('items in level-order: {}'.format(avl_tree.items_level_order())) 264 | 265 | -------------------------------------------------------------------------------- /AVLTrees/test_avl_tree.py: -------------------------------------------------------------------------------- 1 | 2 | # from solution_avl_tree import AVLTree, Node 3 | from starter_avl_tree import AVLTree, Node 4 | import unittest 5 | 6 | class NodeTest(unittest.TestCase): 7 | 8 | def test_init(self): 9 | data = 'a' 10 | n = Node(data) 11 | assert n.data == 'a' 12 | assert n.left_child is None 13 | assert n.right_child is None 14 | 15 | class AVLTreeTest(unittest.TestCase): 16 | 17 | def test_init(self): 18 | avl_tree = AVLTree() 19 | assert avl_tree.root is None 20 | 21 | def test_init_with_iterable(self): 22 | data = [1, 2] 23 | avl_tree = AVLTree(data) 24 | assert avl_tree.root.data == 1 25 | assert avl_tree.root.right_child.data == 2 26 | 27 | def test_node_balance_factor(self): 28 | data = [1, 2] 29 | avl_tree = AVLTree(data) 30 | assert avl_tree.root.balance_factor() == -1 31 | data = [2, 1] 32 | avl_tree = AVLTree(data) 33 | assert avl_tree.root.balance_factor() == 1 34 | 35 | def test_node_update_height(self): 36 | data = [1, 2] 37 | avl_tree = AVLTree(data) 38 | assert avl_tree.root.data == 1 39 | assert avl_tree.root.height == 1 40 | assert avl_tree.root.left_child == None 41 | assert avl_tree.root.right_child.height == 0 42 | avl_tree.insert(3) 43 | assert avl_tree.root.data == 2 44 | assert avl_tree.root.height == 1 45 | assert avl_tree.root.left_child.data == 1 46 | assert avl_tree.root.left_child.height == 0 47 | assert avl_tree.root.right_child.data == 3 48 | assert avl_tree.root.right_child.height == 0 49 | 50 | def test_tree_level_order_traversal(self): 51 | data = [20, 10, 40, 30, 50] 52 | avl_tree = AVLTree(data) 53 | assert avl_tree.items_level_order() == [20, 10, 40, 30, 50] 54 | 55 | def test_single_left_rotation_1(self): 56 | data = [1, 2, 3] 57 | avl_tree = AVLTree(data) 58 | assert avl_tree.root.data == 2 59 | assert avl_tree.root.left_child.data == 1 60 | assert avl_tree.root.right_child.data == 3 61 | assert avl_tree.items_level_order() == [2, 1, 3] 62 | 63 | def test_single_left_rotation_2(self): 64 | data = [20, 10, 40, 30, 50, 55] 65 | avl_tree = AVLTree(data) 66 | assert avl_tree.root.data == 40 67 | assert avl_tree.items_level_order() == [40, 20, 50, 10, 30, 55] 68 | 69 | def test_single_right_rotation_1(self): 70 | data = [3, 2, 1] 71 | avl_tree = AVLTree(data) 72 | assert avl_tree.root.data == 2 73 | assert avl_tree.root.left_child.data == 1 74 | assert avl_tree.root.right_child.data == 3 75 | assert avl_tree.items_level_order() == [2, 1, 3] 76 | 77 | def test_single_right_rotation_2(self): 78 | data = [40, 50, 30, 10, 5] 79 | avl_tree = AVLTree(data) 80 | assert avl_tree.root.data == 40 81 | assert avl_tree.items_level_order() == [40, 10, 50, 5, 30] 82 | 83 | def test_left_right_rotation_1(self): 84 | data = [8, 1, 4] 85 | avl_tree = AVLTree(data) 86 | assert avl_tree.root.data == 4 87 | assert avl_tree.items_level_order() == [4, 1, 8] 88 | 89 | def test_left_right_rotation_2(self): 90 | data = [1, 4, 8, 12, 16, 20, 25, 30, 35, 28] 91 | avl_tree = AVLTree(data) 92 | assert avl_tree.root.data == 12 93 | assert avl_tree.items_level_order() == [12, 4, 25, 1, 8, 20, 30, 16, 28, 35] 94 | 95 | def test_right_left_rotation_1(self): 96 | data = [1, 8, 4] 97 | avl_tree = AVLTree(data) 98 | assert avl_tree.root.data == 4 99 | assert avl_tree.items_level_order() == [4, 1, 8] 100 | 101 | def test_right_left_rotation_2(self): 102 | data = [20, 10, 40, 30, 50, 35] 103 | avl_tree = AVLTree(data) 104 | assert avl_tree.root.data == 30 105 | assert avl_tree.items_level_order() == [30, 20, 40, 10, 35, 50] 106 | -------------------------------------------------------------------------------- /Binary-Search/iterativeBinarySearch.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | array = [0, 3, 4, 5, 6, 15, 18, 22, 25, 27, 31, 33, 34, 35, 37, 42, 53, 60] 4 | 5 | def binarySearch(array, number): 6 | lowerBound = 0 7 | upperBound = len(array) 8 | 9 | while lowerBound < upperBound: 10 | middleIndex = int(math.floor(lowerBound + (upperBound - lowerBound) / 2)) 11 | if array[middleIndex] == number: 12 | return True 13 | elif array[middleIndex] < number: 14 | lowerBound += 1 15 | elif array[middleIndex] > number: 16 | upperBound = middleIndex 17 | return False 18 | 19 | # _bool = binarySearch(array, 22) 20 | # print _bool -------------------------------------------------------------------------------- /Binary-Search/recursiveBinarySearch.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | array = [0, 3, 4, 5, 6, 15, 18, 22, 25, 27, 31, 33, 34, 35, 37, 42, 53, 60] 4 | 5 | def binarySearch(array, number): 6 | middleIndexOfArray = int(math.floor(len(array) / 2)) 7 | if middleIndexOfArray == 0: 8 | return False 9 | 10 | if array[middleIndexOfArray] == number: 11 | return True 12 | elif array[middleIndexOfArray] > number: 13 | return binarySearch(array[:middleIndexOfArray], number) 14 | elif array[middleIndexOfArray] < number: 15 | return binarySearch(array[middleIndexOfArray:], number) 16 | 17 | # _bool = binarySearch(array, 47) 18 | # print _bool -------------------------------------------------------------------------------- /Linked-Lists/doublylinkedlist.py: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | from __future__ import print_function 4 | 5 | 6 | class Node(object): 7 | 8 | def __init__(self, data): 9 | """Initialize this node with the given data""" 10 | self.data = data 11 | self.previous = None 12 | self.next = None 13 | 14 | def __repr__(self): 15 | """Return a string representation of this node""" 16 | return 'Node({})'.format(repr(self.data)) 17 | 18 | 19 | class DoublyLinkedList(object): 20 | 21 | def __init__(self, iterable=None): 22 | """Initialize this linked list; append the given items, if any""" 23 | self.head = None 24 | self.tail = None 25 | if iterable: 26 | for item in iterable: 27 | self.append(item) 28 | 29 | def __repr__(self): 30 | """Return a string representation of this linked list""" 31 | return 'DoublyLinkedList({})'.format(self.as_list()) 32 | 33 | def as_list(self): 34 | """Return a list of all items in this linked list""" 35 | result = [] 36 | current = self.head 37 | 38 | while current is not None: 39 | result.append(current.data) 40 | current = current.next 41 | return result 42 | 43 | def is_empty(self): 44 | """Return True if this linked list is empty, or False""" 45 | return self.head is None 46 | 47 | def length(self): 48 | """Return the length of this linked list by traversing its nodes""" 49 | count = 0 50 | current = self.head 51 | while current is not None: 52 | count += 1 53 | current = current.next 54 | return count 55 | 56 | def append(self, item): 57 | """Insert the given item at the tail of this linked list""" 58 | node = Node(item) 59 | if self.tail is not None: 60 | currentTailNode = self.tail 61 | currentTailNode.next = node 62 | self.tail = node 63 | self.tail.previous = currentTailNode 64 | else: 65 | self.head = node 66 | self.tail = node 67 | self.head.previous = None 68 | self.head.next = self.tail 69 | self.tail.previous = self.head 70 | self.tail.next = None 71 | 72 | def prepend(self, item): 73 | """Insert the given item at the head of this linked list""" 74 | # TODO: prepend given item 75 | node = Node(item) 76 | if self.head is not None: 77 | currentHeadNode = self.head 78 | currentHeadNode.previous = node 79 | node.next = currentHeadNode 80 | self.head = node 81 | 82 | else: 83 | self.head = node 84 | self.tail = node 85 | self.head.next = self.tail 86 | self.tail.previous = self.head 87 | 88 | def delete(self, item): 89 | """Delete the given item from this linked list, or raise ValueError""" 90 | current = self.head 91 | try: 92 | if current.data == item: 93 | if current.data == self.tail.data: 94 | self.head = None 95 | self.tail = None 96 | return 97 | else: 98 | self.head = current.next 99 | return 100 | 101 | while current is not None: 102 | if current.data == item: 103 | #remove item 104 | if current == self.tail: 105 | self.tail = current.previous 106 | current.previous.next = None 107 | else: 108 | current.previous.next = current.next 109 | current.next.previous = current.previous 110 | return 111 | else: 112 | current = current.next 113 | except AttributeError: 114 | raise ValueError 115 | 116 | def find(self, quality): 117 | """Return an item from this linked list satisfying the given quality""" 118 | # TODO: find item where quality(item) is True 119 | current = self.head 120 | 121 | try: 122 | while current.data is not None: 123 | if quality(current.data) is True: 124 | return current.data 125 | else: 126 | current = current.next 127 | except AttributeError: 128 | return None 129 | 130 | 131 | 132 | def test_doubly_linked_list(): 133 | ll = DoublyLinkedList() 134 | print(ll) 135 | ll.append('A') 136 | print(ll) 137 | ll.append('B') 138 | print(ll) 139 | ll.append('C') 140 | print(ll) 141 | print('head: ' + str(ll.head)) 142 | print('tail: ' + str(ll.tail)) 143 | print(ll.length()) 144 | 145 | ll.delete('A') 146 | print(ll) 147 | ll.delete('C') 148 | print(ll) 149 | ll.delete('B') 150 | print(ll) 151 | print('head: ' + str(ll.head)) 152 | print('tail: ' + str(ll.tail)) 153 | print(ll.length()) 154 | 155 | 156 | if __name__ == '__main__': 157 | test_doubly_linked_list() 158 | -------------------------------------------------------------------------------- /Linked-Lists/linkedlist.py: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | from __future__ import print_function 4 | 5 | 6 | class Node(object): 7 | 8 | def __init__(self, data): 9 | """Initialize this node with the given data""" 10 | self.data = data 11 | self.next = None 12 | 13 | def __repr__(self): 14 | """Return a string representation of this node""" 15 | return 'Node({})'.format(repr(self.data)) 16 | 17 | 18 | class LinkedList(object): 19 | 20 | def __init__(self, iterable=None): 21 | """Initialize this linked list; append the given items, if any""" 22 | self.head = None 23 | self.tail = None 24 | if iterable: 25 | for item in iterable: 26 | self.append(item) 27 | 28 | def __repr__(self): 29 | """Return a string representation of this linked list""" 30 | return 'LinkedList({})'.format(self.as_list()) 31 | 32 | def as_list(self): 33 | """Return a list of all items in this linked list""" 34 | result = [] 35 | current = self.head 36 | while current is not None: 37 | result.append(current.data) 38 | # result.append(current) 39 | current = current.next 40 | return result 41 | 42 | def is_empty(self): 43 | """Return True if this linked list is empty, or False""" 44 | return self.head is None 45 | 46 | def length(self): 47 | """Return the length of this linked list by traversing its nodes""" 48 | count = 0 49 | current = self.head 50 | while current is not None: 51 | count += 1 52 | current = current.next 53 | return count 54 | 55 | def append(self, item): 56 | """Insert the given item at the tail of this linked list""" 57 | node = Node(item) 58 | if self.tail is not None: 59 | currentTailNode = self.tail 60 | currentTailNode.next = node 61 | self.tail = node 62 | else: 63 | self.head = node 64 | self.tail = node 65 | 66 | def prepend(self, item): 67 | """Insert the given item at the head of this linked list""" 68 | # TODO: prepend given item 69 | node = Node(item) 70 | if self.head is not None: 71 | currentHeadNode = self.head 72 | node.next = currentHeadNode 73 | self.head = node 74 | else: 75 | self.head = node 76 | self.tail = node 77 | 78 | def delete(self, item): 79 | """Delete the given item from this linked list, or raise ValueError""" 80 | current = self.head 81 | try: 82 | if current.data == item: 83 | if current.data == self.tail.data: 84 | self.head = None 85 | self.tail = None 86 | return 87 | else: 88 | self.head = current.next 89 | return None 90 | 91 | while current.next is not None: 92 | if current.next.data == item: 93 | #remove item 94 | if current.next == self.tail: 95 | self.tail = current 96 | current.next = None 97 | else: 98 | current.next = current.next.next 99 | 100 | return 101 | else: 102 | current = current.next 103 | except AttributeError: 104 | raise ValueError 105 | 106 | def find(self, quality): 107 | """Return an item from this linked list satisfying the given quality""" 108 | # TODO: find item where quality(item) is True 109 | current = self.head 110 | 111 | try: 112 | while current.data is not None: 113 | if quality(current.data) is True: 114 | return current.data 115 | else: 116 | current = current.next 117 | except AttributeError: 118 | return None 119 | 120 | 121 | 122 | def test_linked_list(): 123 | ll = LinkedList() 124 | print(ll) 125 | ll.append('A') 126 | print(ll) 127 | ll.append('B') 128 | print(ll) 129 | ll.append('C') 130 | print(ll) 131 | print('head: ' + str(ll.head)) 132 | print('tail: ' + str(ll.tail)) 133 | print(ll.length()) 134 | 135 | ll.delete('A') 136 | print(ll) 137 | ll.delete('C') 138 | print(ll) 139 | ll.delete('B') 140 | print(ll) 141 | print('head: ' + str(ll.head)) 142 | print('tail: ' + str(ll.tail)) 143 | print(ll.length()) 144 | 145 | 146 | if __name__ == '__main__': 147 | test_linked_list() 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms and Data Structures 2 | 3 | Table of Contents 4 | 5 | ## Motivation 6 | 7 | ## Usage 8 | 9 | ## Getting Started 10 | 11 | ## How to Contribute 12 | -------------------------------------------------------------------------------- /Trie/trie.py: -------------------------------------------------------------------------------- 1 | endOfWord = "$" 2 | 3 | def generateTrieFromWordsArray(words): 4 | root = {} 5 | for word in words: 6 | currentDict = root 7 | for letter in word: 8 | currentDict = currentDict.setdefault(letter, {}) 9 | currentDict[endOfWord] = endOfWord 10 | return root 11 | 12 | def isWordPresentInTrie(trie, word): 13 | currentDict = trie 14 | for letter in word: 15 | if letter in currentDict: 16 | currentDict = currentDict[letter] 17 | else: 18 | return False 19 | if endOfWord in currentDict: 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | arrayOfWords = ['hello', 'hey', 'what', 'when', 'why'] 26 | wordsTrie = generateTrieFromWordsArray(arrayOfWords) 27 | print wordsTrie 28 | print isWordPresentInTrie(wordsTrie, 'hello') 29 | print isWordPresentInTrie(wordsTrie, 'hellow') 30 | --------------------------------------------------------------------------------