├── LICENSE ├── README.md ├── Section_1 ├── List Comprehensions.ipynb ├── Python Data Structures.ipynb └── Python_native-data-structures.pdf ├── Section_2 ├── MaxHeap.pdf ├── Stacks and Queues.pdf └── Stacks, Queues & Heaps.ipynb ├── Section_3 ├── Python Linked Lists.ipynb └── Python Linked Lists.pdf ├── Section_4 ├── Binary Search Tree.ipynb └── Binary Search Trees.pdf └── Section_5 ├── Graph Implementation Using Adjacency Lists.ipynb ├── Graph Implementation Using Adjacency Matrix.ipynb ├── Graphs.pdf ├── graph_adjacency-list.py └── graph_adjacency-matrix.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Joe James 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Data Structures 2 | ### Udemy Course 3 | This repository holds all the supporting files for my Python Data Structures A to Z course, including all the presentations in PDF format, and all the code in Jupyter Notebooks. These resources are available under the MIT license. 4 | 5 | This course covers the following topics: 6 | **Section 1:** Intro, Python native data structures, String, List, Tuple, Set, Dictionary. 7 | **Section 2:** Stacks, Queues and Heaps. 8 | **Section 3:** Linked Lists, Circular Linked Lists, Doubly Linked Lists. 9 | **Section 4:** Binary Search Trees. 10 | **Section 5:** Graphs. 11 | 12 | Each section (2-5) explains how the data structure works, key methods, use cases, and walks through how to implement it in Python 3 code. 13 | -------------------------------------------------------------------------------- /Section_1/List Comprehensions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Python List Comprehensions\n", 8 | "basic format: new_list = [transform sequence [filter] ] \n", 9 | "© Joe James, 2019." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import random" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "**get values within a range**" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "name": "stdout", 35 | "output_type": "stream", 36 | "text": [ 37 | "under_10: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" 38 | ] 39 | } 40 | ], 41 | "source": [ 42 | "under_10 = [x for x in range(10)]\n", 43 | "print('under_10: ' + str(under_10))" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "**get squared values**" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 3, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "squares: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "squares = [x**2 for x in under_10]\n", 68 | "print('squares: ' + str(squares))" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "**get odd numbers using mod**" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 4, 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [ 87 | "odds: [1, 3, 5, 7, 9]\n" 88 | ] 89 | } 90 | ], 91 | "source": [ 92 | "odds = [x for x in range(10) if x%2 == 1]\n", 93 | "print('odds: ' + str(odds))" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "**get multiples of 10**" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 5, 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "name": "stdout", 110 | "output_type": "stream", 111 | "text": [ 112 | "ten_x: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]\n" 113 | ] 114 | } 115 | ], 116 | "source": [ 117 | "ten_x = [x * 10 for x in range(10)]\n", 118 | "print('ten_x: ' + str(ten_x))" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "**get all numbers from a string**" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 6, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "name": "stdout", 135 | "output_type": "stream", 136 | "text": [ 137 | "nums: 2073\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "s = 'I love 2 go t0 the store 7 times a w3ek.'\n", 143 | "nums = [x for x in s if x.isnumeric()]\n", 144 | "print('nums: ' + ''.join(nums))" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "**get index of a list item**" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 7, 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "name": "stdout", 161 | "output_type": "stream", 162 | "text": [ 163 | "index = 2\n" 164 | ] 165 | } 166 | ], 167 | "source": [ 168 | "names = ['Cosmo', 'Pedro', 'Anu', 'Ray']\n", 169 | "idx = [k for k, v in enumerate(names) if v == 'Anu']\n", 170 | "print('index = ' + str(idx[0]))" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "**delete an item from a list**" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 8, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "['D', 'F', 'E', 'A', 'B', 'C'] ['D', 'F', 'E', 'A', 'B']\n" 190 | ] 191 | } 192 | ], 193 | "source": [ 194 | "letters = [x for x in 'ABCDEF']\n", 195 | "random.shuffle(letters)\n", 196 | "letrs = [a for a in letters if a != 'C']\n", 197 | "print(letters, letrs)" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "**if-else condition in a comprehension** \n", 205 | "must come before iteration." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 9, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "name": "stdout", 215 | "output_type": "stream", 216 | "text": [ 217 | "new list: [50, 30, 10, 18, 6, 70]\n" 218 | ] 219 | } 220 | ], 221 | "source": [ 222 | "nums = [5, 3, 10, 18, 6, 7]\n", 223 | "new_list = [x if x%2 == 0 else 10*x for x in nums]\n", 224 | "print('new list: ' + str(new_list))" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": {}, 230 | "source": [ 231 | "**nested loop iteration for 2D list** \n", 232 | "b is the subsets, x is the values." 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 10, 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "name": "stdout", 242 | "output_type": "stream", 243 | "text": [ 244 | "[1, 2, 3, 4]\n" 245 | ] 246 | } 247 | ], 248 | "source": [ 249 | "a = [[1,2],[3,4]]\n", 250 | "new_list = [x for b in a for x in b]\n", 251 | "print(new_list)" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": null, 257 | "metadata": {}, 258 | "outputs": [], 259 | "source": [] 260 | } 261 | ], 262 | "metadata": { 263 | "kernelspec": { 264 | "display_name": "Python 3", 265 | "language": "python", 266 | "name": "python3" 267 | }, 268 | "language_info": { 269 | "codemirror_mode": { 270 | "name": "ipython", 271 | "version": 3 272 | }, 273 | "file_extension": ".py", 274 | "mimetype": "text/x-python", 275 | "name": "python", 276 | "nbconvert_exporter": "python", 277 | "pygments_lexer": "ipython3", 278 | "version": "3.7.0" 279 | } 280 | }, 281 | "nbformat": 4, 282 | "nbformat_minor": 2 283 | } 284 | -------------------------------------------------------------------------------- /Section_1/Python Data Structures.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Intro to Python Data Structures\n", 8 | "Strings, Lists, Tuples, Sets, Dicts \n", 9 | "Created in Python 3.7 \n", 10 | "© Joe James, 2019.\n", 11 | "\n", 12 | "## Sequences: String, List, Tuple\n", 13 | "****\n", 14 | "[Documentation](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range) \n", 15 | "**indexing** - access any item in the sequence using its index. \n", 16 | "Indexing starts with 0 for the first element." 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "g\n", 29 | "cow\n", 30 | "Kevin\n" 31 | ] 32 | } 33 | ], 34 | "source": [ 35 | "# string\n", 36 | "x = 'frog'\n", 37 | "print (x[3])\n", 38 | "\n", 39 | "# list\n", 40 | "x = ['pig', 'cow', 'horse']\n", 41 | "print (x[1])\n", 42 | "\n", 43 | "# tuple\n", 44 | "x = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 45 | "print(x[0])" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "**slicing** - slice out substrings, sublists, subtuples using indexes. \n", 53 | "[start : end+1 : step]" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "name": "stdout", 63 | "output_type": "stream", 64 | "text": [ 65 | "omp\n", 66 | "opt\n", 67 | "puter\n", 68 | "compu\n", 69 | "r\n", 70 | "ter\n", 71 | "comput\n" 72 | ] 73 | } 74 | ], 75 | "source": [ 76 | "x = 'computer'\n", 77 | "print(x[1:4])\n", 78 | "print(x[1:6:2])\n", 79 | "print(x[3:])\n", 80 | "print(x[:5])\n", 81 | "print(x[-1])\n", 82 | "print(x[-3:])\n", 83 | "print(x[:-2])" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "**adding / concatenating** - combine 2 sequences of the same type by using +" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 3, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "horseshoe\n", 103 | "['pig', 'cow', 'horse']\n", 104 | "('Kevin', 'Niklas', 'Jenny', 'Craig')\n" 105 | ] 106 | } 107 | ], 108 | "source": [ 109 | "# string\n", 110 | "x = 'horse' + 'shoe'\n", 111 | "print(x)\n", 112 | "\n", 113 | "# list\n", 114 | "y = ['pig', 'cow'] + ['horse']\n", 115 | "print(y)\n", 116 | "\n", 117 | "# tuple\n", 118 | "z = ('Kevin', 'Niklas', 'Jenny') + ('Craig',)\n", 119 | "print(z)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "**multiplying** - multiply a sequence using *" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 4, 132 | "metadata": {}, 133 | "outputs": [ 134 | { 135 | "name": "stdout", 136 | "output_type": "stream", 137 | "text": [ 138 | "bugbugbug\n", 139 | "[8, 5, 8, 5, 8, 5]\n", 140 | "(2, 4, 2, 4, 2, 4)\n" 141 | ] 142 | } 143 | ], 144 | "source": [ 145 | "# string\n", 146 | "x = 'bug' * 3\n", 147 | "print(x)\n", 148 | "\n", 149 | "# list\n", 150 | "y = [8, 5] * 3\n", 151 | "print(y)\n", 152 | "\n", 153 | "# tuple\n", 154 | "z = (2, 4) * 3\n", 155 | "print(z)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "**checking membership** - test whether an item is or is not in a sequence." 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 5, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "True\n", 175 | "False\n", 176 | "True\n" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "# string\n", 182 | "x = 'bug'\n", 183 | "print('u' in x)\n", 184 | "\n", 185 | "# list\n", 186 | "y = ['pig', 'cow', 'horse']\n", 187 | "print('cow' not in y)\n", 188 | "\n", 189 | "# tuple\n", 190 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 191 | "print('Niklas' in z)" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "**iterating** - iterating through the items in a sequence" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 6, 204 | "metadata": {}, 205 | "outputs": [ 206 | { 207 | "name": "stdout", 208 | "output_type": "stream", 209 | "text": [ 210 | "7\n", 211 | "8\n", 212 | "3\n", 213 | "0 7\n", 214 | "1 8\n", 215 | "2 3\n" 216 | ] 217 | } 218 | ], 219 | "source": [ 220 | "# item\n", 221 | "x = [7, 8, 3]\n", 222 | "for item in x:\n", 223 | " print(item)\n", 224 | " \n", 225 | "# index & item\n", 226 | "y = [7, 8, 3]\n", 227 | "for index, item in enumerate(y):\n", 228 | " print(index, item)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "markdown", 233 | "metadata": {}, 234 | "source": [ 235 | "**number of items** - count the number of items in a sequence" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 7, 241 | "metadata": {}, 242 | "outputs": [ 243 | { 244 | "name": "stdout", 245 | "output_type": "stream", 246 | "text": [ 247 | "3\n", 248 | "3\n", 249 | "4\n" 250 | ] 251 | } 252 | ], 253 | "source": [ 254 | "# string\n", 255 | "x = 'bug'\n", 256 | "print(len(x))\n", 257 | "\n", 258 | "# list\n", 259 | "y = ['pig', 'cow', 'horse']\n", 260 | "print(len(y))\n", 261 | "\n", 262 | "# tuple\n", 263 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 264 | "print(len(z))" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": {}, 270 | "source": [ 271 | "**minimum** - find the minimum item in a sequence lexicographically. \n", 272 | "Alpha or numeric types, but cannot mix types." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 8, 278 | "metadata": {}, 279 | "outputs": [ 280 | { 281 | "name": "stdout", 282 | "output_type": "stream", 283 | "text": [ 284 | "b\n", 285 | "cow\n", 286 | "Craig\n" 287 | ] 288 | } 289 | ], 290 | "source": [ 291 | "# string\n", 292 | "x = 'bug'\n", 293 | "print(min(x))\n", 294 | "\n", 295 | "# list\n", 296 | "y = ['pig', 'cow', 'horse']\n", 297 | "print(min(y))\n", 298 | "\n", 299 | "# tuple\n", 300 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 301 | "print(min(z))" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": {}, 307 | "source": [ 308 | "**maximum** - find the maximum item in a sequence lexicographically. \n", 309 | "Alpha or numeric types, but cannot mix types." 310 | ] 311 | }, 312 | { 313 | "cell_type": "code", 314 | "execution_count": 9, 315 | "metadata": {}, 316 | "outputs": [ 317 | { 318 | "name": "stdout", 319 | "output_type": "stream", 320 | "text": [ 321 | "u\n", 322 | "pig\n", 323 | "Niklas\n" 324 | ] 325 | } 326 | ], 327 | "source": [ 328 | "# string\n", 329 | "x = 'bug'\n", 330 | "print(max(x))\n", 331 | "\n", 332 | "# list\n", 333 | "y = ['pig', 'cow', 'horse']\n", 334 | "print(max(y))\n", 335 | "\n", 336 | "# tuple\n", 337 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 338 | "print(max(z))" 339 | ] 340 | }, 341 | { 342 | "cell_type": "markdown", 343 | "metadata": {}, 344 | "source": [ 345 | "**sum** - find the sum of items in a sequence. \n", 346 | "Entire sequence must be numeric." 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": 10, 352 | "metadata": {}, 353 | "outputs": [ 354 | { 355 | "name": "stdout", 356 | "output_type": "stream", 357 | "text": [ 358 | "27\n", 359 | "20\n", 360 | "80\n" 361 | ] 362 | } 363 | ], 364 | "source": [ 365 | "# string -> error\n", 366 | "# x = [5, 7, 'bug']\n", 367 | "# print(sum(x)) # generates an error\n", 368 | "\n", 369 | "# list\n", 370 | "y = [2, 5, 8, 12]\n", 371 | "print(sum(y))\n", 372 | "print(sum(y[-2:]))\n", 373 | "\n", 374 | "# tuple\n", 375 | "z = (50, 4, 7, 19)\n", 376 | "print(sum(z))" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "**sorting** - returns a new list of items in sorted order. \n", 384 | "Does not change the original list." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": 11, 390 | "metadata": {}, 391 | "outputs": [ 392 | { 393 | "name": "stdout", 394 | "output_type": "stream", 395 | "text": [ 396 | "['b', 'g', 'u']\n", 397 | "['cow', 'horse', 'pig']\n", 398 | "['Craig', 'Jenny', 'Kevin', 'Niklas']\n" 399 | ] 400 | } 401 | ], 402 | "source": [ 403 | "# string\n", 404 | "x = 'bug'\n", 405 | "print(sorted(x))\n", 406 | "\n", 407 | "# list\n", 408 | "y = ['pig', 'cow', 'horse']\n", 409 | "print(sorted(y))\n", 410 | "\n", 411 | "# tuple\n", 412 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 413 | "print(sorted(z))" 414 | ] 415 | }, 416 | { 417 | "cell_type": "markdown", 418 | "metadata": {}, 419 | "source": [ 420 | "**sorting** - sort by second letter \n", 421 | "Add a key parameter and a lambda function to return the second character. \n", 422 | "(the word *key* here is a defined parameter name, *k* is an arbitrary variable name)." 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": 12, 428 | "metadata": {}, 429 | "outputs": [ 430 | { 431 | "name": "stdout", 432 | "output_type": "stream", 433 | "text": [ 434 | "['Kevin', 'Jenny', 'Niklas', 'Craig']\n" 435 | ] 436 | } 437 | ], 438 | "source": [ 439 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 440 | "print(sorted(z, key=lambda k: k[1]))" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "metadata": {}, 446 | "source": [ 447 | "**count(item)** - returns count of an item" 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 13, 453 | "metadata": {}, 454 | "outputs": [ 455 | { 456 | "name": "stdout", 457 | "output_type": "stream", 458 | "text": [ 459 | "2\n", 460 | "2\n", 461 | "1\n" 462 | ] 463 | } 464 | ], 465 | "source": [ 466 | "# string\n", 467 | "x = 'hippo'\n", 468 | "print(x.count('p'))\n", 469 | "\n", 470 | "# list\n", 471 | "y = ['pig', 'cow', 'horse', 'cow']\n", 472 | "print(y.count('cow'))\n", 473 | "\n", 474 | "# tuple\n", 475 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 476 | "print(z.count('Kevin'))" 477 | ] 478 | }, 479 | { 480 | "cell_type": "markdown", 481 | "metadata": {}, 482 | "source": [ 483 | "**index(item)** - returns the index of the first occurence of an item." 484 | ] 485 | }, 486 | { 487 | "cell_type": "code", 488 | "execution_count": 14, 489 | "metadata": {}, 490 | "outputs": [ 491 | { 492 | "name": "stdout", 493 | "output_type": "stream", 494 | "text": [ 495 | "2\n", 496 | "1\n", 497 | "2\n" 498 | ] 499 | } 500 | ], 501 | "source": [ 502 | "# string\n", 503 | "x = 'hippo'\n", 504 | "print(x.index('p'))\n", 505 | "\n", 506 | "# list\n", 507 | "y = ['pig', 'cow', 'horse', 'cow']\n", 508 | "print(y.index('cow'))\n", 509 | "\n", 510 | "# tuple\n", 511 | "z = ('Kevin', 'Niklas', 'Jenny', 'Craig')\n", 512 | "print(z.index('Jenny'))" 513 | ] 514 | }, 515 | { 516 | "cell_type": "markdown", 517 | "metadata": {}, 518 | "source": [ 519 | "**unpacking** - unpack the n items of a sequence into n variables" 520 | ] 521 | }, 522 | { 523 | "cell_type": "code", 524 | "execution_count": 15, 525 | "metadata": {}, 526 | "outputs": [ 527 | { 528 | "name": "stdout", 529 | "output_type": "stream", 530 | "text": [ 531 | "pig cow horse\n" 532 | ] 533 | } 534 | ], 535 | "source": [ 536 | "x = ['pig', 'cow', 'horse']\n", 537 | "a, b, c = x\n", 538 | "print(a, b, c)" 539 | ] 540 | }, 541 | { 542 | "cell_type": "markdown", 543 | "metadata": {}, 544 | "source": [ 545 | "## Lists \n", 546 | "****\n", 547 | "- General purpose\n", 548 | "- Most widely used data structure \n", 549 | "- Grow and shrink size as needed\n", 550 | "- Sequence type\n", 551 | "- Sortable \n", 552 | "\n", 553 | "**constructors** - creating a new list" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "execution_count": 16, 559 | "metadata": {}, 560 | "outputs": [ 561 | { 562 | "name": "stdout", 563 | "output_type": "stream", 564 | "text": [ 565 | "[0, 1, 2, 3, 4, 5, 6, 7]\n", 566 | "[25, 36, 49, 64, 81]\n" 567 | ] 568 | } 569 | ], 570 | "source": [ 571 | "x = list()\n", 572 | "y = ['a', 25, 'dog', 8.43]\n", 573 | "tuple1 = (10, 20)\n", 574 | "z = list(tuple1)\n", 575 | "\n", 576 | "# list comprehension\n", 577 | "a = [m for m in range(8)]\n", 578 | "print(a)\n", 579 | "b = [i**2 for i in range(10) if i>4]\n", 580 | "print(b)" 581 | ] 582 | }, 583 | { 584 | "cell_type": "markdown", 585 | "metadata": {}, 586 | "source": [ 587 | "**delete** - delete a list or an item in a list" 588 | ] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "execution_count": 17, 593 | "metadata": {}, 594 | "outputs": [ 595 | { 596 | "name": "stdout", 597 | "output_type": "stream", 598 | "text": [ 599 | "[5, 8, 6]\n" 600 | ] 601 | } 602 | ], 603 | "source": [ 604 | "x = [5, 3, 8, 6]\n", 605 | "del(x[1])\n", 606 | "print(x)\n", 607 | "del(x) # list x no longer exists" 608 | ] 609 | }, 610 | { 611 | "cell_type": "markdown", 612 | "metadata": {}, 613 | "source": [ 614 | "**append** - append an item to a list" 615 | ] 616 | }, 617 | { 618 | "cell_type": "code", 619 | "execution_count": 18, 620 | "metadata": {}, 621 | "outputs": [ 622 | { 623 | "name": "stdout", 624 | "output_type": "stream", 625 | "text": [ 626 | "[5, 3, 8, 6, 7]\n" 627 | ] 628 | } 629 | ], 630 | "source": [ 631 | "x = [5, 3, 8, 6]\n", 632 | "x.append(7)\n", 633 | "print(x)" 634 | ] 635 | }, 636 | { 637 | "cell_type": "markdown", 638 | "metadata": {}, 639 | "source": [ 640 | "**extend** - append a sequence to a list" 641 | ] 642 | }, 643 | { 644 | "cell_type": "code", 645 | "execution_count": 19, 646 | "metadata": {}, 647 | "outputs": [ 648 | { 649 | "name": "stdout", 650 | "output_type": "stream", 651 | "text": [ 652 | "[5, 3, 8, 6, 12, 13]\n" 653 | ] 654 | } 655 | ], 656 | "source": [ 657 | "x = [5, 3, 8, 6]\n", 658 | "y = [12, 13]\n", 659 | "x.extend(y)\n", 660 | "print(x)" 661 | ] 662 | }, 663 | { 664 | "cell_type": "markdown", 665 | "metadata": {}, 666 | "source": [ 667 | "**insert** - insert an item at a given index" 668 | ] 669 | }, 670 | { 671 | "cell_type": "code", 672 | "execution_count": 20, 673 | "metadata": {}, 674 | "outputs": [ 675 | { 676 | "name": "stdout", 677 | "output_type": "stream", 678 | "text": [ 679 | "[5, 7, 3, 8, 6]\n", 680 | "[5, ['a', 'm'], 7, 3, 8, 6]\n" 681 | ] 682 | } 683 | ], 684 | "source": [ 685 | "x = [5, 3, 8, 6]\n", 686 | "x.insert(1, 7)\n", 687 | "print(x)\n", 688 | "x.insert(1, ['a', 'm'])\n", 689 | "print(x)" 690 | ] 691 | }, 692 | { 693 | "cell_type": "markdown", 694 | "metadata": {}, 695 | "source": [ 696 | "**pop** - pops last item off list and returns item" 697 | ] 698 | }, 699 | { 700 | "cell_type": "code", 701 | "execution_count": 21, 702 | "metadata": {}, 703 | "outputs": [ 704 | { 705 | "name": "stdout", 706 | "output_type": "stream", 707 | "text": [ 708 | "[5, 3, 8]\n", 709 | "8\n" 710 | ] 711 | } 712 | ], 713 | "source": [ 714 | "x = [5, 3, 8, 6]\n", 715 | "x.pop() # pop off the 6\n", 716 | "print(x)\n", 717 | "print(x.pop())" 718 | ] 719 | }, 720 | { 721 | "cell_type": "markdown", 722 | "metadata": {}, 723 | "source": [ 724 | "**remove** - remove first instance of an item" 725 | ] 726 | }, 727 | { 728 | "cell_type": "code", 729 | "execution_count": 22, 730 | "metadata": {}, 731 | "outputs": [ 732 | { 733 | "name": "stdout", 734 | "output_type": "stream", 735 | "text": [ 736 | "[5, 8, 6, 3]\n" 737 | ] 738 | } 739 | ], 740 | "source": [ 741 | "x = [5, 3, 8, 6, 3]\n", 742 | "x.remove(3)\n", 743 | "print(x)" 744 | ] 745 | }, 746 | { 747 | "cell_type": "markdown", 748 | "metadata": {}, 749 | "source": [ 750 | "**reverse** - reverse the order of the list. It is an in-place sort, meaning it changes the original list." 751 | ] 752 | }, 753 | { 754 | "cell_type": "code", 755 | "execution_count": 23, 756 | "metadata": {}, 757 | "outputs": [ 758 | { 759 | "name": "stdout", 760 | "output_type": "stream", 761 | "text": [ 762 | "[6, 8, 3, 5]\n" 763 | ] 764 | } 765 | ], 766 | "source": [ 767 | "x = [5, 3, 8, 6]\n", 768 | "x.reverse()\n", 769 | "print(x)" 770 | ] 771 | }, 772 | { 773 | "cell_type": "markdown", 774 | "metadata": {}, 775 | "source": [ 776 | "**sort** - sort the list in place. \n", 777 | "Note: \n", 778 | "sorted(x) returns a new sorted list without changing the original list x. \n", 779 | "x.sort() puts the items of x in sorted order (sorts in place)." 780 | ] 781 | }, 782 | { 783 | "cell_type": "code", 784 | "execution_count": 24, 785 | "metadata": {}, 786 | "outputs": [ 787 | { 788 | "name": "stdout", 789 | "output_type": "stream", 790 | "text": [ 791 | "[3, 5, 6, 8]\n" 792 | ] 793 | } 794 | ], 795 | "source": [ 796 | "x = [5, 3, 8, 6]\n", 797 | "x.sort()\n", 798 | "print(x)" 799 | ] 800 | }, 801 | { 802 | "cell_type": "markdown", 803 | "metadata": {}, 804 | "source": [ 805 | "**reverse sort** - sort items descending. \n", 806 | "Use *reverse=True* parameter to the sort function." 807 | ] 808 | }, 809 | { 810 | "cell_type": "code", 811 | "execution_count": 25, 812 | "metadata": {}, 813 | "outputs": [ 814 | { 815 | "name": "stdout", 816 | "output_type": "stream", 817 | "text": [ 818 | "[8, 6, 5, 3]\n" 819 | ] 820 | } 821 | ], 822 | "source": [ 823 | "x = [5, 3, 8, 6]\n", 824 | "x.sort(reverse=True)\n", 825 | "print(x)" 826 | ] 827 | }, 828 | { 829 | "cell_type": "markdown", 830 | "metadata": {}, 831 | "source": [ 832 | "## Tuples\n", 833 | "****\n", 834 | "- Immutable (can’t add/change)\n", 835 | "- Useful for fixed data\n", 836 | "- Faster than Lists\n", 837 | "- Sequence type \n", 838 | " \n", 839 | "**constructors** - creating new tuples." 840 | ] 841 | }, 842 | { 843 | "cell_type": "code", 844 | "execution_count": 26, 845 | "metadata": {}, 846 | "outputs": [ 847 | { 848 | "name": "stdout", 849 | "output_type": "stream", 850 | "text": [ 851 | "(2,) \n", 852 | "(2, 4, 6) \n" 853 | ] 854 | } 855 | ], 856 | "source": [ 857 | "x = ()\n", 858 | "x = (1, 2, 3)\n", 859 | "x = 1, 2, 3\n", 860 | "x = 2, # the comma tells Python it's a tuple\n", 861 | "print(x, type(x))\n", 862 | "\n", 863 | "list1 = [2, 4, 6]\n", 864 | "x = tuple(list1)\n", 865 | "print(x, type(x))" 866 | ] 867 | }, 868 | { 869 | "cell_type": "markdown", 870 | "metadata": {}, 871 | "source": [ 872 | "**tuples are immutable**, but member objects may be mutable." 873 | ] 874 | }, 875 | { 876 | "cell_type": "code", 877 | "execution_count": 27, 878 | "metadata": {}, 879 | "outputs": [ 880 | { 881 | "name": "stdout", 882 | "output_type": "stream", 883 | "text": [ 884 | "(1, 2, 3)\n", 885 | "([1], 3)\n", 886 | "([1], 3, 4)\n" 887 | ] 888 | } 889 | ], 890 | "source": [ 891 | "x = (1, 2, 3)\n", 892 | "# del(x[1]) # fails\n", 893 | "# x[1] = 8 # fails\n", 894 | "print(x)\n", 895 | "\n", 896 | "y = ([1, 2], 3) # a tuple where the first item is a list\n", 897 | "del(y[0][1]) # delete the 2\n", 898 | "print(y) # the list within the tuple is mutable\n", 899 | "\n", 900 | "y += (4,) # concatenating two tuples works\n", 901 | "print(y)" 902 | ] 903 | }, 904 | { 905 | "cell_type": "markdown", 906 | "metadata": {}, 907 | "source": [ 908 | "## Sets\n", 909 | "****\n", 910 | "- Store non-duplicate items \n", 911 | "- Very fast access vs Lists \n", 912 | "- Math Set ops (union, intersect) \n", 913 | "- Sets are Unordered \n", 914 | " \n", 915 | "**constructors** - creating new sets" 916 | ] 917 | }, 918 | { 919 | "cell_type": "code", 920 | "execution_count": 28, 921 | "metadata": {}, 922 | "outputs": [ 923 | { 924 | "name": "stdout", 925 | "output_type": "stream", 926 | "text": [ 927 | "{3, 5}\n", 928 | "set()\n", 929 | "{2, 3, 4}\n" 930 | ] 931 | } 932 | ], 933 | "source": [ 934 | "x = {3, 5, 3, 5}\n", 935 | "print(x)\n", 936 | "\n", 937 | "y = set()\n", 938 | "print(y)\n", 939 | "\n", 940 | "list1 = [2, 3, 4]\n", 941 | "z = set(list1)\n", 942 | "print(z)" 943 | ] 944 | }, 945 | { 946 | "cell_type": "markdown", 947 | "metadata": {}, 948 | "source": [ 949 | "**set operations**" 950 | ] 951 | }, 952 | { 953 | "cell_type": "code", 954 | "execution_count": 29, 955 | "metadata": {}, 956 | "outputs": [ 957 | { 958 | "name": "stdout", 959 | "output_type": "stream", 960 | "text": [ 961 | "{8, 3, 5}\n", 962 | "{8, 3, 5, 7}\n", 963 | "{8, 5, 7}\n", 964 | "3\n", 965 | "True\n", 966 | "8 {5, 7}\n", 967 | "set()\n" 968 | ] 969 | } 970 | ], 971 | "source": [ 972 | "x = {3, 8, 5}\n", 973 | "print(x)\n", 974 | "x.add(7)\n", 975 | "print(x)\n", 976 | "\n", 977 | "x.remove(3)\n", 978 | "print(x)\n", 979 | "\n", 980 | "# get length of set x\n", 981 | "print(len(x))\n", 982 | "\n", 983 | "# check membership in x\n", 984 | "print(5 in x)\n", 985 | "\n", 986 | "# pop random item from set x\n", 987 | "print(x.pop(), x)\n", 988 | "\n", 989 | "# delete all items from set x\n", 990 | "x.clear()\n", 991 | "print(x)" 992 | ] 993 | }, 994 | { 995 | "cell_type": "markdown", 996 | "metadata": {}, 997 | "source": [ 998 | "**Mathematical set operations** \n", 999 | "intersection (AND): set1 & set2 \n", 1000 | "union (OR): set1 | set2 \n", 1001 | "symmetric difference (XOR): set1 ^ set2 \n", 1002 | "difference (in set1 but not set2): set1 - set2 \n", 1003 | "subset (set2 contains set1): set1 <= set2 \n", 1004 | "superset (set1 contains set2): set1 >= set2" 1005 | ] 1006 | }, 1007 | { 1008 | "cell_type": "code", 1009 | "execution_count": 30, 1010 | "metadata": {}, 1011 | "outputs": [ 1012 | { 1013 | "name": "stdout", 1014 | "output_type": "stream", 1015 | "text": [ 1016 | "{3}\n", 1017 | "{1, 2, 3, 4, 5}\n", 1018 | "{1, 2, 4, 5}\n", 1019 | "{1, 2}\n", 1020 | "False\n", 1021 | "False\n" 1022 | ] 1023 | } 1024 | ], 1025 | "source": [ 1026 | "s1 = {1, 2, 3}\n", 1027 | "s2 = {3, 4, 5}\n", 1028 | "print(s1 & s2)\n", 1029 | "print(s1 | s2)\n", 1030 | "print(s1 ^ s2)\n", 1031 | "print(s1 - s2)\n", 1032 | "print(s1 <= s2)\n", 1033 | "print(s1 >= s2)" 1034 | ] 1035 | }, 1036 | { 1037 | "cell_type": "markdown", 1038 | "metadata": {}, 1039 | "source": [ 1040 | "## Dictionaries (dict)\n", 1041 | "****\n", 1042 | "- Key/Value pairs\n", 1043 | "- Associative array, like Java HashMap\n", 1044 | "- Dicts are Unordered \n", 1045 | "\n", 1046 | "**constructors** - creating new dictionaries" 1047 | ] 1048 | }, 1049 | { 1050 | "cell_type": "code", 1051 | "execution_count": 31, 1052 | "metadata": {}, 1053 | "outputs": [ 1054 | { 1055 | "name": "stdout", 1056 | "output_type": "stream", 1057 | "text": [ 1058 | "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", 1059 | "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", 1060 | "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n" 1061 | ] 1062 | } 1063 | ], 1064 | "source": [ 1065 | "x = {'pork':25.3, 'beef':33.8, 'chicken':22.7}\n", 1066 | "print(x)\n", 1067 | "x = dict([('pork', 25.3),('beef', 33.8),('chicken', 22.7)])\n", 1068 | "print(x)\n", 1069 | "x = dict(pork=25.3, beef=33.8, chicken=22.7)\n", 1070 | "print(x)" 1071 | ] 1072 | }, 1073 | { 1074 | "cell_type": "markdown", 1075 | "metadata": {}, 1076 | "source": [ 1077 | "**dict operations**" 1078 | ] 1079 | }, 1080 | { 1081 | "cell_type": "code", 1082 | "execution_count": 32, 1083 | "metadata": {}, 1084 | "outputs": [ 1085 | { 1086 | "name": "stdout", 1087 | "output_type": "stream", 1088 | "text": [ 1089 | "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7, 'shrimp': 38.2}\n", 1090 | "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", 1091 | "3\n", 1092 | "{}\n" 1093 | ] 1094 | } 1095 | ], 1096 | "source": [ 1097 | "x['shrimp'] = 38.2 # add or update\n", 1098 | "print(x)\n", 1099 | "\n", 1100 | "# delete an item\n", 1101 | "del(x['shrimp'])\n", 1102 | "print(x)\n", 1103 | "\n", 1104 | "# get length of dict x\n", 1105 | "print(len(x))\n", 1106 | "\n", 1107 | "# delete all items from dict x\n", 1108 | "x.clear()\n", 1109 | "print(x)\n", 1110 | "\n", 1111 | "# delete dict x\n", 1112 | "del(x)" 1113 | ] 1114 | }, 1115 | { 1116 | "cell_type": "markdown", 1117 | "metadata": {}, 1118 | "source": [ 1119 | "**accessing keys and values in a dict** \n", 1120 | "Not compatible with Python 2." 1121 | ] 1122 | }, 1123 | { 1124 | "cell_type": "code", 1125 | "execution_count": 33, 1126 | "metadata": {}, 1127 | "outputs": [ 1128 | { 1129 | "name": "stdout", 1130 | "output_type": "stream", 1131 | "text": [ 1132 | "dict_keys(['pork', 'beef', 'chicken'])\n", 1133 | "dict_values([25.3, 33.8, 22.7])\n", 1134 | "dict_items([('pork', 25.3), ('beef', 33.8), ('chicken', 22.7)])\n", 1135 | "True\n", 1136 | "False\n" 1137 | ] 1138 | } 1139 | ], 1140 | "source": [ 1141 | "y = {'pork':25.3, 'beef':33.8, 'chicken':22.7}\n", 1142 | "print(y.keys())\n", 1143 | "print(y.values())\n", 1144 | "print(y.items()) # key-value pairs\n", 1145 | "\n", 1146 | "# check membership in y_keys (only looks in keys, not values)\n", 1147 | "print('beef' in y)\n", 1148 | "\n", 1149 | "# check membership in y_values\n", 1150 | "print('clams' in y.values())" 1151 | ] 1152 | }, 1153 | { 1154 | "cell_type": "markdown", 1155 | "metadata": {}, 1156 | "source": [ 1157 | "**iterating a dict** - note, items are in random order." 1158 | ] 1159 | }, 1160 | { 1161 | "cell_type": "code", 1162 | "execution_count": 34, 1163 | "metadata": {}, 1164 | "outputs": [ 1165 | { 1166 | "name": "stdout", 1167 | "output_type": "stream", 1168 | "text": [ 1169 | "pork 25.3\n", 1170 | "beef 33.8\n", 1171 | "chicken 22.7\n", 1172 | "pork 25.3\n", 1173 | "beef 33.8\n", 1174 | "chicken 22.7\n" 1175 | ] 1176 | } 1177 | ], 1178 | "source": [ 1179 | "for key in y:\n", 1180 | " print(key, y[key])\n", 1181 | " \n", 1182 | "for k, v in y.items():\n", 1183 | " print(k, v)" 1184 | ] 1185 | }, 1186 | { 1187 | "cell_type": "code", 1188 | "execution_count": null, 1189 | "metadata": {}, 1190 | "outputs": [], 1191 | "source": [] 1192 | } 1193 | ], 1194 | "metadata": { 1195 | "kernelspec": { 1196 | "display_name": "Python 3", 1197 | "language": "python", 1198 | "name": "python3" 1199 | }, 1200 | "language_info": { 1201 | "codemirror_mode": { 1202 | "name": "ipython", 1203 | "version": 3 1204 | }, 1205 | "file_extension": ".py", 1206 | "mimetype": "text/x-python", 1207 | "name": "python", 1208 | "nbconvert_exporter": "python", 1209 | "pygments_lexer": "ipython3", 1210 | "version": "3.7.0" 1211 | } 1212 | }, 1213 | "nbformat": 4, 1214 | "nbformat_minor": 2 1215 | } 1216 | -------------------------------------------------------------------------------- /Section_1/Python_native-data-structures.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_1/Python_native-data-structures.pdf -------------------------------------------------------------------------------- /Section_2/MaxHeap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_2/MaxHeap.pdf -------------------------------------------------------------------------------- /Section_2/Stacks and Queues.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_2/Stacks and Queues.pdf -------------------------------------------------------------------------------- /Section_2/Stacks, Queues & Heaps.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Stacks, Queues & Heaps\n", 8 | "© Joe James, 2019.\n", 9 | "\n", 10 | "### Stack using Python List\n", 11 | "Stack is a LIFO data structure -- last-in, first-out. \n", 12 | "Use append() to push an item onto the stack. \n", 13 | "Use pop() to remove an item." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "metadata": { 20 | "scrolled": true 21 | }, 22 | "outputs": [ 23 | { 24 | "name": "stdout", 25 | "output_type": "stream", 26 | "text": [ 27 | "[4, 7, 12, 19]\n" 28 | ] 29 | } 30 | ], 31 | "source": [ 32 | "my_stack = list()\n", 33 | "my_stack.append(4)\n", 34 | "my_stack.append(7)\n", 35 | "my_stack.append(12)\n", 36 | "my_stack.append(19)\n", 37 | "print(my_stack)" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 3, 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "19\n", 50 | "12\n", 51 | "[4, 7]\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "print(my_stack.pop())\n", 57 | "print(my_stack.pop())\n", 58 | "print(my_stack)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "### Stack using List with a Wrapper Class\n", 66 | "We create a Stack class and a full set of Stack methods. \n", 67 | "But the underlying data structure is really a Python List. \n", 68 | "For pop and peek methods we first check whether the stack is empty, to avoid exceptions." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 4, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "class Stack():\n", 78 | " def __init__(self):\n", 79 | " self.stack = list()\n", 80 | " def push(self, item):\n", 81 | " self.stack.append(item)\n", 82 | " def pop(self):\n", 83 | " if len(self.stack) > 0:\n", 84 | " return self.stack.pop()\n", 85 | " else:\n", 86 | " return None\n", 87 | " def peek(self):\n", 88 | " if len(self.stack) > 0:\n", 89 | " return self.stack[len(self.stack)-1]\n", 90 | " else:\n", 91 | " return None\n", 92 | " def __str__(self):\n", 93 | " return str(self.stack)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "### Test Code for Stack Wrapper Class" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 5, 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "name": "stdout", 110 | "output_type": "stream", 111 | "text": [ 112 | "[1, 3]\n", 113 | "3\n", 114 | "1\n", 115 | "1\n", 116 | "None\n" 117 | ] 118 | } 119 | ], 120 | "source": [ 121 | "my_stack = Stack()\n", 122 | "my_stack.push(1)\n", 123 | "my_stack.push(3)\n", 124 | "print(my_stack)\n", 125 | "print(my_stack.pop())\n", 126 | "print(my_stack.peek())\n", 127 | "print(my_stack.pop())\n", 128 | "print(my_stack.pop())" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "---\n", 136 | "### Queue using Python Deque\n", 137 | "Queue is a FIFO data structure -- first-in, first-out. \n", 138 | "Deque is a double-ended queue, but we can use it for our queue. \n", 139 | "We use append() to enqueue an item, and popleft() to dequeue an item. \n", 140 | "See [Python docs](https://docs.python.org/3/library/collections.html#collections.deque) for deque." 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 6, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "deque([5, 10])\n", 153 | "5\n" 154 | ] 155 | } 156 | ], 157 | "source": [ 158 | "from collections import deque\n", 159 | "my_queue = deque()\n", 160 | "my_queue.append(5)\n", 161 | "my_queue.append(10)\n", 162 | "print(my_queue)\n", 163 | "print(my_queue.popleft())" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "### Fun exercise:\n", 171 | "Write a wrapper class for the Queue class, similar to what we did for Stack, but using Python deque. \n", 172 | "Try adding enqueue, dequeue, and get_size methods." 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "### Python Single-ended Queue Wrapper Class using Deque\n", 180 | "We rename the append method to enqueue, and popleft to dequeue. \n", 181 | "We also add peek and get_size operations." 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 7, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "from collections import deque\n", 191 | "class Queue():\n", 192 | " def __init__(self):\n", 193 | " self.queue = deque()\n", 194 | " self.size = 0\n", 195 | " def enqueue(self, item):\n", 196 | " self.queue.append(item)\n", 197 | " self.size += 1\n", 198 | " def dequeue(self, item):\n", 199 | " if self.size > 0:\n", 200 | " self.size -= 1\n", 201 | " return self.queue.popleft()\n", 202 | " else: \n", 203 | " return None\n", 204 | " def peek(self):\n", 205 | " if self.size > 0:\n", 206 | " ret_val = self.queue.popleft()\n", 207 | " queue.appendleft(ret_val)\n", 208 | " return ret_val\n", 209 | " else:\n", 210 | " return None\n", 211 | " def get_size(self):\n", 212 | " return self.size" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "### Python MaxHeap\n", 220 | "A MaxHeap always bubbles the highest value to the top, so it can be removed instantly. \n", 221 | "Public functions: push, peek, pop \n", 222 | "Private functions: __swap, __floatUp, __bubbleDown, __str__." 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 11, 228 | "metadata": {}, 229 | "outputs": [], 230 | "source": [ 231 | "class MaxHeap:\n", 232 | " def __init__(self, items=[]):\n", 233 | " super().__init__()\n", 234 | " self.heap = [0]\n", 235 | " for item in items:\n", 236 | " self.heap.append(item)\n", 237 | " self.__floatUp(len(self.heap) - 1)\n", 238 | "\n", 239 | " def push(self, data):\n", 240 | " self.heap.append(data)\n", 241 | " self.__floatUp(len(self.heap) - 1)\n", 242 | "\n", 243 | " def peek(self):\n", 244 | " if self.heap[1]:\n", 245 | " return self.heap[1]\n", 246 | " else:\n", 247 | " return False\n", 248 | " \n", 249 | " def pop(self):\n", 250 | " if len(self.heap) > 2:\n", 251 | " self.__swap(1, len(self.heap) - 1)\n", 252 | " max = self.heap.pop()\n", 253 | " self.__bubbleDown(1)\n", 254 | " elif len(self.heap) == 2:\n", 255 | " max = self.heap.pop()\n", 256 | " else: \n", 257 | " max = False\n", 258 | " return max\n", 259 | "\n", 260 | " def __swap(self, i, j):\n", 261 | " self.heap[i], self.heap[j] = self.heap[j], self.heap[i]\n", 262 | "\n", 263 | " def __floatUp(self, index):\n", 264 | " parent = index//2\n", 265 | " if index <= 1:\n", 266 | " return\n", 267 | " elif self.heap[index] > self.heap[parent]:\n", 268 | " self.__swap(index, parent)\n", 269 | " self.__floatUp(parent)\n", 270 | "\n", 271 | " def __bubbleDown(self, index):\n", 272 | " left = index * 2\n", 273 | " right = index * 2 + 1\n", 274 | " largest = index\n", 275 | " if len(self.heap) > left and self.heap[largest] < self.heap[left]:\n", 276 | " largest = left\n", 277 | " if len(self.heap) > right and self.heap[largest] < self.heap[right]:\n", 278 | " largest = right\n", 279 | " if largest != index:\n", 280 | " self.__swap(index, largest)\n", 281 | " self.__bubbleDown(largest)\n", 282 | " \n", 283 | " def __str__(self):\n", 284 | " return str(self.heap)" 285 | ] 286 | }, 287 | { 288 | "cell_type": "markdown", 289 | "metadata": {}, 290 | "source": [ 291 | "### MaxHeap Test Code" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 12, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "name": "stdout", 301 | "output_type": "stream", 302 | "text": [ 303 | "[0, 95, 10, 21, 3]\n", 304 | "95\n", 305 | "21\n" 306 | ] 307 | } 308 | ], 309 | "source": [ 310 | "m = MaxHeap([95, 3, 21])\n", 311 | "m.push(10)\n", 312 | "print(m)\n", 313 | "print(m.pop())\n", 314 | "print(m.peek())" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [] 323 | } 324 | ], 325 | "metadata": { 326 | "kernelspec": { 327 | "display_name": "Python 3", 328 | "language": "python", 329 | "name": "python3" 330 | }, 331 | "language_info": { 332 | "codemirror_mode": { 333 | "name": "ipython", 334 | "version": 3 335 | }, 336 | "file_extension": ".py", 337 | "mimetype": "text/x-python", 338 | "name": "python", 339 | "nbconvert_exporter": "python", 340 | "pygments_lexer": "ipython3", 341 | "version": "3.7.0" 342 | } 343 | }, 344 | "nbformat": 4, 345 | "nbformat_minor": 2 346 | } 347 | -------------------------------------------------------------------------------- /Section_3/Python Linked Lists.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Python Linked Lists" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "### Node Class\n", 15 | "Node class has a constructor that sets the data passed in, and optionally can set the next_node and prev_node. \n", 16 | "It also has a str method to give a string representation for printing. \n", 17 | "Note that prev_node is only used for Doubly Linked Lists." 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 128, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "class Node:\n", 27 | "\n", 28 | " def __init__ (self, d, n=None, p=None):\n", 29 | " self.data = d\n", 30 | " self.next_node = n\n", 31 | " self.prev_node = p\n", 32 | " \n", 33 | " def __str__ (self):\n", 34 | " return ('(' + str(self.data) + ')')" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "### LinkedList Class\n", 42 | "A LinkedList object has two attributes: a root node that defaults to None, and size that defaults to 0.\n", 43 | " \n", 44 | "**Add** method receives a piece of data, creates a new Node, setting the root as its next_node, changes the LL's root pointer to the new node, and increments size.\n", 45 | "\n", 46 | "**Find** iterates through the nodes until it finds the data passed in. If if finds the data it will return it, otherwise returns None.\n", 47 | "\n", 48 | "**Remove** needs pointers to this_node and prev_node. If it finds the data, it needs to check if it is in the root node (prev_node is None) before deciding how to bypass the deleted node.\n", 49 | "\n", 50 | "**Print_list** iterates the list and prints each node." 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 129, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "class LinkedList:\n", 60 | "\n", 61 | " def __init__(self, r = None):\n", 62 | " self.root = r\n", 63 | " self.size = 0\n", 64 | "\n", 65 | " def add(self, d):\n", 66 | " new_node = Node(d, self.root)\n", 67 | " self.root = new_node\n", 68 | " self.size += 1\n", 69 | " \n", 70 | " def find(self, d):\n", 71 | " this_node = self.root\n", 72 | " while this_node is not None:\n", 73 | " if this_node.data == d:\n", 74 | " return d\n", 75 | " else:\n", 76 | " this_node = this_node.next_node\n", 77 | " return None\n", 78 | "\n", 79 | " def remove(self, d):\n", 80 | " this_node = self.root\n", 81 | " prev_node = None\n", 82 | "\n", 83 | " while this_node is not None:\n", 84 | " if this_node.data == d:\n", 85 | " if prev_node is not None: # data is in non-root\n", 86 | " prev_node.next_node = this_node.next_node\n", 87 | " else: # data is in root node\n", 88 | " self.root = this_node.next_node\n", 89 | " self.size -= 1\n", 90 | " return True # data removed\n", 91 | " else:\n", 92 | " prev_node = this_node\n", 93 | " this_node = this_node.next_node\n", 94 | " return False # data not found\n", 95 | " \n", 96 | " def print_list(self):\n", 97 | " this_node = self.root\n", 98 | " while this_node is not None:\n", 99 | " print(this_node, end='->')\n", 100 | " this_node = this_node.next_node\n", 101 | " print('None')" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "### Linked List Test Code\n", 109 | "This test code adds nodes to the LinkedList, Prints the list, prints the size, removes an item, and finds an item." 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 130, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "name": "stdout", 119 | "output_type": "stream", 120 | "text": [ 121 | "(12)->(8)->(5)->None\n", 122 | "size=3\n", 123 | "size=2\n", 124 | "5\n", 125 | "(12)\n" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "myList = LinkedList()\n", 131 | "myList.add(5)\n", 132 | "myList.add(8)\n", 133 | "myList.add(12)\n", 134 | "myList.print_list()\n", 135 | "\n", 136 | "print(\"size=\"+str(myList.size))\n", 137 | "myList.remove(8)\n", 138 | "print(\"size=\"+str(myList.size))\n", 139 | "print(myList.find(5))\n", 140 | "print(myList.root)" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "-----\n", 148 | "### Circular Linked List\n", 149 | "Includes attributes root and size. \n", 150 | "Includes methods add, find, remove, and print_list." 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 131, 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "class CircularLinkedList:\n", 160 | "\n", 161 | " def __init__ (self, r = None):\n", 162 | " self.root = r\n", 163 | " self.size = 0\n", 164 | "\n", 165 | " def add (self, d):\n", 166 | " if self.size == 0:\n", 167 | " self.root = Node(d)\n", 168 | " self.root.next_node = self.root\n", 169 | " else:\n", 170 | " new_node = Node (d, self.root.next_node)\n", 171 | " self.root.next_node = new_node\n", 172 | " self.size += 1\n", 173 | "\n", 174 | " def find (self, d):\n", 175 | " this_node = self.root\n", 176 | " while True:\n", 177 | " if this_node.data == d:\n", 178 | " return d\n", 179 | " elif this_node.next_node == self.root:\n", 180 | " return False\n", 181 | " this_node = this_node.next_node\n", 182 | "\n", 183 | " def remove (self, d):\n", 184 | " this_node = self.root\n", 185 | " prev_node = None\n", 186 | "\n", 187 | " while True:\n", 188 | " if this_node.data == d: # found\n", 189 | " if prev_node is not None:\n", 190 | " prev_node.next_node = this_node.next_node\n", 191 | " else:\n", 192 | " while this_node.next_node != self.root:\n", 193 | " this_node = this_node.next_node\n", 194 | " this_node.next_node = self.root.next_node\n", 195 | " self.root = self.root.next_node\n", 196 | " self.size -= 1\n", 197 | " return True # data removed\n", 198 | " elif this_node.next_node == self.root:\n", 199 | " return False # data not found\n", 200 | " prev_node = this_node\n", 201 | " this_node = this_node.next_node\n", 202 | " \n", 203 | " def print_list (self):\n", 204 | " if self.root is None:\n", 205 | " return\n", 206 | " this_node = self.root\n", 207 | " print (this_node, end='->')\n", 208 | " while this_node.next_node != self.root:\n", 209 | " this_node = this_node.next_node\n", 210 | " print (this_node, end='->')\n", 211 | " print()" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "### Circular Linked List Test Code" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 132, 224 | "metadata": {}, 225 | "outputs": [ 226 | { 227 | "name": "stdout", 228 | "output_type": "stream", 229 | "text": [ 230 | "size=5\n", 231 | "8\n", 232 | "False\n", 233 | "(5)->(9)->(8)->(3)->(7)->(5)->(9)->(8)->(3)->\n" 234 | ] 235 | } 236 | ], 237 | "source": [ 238 | "cll = CircularLinkedList()\n", 239 | "for i in [5, 7, 3, 8, 9]:\n", 240 | " cll.add(i)\n", 241 | "\n", 242 | "print(\"size=\"+str(cll.size))\n", 243 | "print(cll.find(8))\n", 244 | "print(cll.find(12))\n", 245 | "\n", 246 | "my_node = cll.root\n", 247 | "print (my_node, end='->')\n", 248 | "for i in range(8):\n", 249 | " my_node = my_node.next_node\n", 250 | " print (my_node, end='->')\n", 251 | "print()" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": 133, 257 | "metadata": {}, 258 | "outputs": [ 259 | { 260 | "name": "stdout", 261 | "output_type": "stream", 262 | "text": [ 263 | "(5)->(9)->(8)->(3)->(7)->\n", 264 | "False\n", 265 | "size=4\n", 266 | "(9)->(3)->(7)->\n" 267 | ] 268 | } 269 | ], 270 | "source": [ 271 | "cll.print_list()\n", 272 | "cll.remove(8)\n", 273 | "print(cll.remove(15))\n", 274 | "print(\"size=\"+str(cll.size))\n", 275 | "cll.remove(5) # delete root node\n", 276 | "cll.print_list()" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "-----\n", 284 | "### Doubly Linked List" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 134, 290 | "metadata": {}, 291 | "outputs": [], 292 | "source": [ 293 | "class DoublyLinkedList:\n", 294 | "\n", 295 | " def __init__ (self, r = None):\n", 296 | " self.root = r\n", 297 | " self.last = r\n", 298 | " self.size = 0\n", 299 | "\n", 300 | " def add (self, d):\n", 301 | " if self.size == 0:\n", 302 | " self.root = Node(d)\n", 303 | " self.last = self.root\n", 304 | " else:\n", 305 | " new_node = Node(d, self.root)\n", 306 | " self.root.prev_node = new_node\n", 307 | " self.root = new_node\n", 308 | " self.size += 1\n", 309 | "\n", 310 | " def find (self, d):\n", 311 | " this_node = self.root\n", 312 | " while this_node is not None:\n", 313 | " if this_node.data == d:\n", 314 | " return d\n", 315 | " elif this_node.next_node == None:\n", 316 | " return False\n", 317 | " else:\n", 318 | " this_node = this_node.next_node\n", 319 | "\n", 320 | " def remove (self, d):\n", 321 | " this_node = self.root\n", 322 | " while this_node is not None:\n", 323 | " if this_node.data == d:\n", 324 | " if this_node.prev_node is not None:\n", 325 | " if this_node.next_node is not None: # delete a middle node\n", 326 | " this_node.prev_node.next_node = this_node.next_node\n", 327 | " this_node.next_node.prev_node = this_node.prev_node\n", 328 | " else: # delete last node\n", 329 | " this_node.prev_node.next_node = None\n", 330 | " self.last = this_node.prev_node\n", 331 | " else: # delete root node\n", 332 | " self.root = this_node.next_node\n", 333 | " this_node.next_node.prev_node = self.root\n", 334 | " self.size -= 1\n", 335 | " return True # data removed\n", 336 | " else:\n", 337 | " this_node = this_node.next_node\n", 338 | " return False # data not found\n", 339 | " \n", 340 | " def print_list (self):\n", 341 | " if self.root is None:\n", 342 | " return\n", 343 | " this_node = self.root\n", 344 | " print (this_node, end='->')\n", 345 | " while this_node.next_node is not None:\n", 346 | " this_node = this_node.next_node\n", 347 | " print (this_node, end='->')\n", 348 | " print()" 349 | ] 350 | }, 351 | { 352 | "cell_type": "markdown", 353 | "metadata": {}, 354 | "source": [ 355 | "### Doubly Linked List Test Code" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": 135, 361 | "metadata": {}, 362 | "outputs": [ 363 | { 364 | "name": "stdout", 365 | "output_type": "stream", 366 | "text": [ 367 | "size=5\n", 368 | "(9)->(8)->(3)->(9)->(5)->\n", 369 | "size=4\n" 370 | ] 371 | } 372 | ], 373 | "source": [ 374 | "dll = DoublyLinkedList()\n", 375 | "for i in [5, 9, 3, 8, 9]:\n", 376 | " dll.add(i)\n", 377 | "\n", 378 | "print(\"size=\"+str(dll.size))\n", 379 | "dll.print_list()\n", 380 | "dll.remove(8)\n", 381 | "print(\"size=\"+str(dll.size))" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": 136, 387 | "metadata": {}, 388 | "outputs": [ 389 | { 390 | "name": "stdout", 391 | "output_type": "stream", 392 | "text": [ 393 | "False\n", 394 | "False\n", 395 | "(22)->(21)->(9)->(3)->(9)->\n", 396 | "(3)\n" 397 | ] 398 | } 399 | ], 400 | "source": [ 401 | "print(dll.remove(15))\n", 402 | "print(dll.find(15))\n", 403 | "dll.add(21)\n", 404 | "dll.add(22)\n", 405 | "dll.remove(5)\n", 406 | "dll.print_list()\n", 407 | "print(dll.last.prev_node)" 408 | ] 409 | }, 410 | { 411 | "cell_type": "code", 412 | "execution_count": null, 413 | "metadata": {}, 414 | "outputs": [], 415 | "source": [] 416 | } 417 | ], 418 | "metadata": { 419 | "kernelspec": { 420 | "display_name": "Python 3", 421 | "language": "python", 422 | "name": "python3" 423 | }, 424 | "language_info": { 425 | "codemirror_mode": { 426 | "name": "ipython", 427 | "version": 3 428 | }, 429 | "file_extension": ".py", 430 | "mimetype": "text/x-python", 431 | "name": "python", 432 | "nbconvert_exporter": "python", 433 | "pygments_lexer": "ipython3", 434 | "version": "3.7.0" 435 | } 436 | }, 437 | "nbformat": 4, 438 | "nbformat_minor": 2 439 | } 440 | -------------------------------------------------------------------------------- /Section_3/Python Linked Lists.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_3/Python Linked Lists.pdf -------------------------------------------------------------------------------- /Section_4/Binary Search Tree.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Binary Search Tree\n", 8 | "**Constructor** sets three attributes: data, left subtree and right subtree. \n", 9 | "**Insert** inserts a new subtree into the proper location. \n", 10 | "**Find** finds a value. If value not found, returns False. \n", 11 | "**Get_size** returns the number of nodes in the tree (excluding None nodes). \n", 12 | "**Preorder** prints a preorder traversal of the tree. \n", 13 | "**Inorder** prints an inorder traversal of the tree." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 69, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "class Tree:\n", 23 | " def __init__(self, data, left=None, right=None):\n", 24 | " self.data = data\n", 25 | " self.left = left\n", 26 | " self.right = right\n", 27 | " def insert(self, data):\n", 28 | " if self.data == data:\n", 29 | " return False # duplicate value\n", 30 | " elif self.data > data:\n", 31 | " if self.left is not None:\n", 32 | " return self.left.insert(data)\n", 33 | " else:\n", 34 | " self.left = Tree(data)\n", 35 | " return True\n", 36 | " else:\n", 37 | " if self.right is not None:\n", 38 | " return self.right.insert(data)\n", 39 | " else:\n", 40 | " self.right = Tree(data)\n", 41 | " return True\n", 42 | " def find(self, data):\n", 43 | " if self.data == data:\n", 44 | " return data\n", 45 | " elif self.data > data:\n", 46 | " if self.left is None:\n", 47 | " return False\n", 48 | " else:\n", 49 | " return self.left.find(data)\n", 50 | " elif self.data < data:\n", 51 | " if self.right is None:\n", 52 | " return False\n", 53 | " else:\n", 54 | " return self.right.find(data)\n", 55 | " def get_size(self):\n", 56 | " if self.left is not None and self.right is not None:\n", 57 | " return 1 + self.left.get_size() + self.right.get_size()\n", 58 | " elif self.left:\n", 59 | " return 1 + self.left.get_size()\n", 60 | " elif self.right:\n", 61 | " return 1 + self.right.get_size()\n", 62 | " else:\n", 63 | " return 1\n", 64 | " def preorder(self):\n", 65 | " if self is not None:\n", 66 | " print (self.data, end=' ')\n", 67 | " if self.left is not None:\n", 68 | " self.left.preorder()\n", 69 | " if self.right:\n", 70 | " self.right.preorder()\n", 71 | " def inorder(self):\n", 72 | " if self is not None:\n", 73 | " if self.left is not None:\n", 74 | " self.left.inorder()\n", 75 | " print (self.data, end=' ')\n", 76 | " if self.right is not None:\n", 77 | " self.right.inorder()\n" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "### Test Code\n", 85 | "We create a new tree, insert one value, insert a whole list of values, find all values from 1 to 15 (False for 0, 5 and 8 shows that those values are not in the tree), print the size of the tree, print preorder and postorder traversals." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 70, 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "name": "stdout", 95 | "output_type": "stream", 96 | "text": [ 97 | "False 1 2 3 4 False 6 7 False 9 10 11 12 13 14 15 \n", 98 | " 13\n", 99 | "7 2 1 3 6 4 9 15 10 12 11 13 14 \n", 100 | "1 2 3 4 6 7 9 10 11 12 13 14 15 \n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "tree = Tree(7)\n", 106 | "tree.insert(9)\n", 107 | "for i in [15, 10, 2, 12, 3, 1, 13, 6, 11, 4, 14, 9]:\n", 108 | " tree.insert(i)\n", 109 | "for i in range(16):\n", 110 | " print(tree.find(i), end=' ')\n", 111 | "print('\\n', tree.get_size())\n", 112 | "\n", 113 | "tree.preorder()\n", 114 | "print()\n", 115 | "tree.inorder()\n", 116 | "print()" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [] 125 | } 126 | ], 127 | "metadata": { 128 | "kernelspec": { 129 | "display_name": "Python 3", 130 | "language": "python", 131 | "name": "python3" 132 | }, 133 | "language_info": { 134 | "codemirror_mode": { 135 | "name": "ipython", 136 | "version": 3 137 | }, 138 | "file_extension": ".py", 139 | "mimetype": "text/x-python", 140 | "name": "python", 141 | "nbconvert_exporter": "python", 142 | "pygments_lexer": "ipython3", 143 | "version": "3.7.0" 144 | } 145 | }, 146 | "nbformat": 4, 147 | "nbformat_minor": 2 148 | } 149 | -------------------------------------------------------------------------------- /Section_4/Binary Search Trees.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_4/Binary Search Trees.pdf -------------------------------------------------------------------------------- /Section_5/Graph Implementation Using Adjacency Lists.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Graph Implementation Using Adjacency Lists\n", 8 | "for an undirected graph. \n", 9 | "© Joe James, 2019." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "### Vertex Class\n", 17 | "The Vertex class has a constructor that sets the name of the vertex (in our example, just a letter), and creates a new empty set to store neighbors.\n", 18 | "\n", 19 | "The add_neighbor method adds the name of a neighboring vertex to the neighbors set. This set automatically eliminates duplicates." 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 25, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "class Vertex:\n", 29 | " def __init__(self, n):\n", 30 | " self.name = n\n", 31 | " self.neighbors = set()\n", 32 | " \n", 33 | " def add_neighbor(self, v):\n", 34 | " self.neighbors.add(v)" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "### Graph Class\n", 42 | "The Graph class uses a dictionary to store vertices in the format, vertex_name:vertex_object.\n", 43 | " \n", 44 | "Adding a new vertex to the graph, we first check if the object passed in is a vertex object, then we check if it already exists in the graph. If both checks pass, then we add the vertex to the graph's vertices dictionary.\n", 45 | "\n", 46 | "When adding an edge, we receive two vertex names, we first check if both vertex names are valid, then we add each to the other's neighbors set.\n", 47 | "\n", 48 | "To print the graph, we iterate through the vertices, and print each vertex name (the key) followed by its sorted neighbors list." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 26, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "class Graph:\n", 58 | " vertices = {}\n", 59 | " \n", 60 | " def add_vertex(self, vertex):\n", 61 | " if isinstance(vertex, Vertex) and vertex.name not in self.vertices:\n", 62 | " self.vertices[vertex.name] = vertex\n", 63 | " return True\n", 64 | " else:\n", 65 | " return False\n", 66 | " \n", 67 | " def add_edge(self, u, v):\n", 68 | " if u in self.vertices and v in self.vertices:\n", 69 | " self.vertices[u].add_neighbor(v)\n", 70 | " self.vertices[v].add_neighbor(u)\n", 71 | " return True\n", 72 | " else:\n", 73 | " return False\n", 74 | " \n", 75 | " def print_graph(self):\n", 76 | " for key in sorted(list(self.vertices.keys())):\n", 77 | " print(key, sorted(list(self.vertices[key].neighbors)))" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "### Test Code\n", 85 | "Here we create a new Graph object. We create a new vertex named A. We add A to the graph. Then we add new vertex B to the graph. Then we iterate from A to K and add a bunch of vertices to the graph. Since the add_vertex method checks for duplicates, A and B are not added twice." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 27, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "g = Graph()\n", 95 | "a = Vertex('A')\n", 96 | "g.add_vertex(a)\n", 97 | "g.add_vertex(Vertex('B'))\n", 98 | "for i in range(ord('A'), ord('K')):\n", 99 | " g.add_vertex(Vertex(chr(i)))" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "An edge consists of two vertex names. Here we iterate through a list of edges and add each to the graph. \n", 107 | "\n", 108 | "This print_graph method doesn't give a very good visualization of the graph, but it does show the neighbors for each vertex." 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 28, 114 | "metadata": {}, 115 | "outputs": [ 116 | { 117 | "name": "stdout", 118 | "output_type": "stream", 119 | "text": [ 120 | "A ['B', 'E']\n", 121 | "B ['A', 'F']\n", 122 | "C ['G']\n", 123 | "D ['E', 'H']\n", 124 | "E ['A', 'D', 'H']\n", 125 | "F ['B', 'G', 'I', 'J']\n", 126 | "G ['C', 'F', 'J']\n", 127 | "H ['D', 'E', 'I']\n", 128 | "I ['F', 'H']\n", 129 | "J ['F', 'G']\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI']\n", 135 | "for edge in edges:\n", 136 | " g.add_edge(edge[0], edge[1])\n", 137 | "\n", 138 | "g.print_graph()" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [] 147 | } 148 | ], 149 | "metadata": { 150 | "kernelspec": { 151 | "display_name": "Python 3", 152 | "language": "python", 153 | "name": "python3" 154 | }, 155 | "language_info": { 156 | "codemirror_mode": { 157 | "name": "ipython", 158 | "version": 3 159 | }, 160 | "file_extension": ".py", 161 | "mimetype": "text/x-python", 162 | "name": "python", 163 | "nbconvert_exporter": "python", 164 | "pygments_lexer": "ipython3", 165 | "version": "3.7.0" 166 | } 167 | }, 168 | "nbformat": 4, 169 | "nbformat_minor": 2 170 | } 171 | -------------------------------------------------------------------------------- /Section_5/Graph Implementation Using Adjacency Matrix.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Graph Implementation Using Adjacency Matrix\n", 8 | "for undirected graph, with weighted or unweighted edges. \n", 9 | "© Joe James, 2019." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "### Vertex Class\n", 17 | "A vertex object only needs to store its name. " 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 4, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "class Vertex:\n", 27 | " def __init__(self, n):\n", 28 | " self.name = n" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "### Graph Class\n", 36 | "A graph object has three attributes: \n", 37 | "**vertices** - a dictionary with vertex_name:vertex_object. \n", 38 | "**edges** - a 2-dimensional list (ie. a matrix) of edges. for an unweighted graph it will contain 0 for no edge and 1 for edge. \n", 39 | "**edge_indices** - a dictionary with vertex_name:list_index (eg. A:0) to access edges. \n", 40 | "add_vertex updates all three of these attributes. \n", 41 | "add_edge only needs to update the edges matrix." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 5, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "class Graph:\n", 51 | " vertices = {}\n", 52 | " edges = []\n", 53 | " edge_indices = {}\n", 54 | " \n", 55 | " def add_vertex(self, vertex):\n", 56 | " if isinstance(vertex, Vertex) and vertex.name not in self.vertices:\n", 57 | " self.vertices[vertex.name] = vertex\n", 58 | " # for loop appends a column of zeros to the edges matrix\n", 59 | " for row in self.edges:\n", 60 | " row.append(0)\n", 61 | " # append a row of zeros to the bottom of the edges matrix\n", 62 | " self.edges.append([0] * (len(self.edges)+1))\n", 63 | " self.edge_indices[vertex.name] = len(self.edge_indices)\n", 64 | " return True\n", 65 | " else:\n", 66 | " return False\n", 67 | " \n", 68 | " def add_edge(self, u, v, weight=1):\n", 69 | " if u in self.vertices and v in self.vertices:\n", 70 | " self.edges[self.edge_indices[u]][self.edge_indices[v]] = weight\n", 71 | " self.edges[self.edge_indices[v]][self.edge_indices[u]] = weight\n", 72 | " return True\n", 73 | " else:\n", 74 | " return False\n", 75 | " \n", 76 | " def print_graph(self):\n", 77 | " for v, i in sorted(self.edge_indices.items()):\n", 78 | " print(v + ' ', end='')\n", 79 | " for j in range(len(self.edges)):\n", 80 | " print(self.edges[i][j], end=' ')\n", 81 | " print(' ')" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "### Test Code\n", 89 | "Here we create a new Graph object. We create a new vertex named A. We add A to the graph. Then we add new vertex B to the graph. Then we iterate from A to K and add a bunch of vertices to the graph. Since the add_vertex method checks for duplicates, A and B are not added twice.\n", 90 | "This is exactly the same test code we used for the graph with adjacency lists." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 8, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "g = Graph()\n", 100 | "a = Vertex('A')\n", 101 | "g.add_vertex(a)\n", 102 | "g.add_vertex(Vertex('B'))\n", 103 | "for i in range(ord('A'), ord('K')):\n", 104 | " g.add_vertex(Vertex(chr(i)))" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "An edge consists of two vertex names. Here we iterate through a list of edges and add each to the graph. \n", 112 | "\n", 113 | "This print_graph method doesn't give a very good visualization of the graph, but it does show the adjacency matrix so we can see each vertex's neighbors." 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 7, 119 | "metadata": {}, 120 | "outputs": [ 121 | { 122 | "name": "stdout", 123 | "output_type": "stream", 124 | "text": [ 125 | "A 0 1 0 0 1 0 0 0 0 0 \n", 126 | "B 1 0 0 0 0 1 0 0 0 0 \n", 127 | "C 0 0 0 0 0 0 1 0 0 0 \n", 128 | "D 0 0 0 0 1 0 0 1 0 0 \n", 129 | "E 1 0 0 1 0 0 0 1 0 0 \n", 130 | "F 0 1 0 0 0 0 1 0 1 1 \n", 131 | "G 0 0 1 0 0 1 0 0 0 1 \n", 132 | "H 0 0 0 1 1 0 0 0 1 0 \n", 133 | "I 0 0 0 0 0 1 0 1 0 0 \n", 134 | "J 0 0 0 0 0 1 1 0 0 0 \n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI']\n", 140 | "for edge in edges:\n", 141 | " g.add_edge(edge[0], edge[1])\n", 142 | "\n", 143 | "g.print_graph()" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [] 152 | } 153 | ], 154 | "metadata": { 155 | "kernelspec": { 156 | "display_name": "Python 3", 157 | "language": "python", 158 | "name": "python3" 159 | }, 160 | "language_info": { 161 | "codemirror_mode": { 162 | "name": "ipython", 163 | "version": 3 164 | }, 165 | "file_extension": ".py", 166 | "mimetype": "text/x-python", 167 | "name": "python", 168 | "nbconvert_exporter": "python", 169 | "pygments_lexer": "ipython3", 170 | "version": "3.7.0" 171 | } 172 | }, 173 | "nbformat": 4, 174 | "nbformat_minor": 2 175 | } 176 | -------------------------------------------------------------------------------- /Section_5/Graphs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeyajames/udemy_data_structures/0c191fe4aa8afda10817d696450aacd6071e651b/Section_5/Graphs.pdf -------------------------------------------------------------------------------- /Section_5/graph_adjacency-list.py: -------------------------------------------------------------------------------- 1 | # implementation of an undirected graph using Adjacency Lists 2 | class Vertex: 3 | def __init__(self, n): 4 | self.name = n 5 | self.neighbors = list() 6 | 7 | def add_neighbor(self, v): 8 | if v not in self.neighbors: 9 | self.neighbors.append(v) 10 | self.neighbors.sort() 11 | 12 | class Graph: 13 | vertices = {} 14 | 15 | def add_vertex(self, vertex): 16 | if isinstance(vertex, Vertex) and vertex.name not in self.vertices: 17 | self.vertices[vertex.name] = vertex 18 | return True 19 | else: 20 | return False 21 | 22 | def add_edge(self, u, v): 23 | if u in self.vertices and v in self.vertices: 24 | # my YouTube video shows a silly for loop here, but this is a much faster way to do it 25 | self.vertices[u].add_neighbor(v) 26 | self.vertices[v].add_neighbor(u) 27 | return True 28 | else: 29 | return False 30 | 31 | def print_graph(self): 32 | for key in sorted(list(self.vertices.keys())): 33 | print(key + str(self.vertices[key].neighbors)) 34 | 35 | g = Graph() 36 | # print(str(len(g.vertices))) 37 | a = Vertex('A') 38 | g.add_vertex(a) 39 | g.add_vertex(Vertex('B')) 40 | for i in range(ord('A'), ord('K')): 41 | g.add_vertex(Vertex(chr(i))) 42 | 43 | edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI'] 44 | for edge in edges: 45 | g.add_edge(edge[:1], edge[1:]) 46 | 47 | g.print_graph() -------------------------------------------------------------------------------- /Section_5/graph_adjacency-matrix.py: -------------------------------------------------------------------------------- 1 | # implementation of an undirected graph using Adjacency Matrix, with weighted or unweighted edges 2 | class Vertex: 3 | def __init__(self, n): 4 | self.name = n 5 | 6 | class Graph: 7 | vertices = {} 8 | edges = [] 9 | edge_indices = {} 10 | 11 | def add_vertex(self, vertex): 12 | if isinstance(vertex, Vertex) and vertex.name not in self.vertices: 13 | self.vertices[vertex.name] = vertex 14 | for row in self.edges: 15 | row.append(0) 16 | self.edges.append([0] * (len(self.edges)+1)) 17 | self.edge_indices[vertex.name] = len(self.edge_indices) 18 | return True 19 | else: 20 | return False 21 | 22 | def add_edge(self, u, v, weight=1): 23 | if u in self.vertices and v in self.vertices: 24 | self.edges[self.edge_indices[u]][self.edge_indices[v]] = weight 25 | self.edges[self.edge_indices[v]][self.edge_indices[u]] = weight 26 | return True 27 | else: 28 | return False 29 | 30 | def print_graph(self): 31 | for v, i in sorted(self.edge_indices.items()): 32 | print(v + ' ', end='') 33 | for j in range(len(self.edges)): 34 | print(self.edges[i][j], end='') 35 | print(' ') 36 | 37 | g = Graph() 38 | # print(str(len(g.vertices))) 39 | a = Vertex('A') 40 | g.add_vertex(a) 41 | g.add_vertex(Vertex('B')) 42 | for i in range(ord('A'), ord('K')): 43 | g.add_vertex(Vertex(chr(i))) 44 | 45 | edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI'] 46 | for edge in edges: 47 | g.add_edge(edge[:1], edge[1:]) 48 | 49 | g.print_graph() --------------------------------------------------------------------------------