├── BST_Validator └── main.py ├── README.md ├── Linked_List └── main.py ├── Binary_Search_Tree └── main.py └── AVL_Tree └── main.py /BST_Validator/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class Node: 4 | def __init__(self,value=None): 5 | self.value=value 6 | self.left_child=None 7 | self.right_child=None 8 | 9 | def validate_bst(root,min=-sys.maxint,max=sys.maxint): 10 | if root==None: 11 | return True 12 | if (root.value>min and 13 | root.value=self.length() or index<0: # added 'index<0' post-video 40 | print "ERROR: 'Get' Index out of range!" 41 | return None 42 | cur_idx=0 43 | cur_node=self.head 44 | while True: 45 | cur_node=cur_node.next 46 | if cur_idx==index: return cur_node.data 47 | cur_idx+=1 48 | 49 | # Deletes the node at index 'index'. 50 | def erase(self,index): 51 | if index>=self.length() or index<0: # added 'index<0' post-video 52 | print "ERROR: 'Erase' Index out of range!" 53 | return 54 | cur_idx=0 55 | cur_node=self.head 56 | while True: 57 | last_node=cur_node 58 | cur_node=cur_node.next 59 | if cur_idx==index: 60 | last_node.next=cur_node.next 61 | return 62 | cur_idx+=1 63 | 64 | # Allows for bracket operator syntax (i.e. a[0] to return first item). 65 | def __getitem__(self,index): 66 | return self.get(index) 67 | 68 | 69 | ####################################################### 70 | # Functions added after video tutorial 71 | 72 | # Inserts a new node at index 'index' containing data 'data'. 73 | # Indices begin at 0. If the provided index is greater than or 74 | # equal to the length of the linked list the 'data' will be appended. 75 | def insert(self,index,data): 76 | if index>=self.length() or index<0: 77 | return self.append(data) 78 | cur_node=self.head 79 | prior_node=self.head 80 | cur_idx=0 81 | while True: 82 | cur_node=cur_node.next 83 | if cur_idx==index: 84 | new_node=node(data) 85 | prior_node.next=new_node 86 | new_node.next=cur_node 87 | return 88 | prior_node=cur_node 89 | cur_idx+=1 90 | 91 | # Inserts the node 'node' at index 'index'. Indices begin at 0. 92 | # If the 'index' is greater than or equal to the length of the linked 93 | # list the 'node' will be appended. 94 | def insert_node(self,index,node): 95 | if index<0: 96 | print "ERROR: 'Erase' Index cannot be negative!" 97 | return 98 | if index>=self.length(): # append the node 99 | cur_node=self.head 100 | while cur_node.next!=None: 101 | cur_node=cur_node.next 102 | cur_node.next=node 103 | return 104 | cur_node=self.head 105 | prior_node=self.head 106 | cur_idx=0 107 | while True: 108 | cur_node=cur_node.next 109 | if cur_idx==index: 110 | prior_node.next=node 111 | return 112 | prior_node=cur_node 113 | cur_idx+=1 114 | 115 | # Sets the data at index 'index' equal to 'data'. 116 | # Indices begin at 0. If the 'index' is greater than or equal 117 | # to the length of the linked list a warning will be printed 118 | # to the user. 119 | def set(self,index,data): 120 | if index>=self.length() or index<0: 121 | print "ERROR: 'Set' Index out of range!" 122 | return 123 | cur_node=self.head 124 | cur_idx=0 125 | while True: 126 | cur_node=cur_node.next 127 | if cur_idx==index: 128 | cur_node.data=data 129 | return 130 | cur_idx+=1 -------------------------------------------------------------------------------- /Binary_Search_Tree/main.py: -------------------------------------------------------------------------------- 1 | class node: 2 | def __init__(self,value=None): 3 | self.value=value 4 | self.left_child=None 5 | self.right_child=None 6 | self.parent=None # pointer to parent node in tree 7 | 8 | class binary_search_tree: 9 | def __init__(self): 10 | self.root=None 11 | 12 | def insert(self,value): 13 | if self.root==None: 14 | self.root=node(value) 15 | else: 16 | self._insert(value,self.root) 17 | 18 | def _insert(self,value,cur_node): 19 | if valuecur_node.value: 26 | if cur_node.right_child==None: 27 | cur_node.right_child=node(value) 28 | cur_node.right_child.parent=cur_node # set parent 29 | else: 30 | self._insert(value,cur_node.right_child) 31 | else: 32 | print "Value already in tree!" 33 | 34 | def print_tree(self): 35 | if self.root!=None: 36 | self._print_tree(self.root) 37 | 38 | def _print_tree(self,cur_node): 39 | if cur_node!=None: 40 | self._print_tree(cur_node.left_child) 41 | print str(cur_node.value) 42 | self._print_tree(cur_node.right_child) 43 | 44 | def height(self): 45 | if self.root!=None: 46 | return self._height(self.root,0) 47 | else: 48 | return 0 49 | 50 | def _height(self,cur_node,cur_height): 51 | if cur_node==None: return cur_height 52 | left_height=self._height(cur_node.left_child,cur_height+1) 53 | right_height=self._height(cur_node.right_child,cur_height+1) 54 | return max(left_height,right_height) 55 | 56 | def find(self,value): 57 | if self.root!=None: 58 | return self._find(value,self.root) 59 | else: 60 | return None 61 | 62 | def _find(self,value,cur_node): 63 | if value==cur_node.value: 64 | return cur_node 65 | elif valuecur_node.value and cur_node.right_child!=None: 68 | return self._find(value,cur_node.right_child) 69 | 70 | def delete_value(self,value): 71 | return self.delete_node(self.find(value)) 72 | 73 | def delete_node(self,node): 74 | 75 | ## ----- 76 | # Improvements since prior lesson 77 | 78 | # Protect against deleting a node not found in the tree 79 | if node==None or self.find(node.value)==None: 80 | print "Node to be deleted not found in the tree!" 81 | return None 82 | ## ----- 83 | 84 | # returns the node with min value in tree rooted at input node 85 | def min_value_node(n): 86 | current=n 87 | while current.left_child!=None: 88 | current=current.left_child 89 | return current 90 | 91 | # returns the number of children for the specified node 92 | def num_children(n): 93 | num_children=0 94 | if n.left_child!=None: num_children+=1 95 | if n.right_child!=None: num_children+=1 96 | return num_children 97 | 98 | # get the parent of the node to be deleted 99 | node_parent=node.parent 100 | 101 | # get the number of children of the node to be deleted 102 | node_children=num_children(node) 103 | 104 | # break operation into different cases based on the 105 | # structure of the tree & node to be deleted 106 | 107 | # CASE 1 (node has no children) 108 | if node_children==0: 109 | 110 | # Added this if statement post-video, previously if you 111 | # deleted the root node it would delete entire tree. 112 | if node_parent!=None: 113 | # remove reference to the node from the parent 114 | if node_parent.left_child==node: 115 | node_parent.left_child=None 116 | else: 117 | node_parent.right_child=None 118 | else: 119 | self.root=None 120 | 121 | # CASE 2 (node has a single child) 122 | if node_children==1: 123 | 124 | # get the single child node 125 | if node.left_child!=None: 126 | child=node.left_child 127 | else: 128 | child=node.right_child 129 | 130 | # Added this if statement post-video, previously if you 131 | # deleted the root node it would delete entire tree. 132 | if node_parent!=None: 133 | # replace the node to be deleted with its child 134 | if node_parent.left_child==node: 135 | node_parent.left_child=child 136 | else: 137 | node_parent.right_child=child 138 | else: 139 | self.root=child 140 | 141 | # correct the parent pointer in node 142 | child.parent=node_parent 143 | 144 | # CASE 3 (node has two children) 145 | if node_children==2: 146 | 147 | # get the inorder successor of the deleted node 148 | successor=min_value_node(node.right_child) 149 | 150 | # copy the inorder successor's value to the node formerly 151 | # holding the value we wished to delete 152 | node.value=successor.value 153 | 154 | # delete the inorder successor now that it's value was 155 | # copied into the other node 156 | self.delete_node(successor) 157 | 158 | def search(self,value): 159 | if self.root!=None: 160 | return self._search(value,self.root) 161 | else: 162 | return False 163 | 164 | def _search(self,value,cur_node): 165 | if value==cur_node.value: 166 | return True 167 | elif valuecur_node.value and cur_node.right_child!=None: 170 | return self._search(value,cur_node.right_child) 171 | return False -------------------------------------------------------------------------------- /AVL_Tree/main.py: -------------------------------------------------------------------------------- 1 | class node: 2 | def __init__(self,value=None): 3 | self.value=value 4 | self.left_child=None 5 | self.right_child=None 6 | self.parent=None # pointer to parent node in tree 7 | self.height=1 # height of node in tree (max dist. to leaf) NEW FOR AVL 8 | 9 | class AVLTree: 10 | def __init__(self): 11 | self.root=None 12 | 13 | def __repr__(self): 14 | if self.root==None: return '' 15 | content='\n' # to hold final string 16 | cur_nodes=[self.root] # all nodes at current level 17 | cur_height=self.root.height # height of nodes at current level 18 | sep=' '*(2**(cur_height-1)) # variable sized separator between elements 19 | while True: 20 | cur_height+=-1 # decrement current height 21 | if len(cur_nodes)==0: break 22 | cur_row=' ' 23 | next_row='' 24 | next_nodes=[] 25 | 26 | if all(n is None for n in cur_nodes): 27 | break 28 | 29 | for n in cur_nodes: 30 | 31 | if n==None: 32 | cur_row+=' '+sep 33 | next_row+=' '+sep 34 | next_nodes.extend([None,None]) 35 | continue 36 | 37 | if n.value!=None: 38 | buf=' '*((5-len(str(n.value)))/2) 39 | cur_row+='%s%s%s'%(buf,str(n.value),buf)+sep 40 | else: 41 | cur_row+=' '*5+sep 42 | 43 | if n.left_child!=None: 44 | next_nodes.append(n.left_child) 45 | next_row+=' /'+sep 46 | else: 47 | next_row+=' '+sep 48 | next_nodes.append(None) 49 | 50 | if n.right_child!=None: 51 | next_nodes.append(n.right_child) 52 | next_row+='\ '+sep 53 | else: 54 | next_row+=' '+sep 55 | next_nodes.append(None) 56 | 57 | content+=(cur_height*' '+cur_row+'\n'+cur_height*' '+next_row+'\n') 58 | cur_nodes=next_nodes 59 | sep=' '*(len(sep)/2) # cut separator size in half 60 | return content 61 | 62 | def insert(self,value): 63 | if self.root==None: 64 | self.root=node(value) 65 | else: 66 | self._insert(value,self.root) 67 | 68 | def _insert(self,value,cur_node): 69 | if valuecur_node.value: 77 | if cur_node.right_child==None: 78 | cur_node.right_child=node(value) 79 | cur_node.right_child.parent=cur_node # set parent 80 | self._inspect_insertion(cur_node.right_child) 81 | else: 82 | self._insert(value,cur_node.right_child) 83 | else: 84 | print "Value already in tree!" 85 | 86 | def print_tree(self): 87 | if self.root!=None: 88 | self._print_tree(self.root) 89 | 90 | def _print_tree(self,cur_node): 91 | if cur_node!=None: 92 | self._print_tree(cur_node.left_child) 93 | print '%s, h=%d'%(str(cur_node.value),cur_node.height) 94 | self._print_tree(cur_node.right_child) 95 | 96 | def height(self): 97 | if self.root!=None: 98 | return self._height(self.root,0) 99 | else: 100 | return 0 101 | 102 | def _height(self,cur_node,cur_height): 103 | if cur_node==None: return cur_height 104 | left_height=self._height(cur_node.left_child,cur_height+1) 105 | right_height=self._height(cur_node.right_child,cur_height+1) 106 | return max(left_height,right_height) 107 | 108 | def find(self,value): 109 | if self.root!=None: 110 | return self._find(value,self.root) 111 | else: 112 | return None 113 | 114 | def _find(self,value,cur_node): 115 | if value==cur_node.value: 116 | return cur_node 117 | elif valuecur_node.value and cur_node.right_child!=None: 120 | return self._find(value,cur_node.right_child) 121 | 122 | def delete_value(self,value): 123 | return self.delete_node(self.find(value)) 124 | 125 | def delete_node(self,node): 126 | 127 | ## ----- 128 | # Improvements since prior lesson 129 | 130 | # Protect against deleting a node not found in the tree 131 | if node==None or self.find(node.value)==None: 132 | print "Node to be deleted not found in the tree!" 133 | return None 134 | ## ----- 135 | 136 | # returns the node with min value in tree rooted at input node 137 | def min_value_node(n): 138 | current=n 139 | while current.left_child!=None: 140 | current=current.left_child 141 | return current 142 | 143 | # returns the number of children for the specified node 144 | def num_children(n): 145 | num_children=0 146 | if n.left_child!=None: num_children+=1 147 | if n.right_child!=None: num_children+=1 148 | return num_children 149 | 150 | # get the parent of the node to be deleted 151 | node_parent=node.parent 152 | 153 | # get the number of children of the node to be deleted 154 | node_children=num_children(node) 155 | 156 | # break operation into different cases based on the 157 | # structure of the tree & node to be deleted 158 | 159 | # CASE 1 (node has no children) 160 | if node_children==0: 161 | 162 | if node_parent!=None: 163 | # remove reference to the node from the parent 164 | if node_parent.left_child==node: 165 | node_parent.left_child=None 166 | else: 167 | node_parent.right_child=None 168 | else: 169 | self.root=None 170 | 171 | # CASE 2 (node has a single child) 172 | if node_children==1: 173 | 174 | # get the single child node 175 | if node.left_child!=None: 176 | child=node.left_child 177 | else: 178 | child=node.right_child 179 | 180 | if node_parent!=None: 181 | # replace the node to be deleted with its child 182 | if node_parent.left_child==node: 183 | node_parent.left_child=child 184 | else: 185 | node_parent.right_child=child 186 | else: 187 | self.root=child 188 | 189 | # correct the parent pointer in node 190 | child.parent=node_parent 191 | 192 | # CASE 3 (node has two children) 193 | if node_children==2: 194 | 195 | # get the inorder successor of the deleted node 196 | successor=min_value_node(node.right_child) 197 | 198 | # copy the inorder successor's value to the node formerly 199 | # holding the value we wished to delete 200 | node.value=successor.value 201 | 202 | # delete the inorder successor now that it's value was 203 | # copied into the other node 204 | self.delete_node(successor) 205 | 206 | # exit function so we don't call the _inspect_deletion twice 207 | return 208 | 209 | if node_parent!=None: 210 | # fix the height of the parent of current node 211 | node_parent.height=1+max(self.get_height(node_parent.left_child),self.get_height(node_parent.right_child)) 212 | 213 | # begin to traverse back up the tree checking if there are 214 | # any sections which now invalidate the AVL balance rules 215 | self._inspect_deletion(node_parent) 216 | 217 | def search(self,value): 218 | if self.root!=None: 219 | return self._search(value,self.root) 220 | else: 221 | return False 222 | 223 | def _search(self,value,cur_node): 224 | if value==cur_node.value: 225 | return True 226 | elif valuecur_node.value and cur_node.right_child!=None: 229 | return self._search(value,cur_node.right_child) 230 | return False 231 | 232 | 233 | # Functions added for AVL... 234 | 235 | def _inspect_insertion(self,cur_node,path=[]): 236 | if cur_node.parent==None: return 237 | path=[cur_node]+path 238 | 239 | left_height =self.get_height(cur_node.parent.left_child) 240 | right_height=self.get_height(cur_node.parent.right_child) 241 | 242 | if abs(left_height-right_height)>1: 243 | path=[cur_node.parent]+path 244 | self._rebalance_node(path[0],path[1],path[2]) 245 | return 246 | 247 | new_height=1+cur_node.height 248 | if new_height>cur_node.parent.height: 249 | cur_node.parent.height=new_height 250 | 251 | self._inspect_insertion(cur_node.parent,path) 252 | 253 | def _inspect_deletion(self,cur_node): 254 | if cur_node==None: return 255 | 256 | left_height =self.get_height(cur_node.left_child) 257 | right_height=self.get_height(cur_node.right_child) 258 | 259 | if abs(left_height-right_height)>1: 260 | y=self.taller_child(cur_node) 261 | x=self.taller_child(y) 262 | self._rebalance_node(cur_node,y,x) 263 | 264 | self._inspect_deletion(cur_node.parent) 265 | 266 | def _rebalance_node(self,z,y,x): 267 | if y==z.left_child and x==y.left_child: 268 | self._right_rotate(z) 269 | elif y==z.left_child and x==y.right_child: 270 | self._left_rotate(y) 271 | self._right_rotate(z) 272 | elif y==z.right_child and x==y.right_child: 273 | self._left_rotate(z) 274 | elif y==z.right_child and x==y.left_child: 275 | self._right_rotate(y) 276 | self._left_rotate(z) 277 | else: 278 | raise Exception('_rebalance_node: z,y,x node configuration not recognized!') 279 | 280 | def _right_rotate(self,z): 281 | sub_root=z.parent 282 | y=z.left_child 283 | t3=y.right_child 284 | y.right_child=z 285 | z.parent=y 286 | z.left_child=t3 287 | if t3!=None: t3.parent=z 288 | y.parent=sub_root 289 | if y.parent==None: 290 | self.root=y 291 | else: 292 | if y.parent.left_child==z: 293 | y.parent.left_child=y 294 | else: 295 | y.parent.right_child=y 296 | z.height=1+max(self.get_height(z.left_child), 297 | self.get_height(z.right_child)) 298 | y.height=1+max(self.get_height(y.left_child), 299 | self.get_height(y.right_child)) 300 | 301 | def _left_rotate(self,z): 302 | sub_root=z.parent 303 | y=z.right_child 304 | t2=y.left_child 305 | y.left_child=z 306 | z.parent=y 307 | z.right_child=t2 308 | if t2!=None: t2.parent=z 309 | y.parent=sub_root 310 | if y.parent==None: 311 | self.root=y 312 | else: 313 | if y.parent.left_child==z: 314 | y.parent.left_child=y 315 | else: 316 | y.parent.right_child=y 317 | z.height=1+max(self.get_height(z.left_child), 318 | self.get_height(z.right_child)) 319 | y.height=1+max(self.get_height(y.left_child), 320 | self.get_height(y.right_child)) 321 | 322 | def get_height(self,cur_node): 323 | if cur_node==None: return 0 324 | return cur_node.height 325 | 326 | def taller_child(self,cur_node): 327 | left=self.get_height(cur_node.left_child) 328 | right=self.get_height(cur_node.right_child) 329 | return cur_node.left_child if left>=right else cur_node.right_child 330 | 331 | --------------------------------------------------------------------------------