├── README.md ├── test.js ├── LICENSE └── itsy-bitsy-data-structures.js /README.md: -------------------------------------------------------------------------------- 1 | ITSY BITSY DATA STRUCTURES 2 | 3 | ***Welcome to Itsy Bitsy Data Structures!*** 4 | 5 | In here are super simplified examples of many of the common data structures 6 | written in easy to read JavaScript. 7 | 8 | Reading through the guided code will help you learn about what data structures 9 | are, what their uses are, and how to discuss them. 10 | 11 | ### [Want to jump into the code? Click here](itsy-bitsy-data-structures.js) 12 | 13 | Also be sure to check out my other code walkthrough: 14 | [The Super Tiny Compiler](https://github.com/thejameskyle/the-super-tiny-compiler) 15 | 16 | --- 17 | 18 | ### Why should I care? 19 | 20 | Data Structures might not be the juiciest topic in the world, but they are 21 | hugely important to growing as an engineer. Knowing data structures don't just 22 | make your programs faster and more efficient, but they help you organize your 23 | code and your thoughts so that you can build more complicated programs without 24 | a ton of mental overhead. 25 | 26 | ### But data structures are scary! 27 | 28 | Yeah, lots of computer science topics are intimidating, and that's largely a 29 | fault of how they are taught. In this we're going to do a high level pass over 30 | a lot of the key things you need to know in order to dive into them deeper. 31 | It's more about introducing you to the shared language of data structures. 32 | 33 | ### Okay so where do I begin? 34 | 35 | Awesome! Head on over to the 36 | [itsy-bitsy-data-structures.js](itsy-bitsy-data-structures.js) file. 37 | 38 | ### I'm back, that didn't make sense 39 | 40 | Ouch, I'm really sorry. I'm planning on doing a lot more work on this to add 41 | inline annotations. If you want to come back when that's done, you can either 42 | watch/star this repo or follow me on 43 | [twitter](https://twitter.com/thejameskyle) for updates. 44 | 45 | --- 46 | 47 | [![cc-by-4.0](https://licensebuttons.net/l/by/4.0/80x15.png)](http://creativecommons.org/licenses/by/4.0/) 48 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var ItsyBitsyDataStructures = require('./itsy-bitsy-data-structures'); 5 | 6 | /** 7 | * ============================================================================ 8 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 9 | * ============================================================================ 10 | */ 11 | 12 | (function() { 13 | var list = new ItsyBitsyDataStructures.List(); 14 | 15 | list.push(1); 16 | list.unshift(2); 17 | 18 | assert.equal(list.get(1), 1); 19 | assert.equal(list.get(0), 2); 20 | 21 | assert.equal(list.shift(), 2); 22 | assert.equal(list.get(0), 1); 23 | 24 | assert.equal(list.pop(), 1); 25 | assert.equal(list.get(0), undefined); 26 | }()); 27 | 28 | /** 29 | * ============================================================================ 30 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 31 | * ============================================================================ 32 | */ 33 | 34 | (function() { 35 | var hashTable = new ItsyBitsyDataStructures.HashTable(); 36 | 37 | hashTable.set('foo', 'bar'); 38 | assert.equal(hashTable.get('foo'), 'bar'); 39 | 40 | hashTable.remove('foo'); 41 | assert.equal(hashTable.get('foo'), undefined); 42 | }()); 43 | 44 | /** 45 | * ============================================================================ 46 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 47 | * ============================================================================ 48 | */ 49 | 50 | (function() { 51 | var stack = new ItsyBitsyDataStructures.Stack(); 52 | 53 | stack.push(1); 54 | stack.push(2); 55 | 56 | assert.equal(stack.peek(), 2); 57 | assert.equal(stack.pop(), 2); 58 | assert.equal(stack.peek(), 1); 59 | assert.equal(stack.pop(), 1); 60 | }()); 61 | 62 | /** 63 | * ============================================================================ 64 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 65 | * ============================================================================ 66 | */ 67 | 68 | (function() { 69 | var queue = new ItsyBitsyDataStructures.Queue(); 70 | 71 | queue.enqueue(1); 72 | queue.enqueue(2); 73 | 74 | assert.equal(queue.peek(), 1); 75 | assert.equal(queue.dequeue(), 1); 76 | assert.equal(queue.peek(), 2); 77 | assert.equal(queue.dequeue(), 2); 78 | }()); 79 | 80 | /** 81 | * ============================================================================ 82 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 83 | * ============================================================================ 84 | */ 85 | 86 | (function() { 87 | var graph = new ItsyBitsyDataStructures.Graph(); 88 | 89 | graph.addNode(1); 90 | graph.addNode(2); 91 | graph.addNode(3); 92 | 93 | assert.equal(graph.find(1).value, 1); 94 | assert.equal(graph.find(2).value, 2); 95 | 96 | graph.addLine(1, 2); 97 | graph.addLine(1, 3); 98 | graph.addLine(2, 3); 99 | 100 | assert.equal(graph.find(1).lines[0].value, 2); 101 | assert.equal(graph.find(1).lines[1].value, 3); 102 | assert.equal(graph.find(2).lines[0].value, 3); 103 | }()); 104 | 105 | /** 106 | * ============================================================================ 107 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 108 | * ============================================================================ 109 | */ 110 | 111 | (function() { 112 | var linkedList = new ItsyBitsyDataStructures.LinkedList(); 113 | 114 | linkedList.add(1, 0); 115 | linkedList.add(2, 1); 116 | linkedList.add(3, 2); 117 | linkedList.add(4, 3); 118 | 119 | assert.equal(linkedList.get(0).value, 1); 120 | assert.equal(linkedList.get(1).value, 2); 121 | 122 | linkedList.remove(1); 123 | assert.equal(linkedList.get(1).value, 3); 124 | 125 | linkedList.remove(2); 126 | assert.equal(linkedList.get(1).value, 3); 127 | 128 | linkedList.remove(0); 129 | assert.equal(linkedList.get(0).value, 3); 130 | }()); 131 | 132 | /** 133 | * ============================================================================ 134 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 135 | * ============================================================================ 136 | */ 137 | 138 | (function() { 139 | var tree = new ItsyBitsyDataStructures.Tree(); 140 | 141 | tree.add(1); 142 | tree.add(2, 1); 143 | tree.add(3, 1); 144 | tree.add(4, 2); 145 | tree.add(5, 2); 146 | 147 | var traversed = []; 148 | tree.traverse(function(node) { 149 | traversed.push(node.value); 150 | }); 151 | 152 | assert.deepEqual(traversed, [1, 2, 4, 5, 3]); 153 | }()); 154 | 155 | /** 156 | * ============================================================================ 157 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 158 | * ============================================================================ 159 | */ 160 | 161 | (function() { 162 | var binarySearchTree = new ItsyBitsyDataStructures.BinarySearchTree(); 163 | 164 | // root 165 | binarySearchTree.add(4); 166 | 167 | // left side 168 | binarySearchTree.add(2); 169 | binarySearchTree.add(1); 170 | binarySearchTree.add(3); 171 | 172 | // right side 173 | binarySearchTree.add(6); 174 | binarySearchTree.add(5); 175 | binarySearchTree.add(7); 176 | 177 | assert.ok(binarySearchTree.contains(2)); 178 | assert.ok(binarySearchTree.contains(3)); 179 | assert.ok(binarySearchTree.contains(4)); 180 | 181 | // duplicate 182 | binarySearchTree.add(6); 183 | }()); 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution 4.0 International Public License 58 | 59 | By exercising the Licensed Rights (defined below), You accept and agree 60 | to be bound by the terms and conditions of this Creative Commons 61 | Attribution 4.0 International Public License ("Public License"). To the 62 | extent this Public License may be interpreted as a contract, You are 63 | granted the Licensed Rights in consideration of Your acceptance of 64 | these terms and conditions, and the Licensor grants You such rights in 65 | consideration of benefits the Licensor receives from making the 66 | Licensed Material available under these terms and conditions. 67 | 68 | 69 | Section 1 -- Definitions. 70 | 71 | a. Adapted Material means material subject to Copyright and Similar 72 | Rights that is derived from or based upon the Licensed Material 73 | and in which the Licensed Material is translated, altered, 74 | arranged, transformed, or otherwise modified in a manner requiring 75 | permission under the Copyright and Similar Rights held by the 76 | Licensor. For purposes of this Public License, where the Licensed 77 | Material is a musical work, performance, or sound recording, 78 | Adapted Material is always produced where the Licensed Material is 79 | synched in timed relation with a moving image. 80 | 81 | b. Adapter's License means the license You apply to Your Copyright 82 | and Similar Rights in Your contributions to Adapted Material in 83 | accordance with the terms and conditions of this Public License. 84 | 85 | c. Copyright and Similar Rights means copyright and/or similar rights 86 | closely related to copyright including, without limitation, 87 | performance, broadcast, sound recording, and Sui Generis Database 88 | Rights, without regard to how the rights are labeled or 89 | categorized. For purposes of this Public License, the rights 90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 91 | Rights. 92 | 93 | d. Effective Technological Measures means those measures that, in the 94 | absence of proper authority, may not be circumvented under laws 95 | fulfilling obligations under Article 11 of the WIPO Copyright 96 | Treaty adopted on December 20, 1996, and/or similar international 97 | agreements. 98 | 99 | e. Exceptions and Limitations means fair use, fair dealing, and/or 100 | any other exception or limitation to Copyright and Similar Rights 101 | that applies to Your use of the Licensed Material. 102 | 103 | f. Licensed Material means the artistic or literary work, database, 104 | or other material to which the Licensor applied this Public 105 | License. 106 | 107 | g. Licensed Rights means the rights granted to You subject to the 108 | terms and conditions of this Public License, which are limited to 109 | all Copyright and Similar Rights that apply to Your use of the 110 | Licensed Material and that the Licensor has authority to license. 111 | 112 | h. Licensor means the individual(s) or entity(ies) granting rights 113 | under this Public License. 114 | 115 | i. Share means to provide material to the public by any means or 116 | process that requires permission under the Licensed Rights, such 117 | as reproduction, public display, public performance, distribution, 118 | dissemination, communication, or importation, and to make material 119 | available to the public including in ways that members of the 120 | public may access the material from a place and at a time 121 | individually chosen by them. 122 | 123 | j. Sui Generis Database Rights means rights other than copyright 124 | resulting from Directive 96/9/EC of the European Parliament and of 125 | the Council of 11 March 1996 on the legal protection of databases, 126 | as amended and/or succeeded, as well as other essentially 127 | equivalent rights anywhere in the world. 128 | 129 | k. You means the individual or entity exercising the Licensed Rights 130 | under this Public License. Your has a corresponding meaning. 131 | 132 | 133 | Section 2 -- Scope. 134 | 135 | a. License grant. 136 | 137 | 1. Subject to the terms and conditions of this Public License, 138 | the Licensor hereby grants You a worldwide, royalty-free, 139 | non-sublicensable, non-exclusive, irrevocable license to 140 | exercise the Licensed Rights in the Licensed Material to: 141 | 142 | a. reproduce and Share the Licensed Material, in whole or 143 | in part; and 144 | 145 | b. produce, reproduce, and Share Adapted Material. 146 | 147 | 2. Exceptions and Limitations. For the avoidance of doubt, where 148 | Exceptions and Limitations apply to Your use, this Public 149 | License does not apply, and You do not need to comply with 150 | its terms and conditions. 151 | 152 | 3. Term. The term of this Public License is specified in Section 153 | 6(a). 154 | 155 | 4. Media and formats; technical modifications allowed. The 156 | Licensor authorizes You to exercise the Licensed Rights in 157 | all media and formats whether now known or hereafter created, 158 | and to make technical modifications necessary to do so. The 159 | Licensor waives and/or agrees not to assert any right or 160 | authority to forbid You from making technical modifications 161 | necessary to exercise the Licensed Rights, including 162 | technical modifications necessary to circumvent Effective 163 | Technological Measures. For purposes of this Public License, 164 | simply making modifications authorized by this Section 2(a) 165 | (4) never produces Adapted Material. 166 | 167 | 5. Downstream recipients. 168 | 169 | a. Offer from the Licensor -- Licensed Material. Every 170 | recipient of the Licensed Material automatically 171 | receives an offer from the Licensor to exercise the 172 | Licensed Rights under the terms and conditions of this 173 | Public License. 174 | 175 | b. No downstream restrictions. You may not offer or impose 176 | any additional or different terms or conditions on, or 177 | apply any Effective Technological Measures to, the 178 | Licensed Material if doing so restricts exercise of the 179 | Licensed Rights by any recipient of the Licensed 180 | Material. 181 | 182 | 6. No endorsement. Nothing in this Public License constitutes or 183 | may be construed as permission to assert or imply that You 184 | are, or that Your use of the Licensed Material is, connected 185 | with, or sponsored, endorsed, or granted official status by, 186 | the Licensor or others designated to receive attribution as 187 | provided in Section 3(a)(1)(A)(i). 188 | 189 | b. Other rights. 190 | 191 | 1. Moral rights, such as the right of integrity, are not 192 | licensed under this Public License, nor are publicity, 193 | privacy, and/or other similar personality rights; however, to 194 | the extent possible, the Licensor waives and/or agrees not to 195 | assert any such rights held by the Licensor to the limited 196 | extent necessary to allow You to exercise the Licensed 197 | Rights, but not otherwise. 198 | 199 | 2. Patent and trademark rights are not licensed under this 200 | Public License. 201 | 202 | 3. To the extent possible, the Licensor waives any right to 203 | collect royalties from You for the exercise of the Licensed 204 | Rights, whether directly or through a collecting society 205 | under any voluntary or waivable statutory or compulsory 206 | licensing scheme. In all other cases the Licensor expressly 207 | reserves any right to collect such royalties. 208 | 209 | 210 | Section 3 -- License Conditions. 211 | 212 | Your exercise of the Licensed Rights is expressly made subject to the 213 | following conditions. 214 | 215 | a. Attribution. 216 | 217 | 1. If You Share the Licensed Material (including in modified 218 | form), You must: 219 | 220 | a. retain the following if it is supplied by the Licensor 221 | with the Licensed Material: 222 | 223 | i. identification of the creator(s) of the Licensed 224 | Material and any others designated to receive 225 | attribution, in any reasonable manner requested by 226 | the Licensor (including by pseudonym if 227 | designated); 228 | 229 | ii. a copyright notice; 230 | 231 | iii. a notice that refers to this Public License; 232 | 233 | iv. a notice that refers to the disclaimer of 234 | warranties; 235 | 236 | v. a URI or hyperlink to the Licensed Material to the 237 | extent reasonably practicable; 238 | 239 | b. indicate if You modified the Licensed Material and 240 | retain an indication of any previous modifications; and 241 | 242 | c. indicate the Licensed Material is licensed under this 243 | Public License, and include the text of, or the URI or 244 | hyperlink to, this Public License. 245 | 246 | 2. You may satisfy the conditions in Section 3(a)(1) in any 247 | reasonable manner based on the medium, means, and context in 248 | which You Share the Licensed Material. For example, it may be 249 | reasonable to satisfy the conditions by providing a URI or 250 | hyperlink to a resource that includes the required 251 | information. 252 | 253 | 3. If requested by the Licensor, You must remove any of the 254 | information required by Section 3(a)(1)(A) to the extent 255 | reasonably practicable. 256 | 257 | 4. If You Share Adapted Material You produce, the Adapter's 258 | License You apply must not prevent recipients of the Adapted 259 | Material from complying with this Public License. 260 | 261 | 262 | Section 4 -- Sui Generis Database Rights. 263 | 264 | Where the Licensed Rights include Sui Generis Database Rights that 265 | apply to Your use of the Licensed Material: 266 | 267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 268 | to extract, reuse, reproduce, and Share all or a substantial 269 | portion of the contents of the database; 270 | 271 | b. if You include all or a substantial portion of the database 272 | contents in a database in which You have Sui Generis Database 273 | Rights, then the database in which You have Sui Generis Database 274 | Rights (but not its individual contents) is Adapted Material; and 275 | 276 | c. You must comply with the conditions in Section 3(a) if You Share 277 | all or a substantial portion of the contents of the database. 278 | 279 | For the avoidance of doubt, this Section 4 supplements and does not 280 | replace Your obligations under this Public License where the Licensed 281 | Rights include other Copyright and Similar Rights. 282 | 283 | 284 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 285 | 286 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 287 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 288 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 289 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 290 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 291 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 292 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 293 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 294 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 295 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 296 | 297 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 298 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 299 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 300 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 301 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 302 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 303 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 304 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 305 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 306 | 307 | c. The disclaimer of warranties and limitation of liability provided 308 | above shall be interpreted in a manner that, to the extent 309 | possible, most closely approximates an absolute disclaimer and 310 | waiver of all liability. 311 | 312 | 313 | Section 6 -- Term and Termination. 314 | 315 | a. This Public License applies for the term of the Copyright and 316 | Similar Rights licensed here. However, if You fail to comply with 317 | this Public License, then Your rights under this Public License 318 | terminate automatically. 319 | 320 | b. Where Your right to use the Licensed Material has terminated under 321 | Section 6(a), it reinstates: 322 | 323 | 1. automatically as of the date the violation is cured, provided 324 | it is cured within 30 days of Your discovery of the 325 | violation; or 326 | 327 | 2. upon express reinstatement by the Licensor. 328 | 329 | For the avoidance of doubt, this Section 6(b) does not affect any 330 | right the Licensor may have to seek remedies for Your violations 331 | of this Public License. 332 | 333 | c. For the avoidance of doubt, the Licensor may also offer the 334 | Licensed Material under separate terms or conditions or stop 335 | distributing the Licensed Material at any time; however, doing so 336 | will not terminate this Public License. 337 | 338 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 339 | License. 340 | 341 | 342 | Section 7 -- Other Terms and Conditions. 343 | 344 | a. The Licensor shall not be bound by any additional or different 345 | terms or conditions communicated by You unless expressly agreed. 346 | 347 | b. Any arrangements, understandings, or agreements regarding the 348 | Licensed Material not stated herein are separate from and 349 | independent of the terms and conditions of this Public License. 350 | 351 | 352 | Section 8 -- Interpretation. 353 | 354 | a. For the avoidance of doubt, this Public License does not, and 355 | shall not be interpreted to, reduce, limit, restrict, or impose 356 | conditions on any use of the Licensed Material that could lawfully 357 | be made without permission under this Public License. 358 | 359 | b. To the extent possible, if any provision of this Public License is 360 | deemed unenforceable, it shall be automatically reformed to the 361 | minimum extent necessary to make it enforceable. If the provision 362 | cannot be reformed, it shall be severed from this Public License 363 | without affecting the enforceability of the remaining terms and 364 | conditions. 365 | 366 | c. No term or condition of this Public License will be waived and no 367 | failure to comply consented to unless expressly agreed to by the 368 | Licensor. 369 | 370 | d. Nothing in this Public License constitutes or may be interpreted 371 | as a limitation upon, or waiver of, any privileges and immunities 372 | that apply to the Licensor or You, including from the legal 373 | processes of any jurisdiction or authority. 374 | 375 | 376 | ======================================================================= 377 | 378 | Creative Commons is not a party to its public licenses. 379 | Notwithstanding, Creative Commons may elect to apply one of its public 380 | licenses to material it publishes and in those instances will be 381 | considered the "Licensor." Except for the limited purpose of indicating 382 | that material is shared under a Creative Commons public license or as 383 | otherwise permitted by the Creative Commons policies published at 384 | creativecommons.org/policies, Creative Commons does not authorize the 385 | use of the trademark "Creative Commons" or any other trademark or logo 386 | of Creative Commons without its prior written consent including, 387 | without limitation, in connection with any unauthorized modifications 388 | to any of its public licenses or any other arrangements, 389 | understandings, or agreements concerning use of licensed material. For 390 | the avoidance of doubt, this paragraph does not form part of the public 391 | licenses. 392 | 393 | Creative Commons may be contacted at creativecommons.org. 394 | -------------------------------------------------------------------------------- /itsy-bitsy-data-structures.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * ███████████████═╗ ███████████████═╗ █████████████═╗ █████═╗ █████═╗ 5 | * ███████████████ ║ ███████████████ ║ ███████████████ ║ █████ ║ █████ ║ 6 | * ╚═══█████ ╔════╝ ╚═══█████ ╔════╝ █████ ╔═════════╝ █████ ║ █████ ║ 7 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 8 | * █████ ║ █████ ║ █████████████═╗ ███████████████ ║ 9 | * █████ ║ █████ ║ ╚█████████████═╗ ╚███████████ ╔═╝ 10 | * █████ ║ █████ ║ ╚══════█████ ║ ╚═█████ ╔══╝ 11 | * █████ ║ █████ ║ █████ ║ █████ ║ 12 | * ███████████████═╗ █████ ║ ███████████████ ║ █████ ║ 13 | * ███████████████ ║ █████ ║ █████████████ ╔═╝ █████ ║ 14 | * ╚══════════════╝ ╚════╝ ╚════════════╝ ╚════╝ 15 | * 16 | * █████████████═══╗ ███████████████═╗ ███████████████═╗ █████████████═╗ █████═╗ █████═╗ 17 | * ███████████████ ║ ███████████████ ║ ███████████████ ║ ███████████████ ║ █████ ║ █████ ║ 18 | * █████ ╔═══█████ ║ ╚═══█████ ╔════╝ ╚═══█████ ╔════╝ █████ ╔═════════╝ █████ ║ █████ ║ 19 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 20 | * █████████████ ╔═╝ █████ ║ █████ ║ █████████████═╗ ███████████████ ║ 21 | * ███████████████═╗ █████ ║ █████ ║ ╚█████████████═╗ ╚███████████ ╔═╝ 22 | * █████ ╔═══█████ ║ █████ ║ █████ ║ ╚══════█████ ║ ╚═█████ ╔══╝ 23 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 24 | * ███████████████ ║ ███████████████═╗ █████ ║ ███████████████ ║ █████ ║ 25 | * █████████████ ╔═╝ ███████████████ ║ █████ ║ █████████████ ╔═╝ █████ ║ 26 | * ╚════════════╝ ╚══════════════╝ ╚════╝ ╚════════════╝ ╚════╝ 27 | * 28 | * █████████████═══╗ ███████████═══╗ ███████████████═╗ ███████████═══╗ 29 | * ███████████████ ║ ███████████████ ║ ███████████████ ║ ███████████████ ║ 30 | * █████ ╔═══█████ ║ █████ ╔═══█████ ║ ╚═══█████ ╔════╝ █████ ╔═══█████ ║ 31 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 32 | * █████ ║ █████ ║ ███████████████ ║ █████ ║ ███████████████ ║ 33 | * █████ ║ █████ ║ ███████████████ ║ █████ ║ ███████████████ ║ 34 | * █████ ║ █████ ║ █████ ╔═══█████ ║ █████ ║ █████ ╔═══█████ ║ 35 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 36 | * ███████████████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 37 | * █████████████ ╔═╝ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 38 | * ╚════════════╝ ╚════╝ ╚════╝ ╚════╝ ╚════╝ ╚════╝ 39 | * 40 | * █████████████═╗ ███████████████═╗ █████████████═══╗ █████═╗ █████═╗ █████████████═╗ ███████████████═╗ 41 | * ███████████████ ║ ███████████████ ║ ███████████████ ║ █████ ║ █████ ║ ███████████████ ║ ███████████████ ║ 42 | * █████ ╔═════════╝ ╚═══█████ ╔════╝ █████ ╔═══█████ ║ █████ ║ █████ ║ █████ ╔═════════╝ ╚═══█████ ╔════╝ 43 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 44 | * █████████████═╗ █████ ║ █████████████ ╔═╝ █████ ║ █████ ║ █████ ║ █████ ║ 45 | * ╚█████████████═╗ █████ ║ ███████████████═╗ █████ ║ █████ ║ █████ ║ █████ ║ 46 | * ╚══════█████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 47 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 48 | * ███████████████ ║ █████ ║ █████ ║ █████ ║ ███████████████ ║ ███████████████═╗ █████ ║ 49 | * █████████████ ╔═╝ █████ ║ █████ ║ █████ ║ ╚███████████ ╔═╝ ╚█████████████ ║ █████ ║ 50 | * ╚════════════╝ ╚════╝ ╚════╝ ╚════╝ ╚══════════╝ ╚════════════╝ ╚════╝ 51 | * 52 | * █████═╗ █████═╗ █████████████═══╗ ████████████████═╗ ██████████████═╗ 53 | * █████ ║ █████ ║ ███████████████ ║ ████████████████ ║ ████████████████ ║ 54 | * █████ ║ █████ ║ █████ ╔═══█████ ║ █████ ╔══════════╝ █████ ╔══════════╝ 55 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 56 | * █████ ║ █████ ║ █████████████ ╔═╝ ████████████████═╗ ██████████████═╗ 57 | * █████ ║ █████ ║ ███████████████═╗ ████████████████ ║ ╚██████████████═╗ 58 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ╔══════════╝ ╚═══════█████ ║ 59 | * █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ █████ ║ 60 | * ███████████████ ║ █████ ║ █████ ║ ████████████████═╗ ████████████████ ║ 61 | * ╚███████████ ╔═╝ █████ ║ █████ ║ ████████████████ ║ ██████████████ ╔═╝ 62 | * ╚══════════╝ ╚════╝ ╚════╝ ╚═══════════════╝ ╚═════════════╝ 63 | * 64 | * ══════════════════════════════════════════════════════════════════════ 65 | * ████ By James Kyle (@thejameskyle) █████████████████████████████████████████ 66 | * ══════════════════════════════════════════════════════════════════════ 67 | */ 68 | 69 | /** 70 | * Today we're gonna learn all about data structures. 71 | * 72 | * "OOooooOOOooh *soo* exciting" right? 73 | * 74 | * Yeah, they definitely aren't the juiciest topic out there, but they are 75 | * important. Not just to pass computer science 101, but in order to be a 76 | * better programmer. 77 | * 78 | * Knowing your data structures can help you: 79 | * 80 | * - Manage complexity and make your programs easier to follow. 81 | * - Build high-performance, memory-efficient programs. 82 | * 83 | * I believe that the former is more important. Using the 84 | * right data structure can drastically simplify what would otherwise be 85 | * complicated logic. 86 | * 87 | * The latter is important too. If performance or memory matters then 88 | * using the right data structure is more than often essential. 89 | * 90 | * In order to learn about data structures, we're going to implement a few of 91 | * them together. Don't worry, we'll keep the code nice and short. In fact, 92 | * there are way more comments than there is code. 93 | */ 94 | 95 | /** 96 | * ============================================================================ 97 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 98 | * ============================================================================ 99 | */ 100 | 101 | /** 102 | * What are data structures? 103 | * 104 | * Essentially, they are different methods of storing and organizing data that 105 | * serve a number of different needs. 106 | * 107 | * Data can always be represented in many different ways. However, depending on 108 | * what that data is and what you need to do with it, one representation will 109 | * be a better choice than the others. 110 | * 111 | * To understand why, let's first talk a bit about algorithms. 112 | */ 113 | 114 | /*** ===================================================================== ***\ 115 | ** - ALGORITHMS ---------------------------------------------------------- ** 116 | * ========================================================================= * 117 | * * 118 | * ,--,--. ,--,--. * 119 | * ,----------. | | | | | | _____ * 120 | * |`----------'| | | | | | | | | ,------. * 121 | * | | | | | | | | ,--. | o o | |`------'| * 122 | * | | ,| +-|-+ | | +-|-+ |` | | |_____| | | * 123 | * | | ,:==| | |###|======|###| | |====#==#====#=,, | | * 124 | * | | || `| +---+ | | +---+ |' ,,=#==#====O=`` ,| | * 125 | * | | || | | | | | | ``=#==#====#=====|| | * 126 | * `----------' || | | | | | | |__| `| | * 127 | * | | ``=| |===`` `--,',--` `--,',--` /||\ `------' * 128 | ** \_/ \_/ / / \ \ / / \ \ //||\\ |_| |_| ** 129 | \*** ===================================================================== ***/ 130 | 131 | /** 132 | * Algorithms is a fancy name for step-by-step sets of operations to be 133 | * performed. 134 | * 135 | * Data structures are implemented with algorithms, and algorithms are 136 | * implemented with data structures. It's data structures and algorithms all 137 | * the way down until you reach the micro-scopic people with punch cards that 138 | * control the computer (Yeah– Intel is enslaving super tiny people. Wake up 139 | * sheeple!) 140 | * 141 | * Any given task can be implemented in an infinite number of ways. So for 142 | * common tasks there are often many different algorithms that people have come up 143 | * with. 144 | * 145 | * For example, there are an absurd number of algorithms for sorting a set of 146 | * unordered items: 147 | * 148 | * Insertion Sort, Selection Sort, Merge Sort, Bubble Sort, Heap Sort, 149 | * Quick Sort, Shell Sort, Timsort, Bucket Sort, Radix Sort, ... 150 | * 151 | * Some of these are significantly faster than others. Some use less memory. 152 | * Some are easy to implement. Some are based on assumptions about the dataset. 153 | * 154 | * Every single one of them will be better for *something*. So you'll need to 155 | * make a decision based on what your needs are and for that you'll need a way 156 | * of comparing them, a way to measure them. 157 | * 158 | * When we compare the performance of algorithms we use a rough measurement of 159 | * their average and worst-case performance using something called "Big-O". 160 | */ 161 | 162 | /*** ===================================================================== ***\ 163 | ** - BIG-O NOTATION ------------------------------------------------------ ** 164 | * ========================================================================= * 165 | * a b d * 166 | * a b O(N^2) d * 167 | * O(N!) a b O(N log N) d c * 168 | * a b d c * 169 | * a b d c O(N) * 170 | * a b d c * 171 | * a b d c * 172 | * a b d c * 173 | * ab c O(1) * 174 | * e e e e ec d e e e e e e e e * 175 | * ba c d * 176 | * ba c d f f f f f f f * 177 | ** cadf f d f f f f f O(log N) ** 178 | \*** ===================================================================== ***/ 179 | 180 | /** 181 | * Big-O Notation is a way of roughly measuring the performance of algorithms 182 | * in order to compare one against another when discussing them. 183 | * 184 | * Big-O is a mathematical notation that we borrowed in computer science to 185 | * classify algorithms by how they respond to the number (N) of items that you 186 | * give them. 187 | * 188 | * There are two primary things that you measure with Big-O: 189 | * 190 | * - **Time complexity** refers to the total count of operations an algorithm 191 | * will perform given a set of items. 192 | * 193 | * - **Space complexity** refers to the total memory an algorithm will take up 194 | * while running given a set of items. 195 | * 196 | * We measure these independently from one another because while an algorithm 197 | * may perform less operations than another, it may also take up way more 198 | * memory. Depending on what your requirements are, one may be a better choice 199 | * than the other. 200 | * 201 | * These are some common Big-O's: 202 | * 203 | * Name Notation How you feel when they show up at your party 204 | * ------------------------------------------------------------------------ 205 | * Constant O(1) AWESOME!! 206 | * Logarithmic O(log N) GREAT! 207 | * Linear O(N) OKAY. 208 | * Linearithmic O(N log N) UGH... 209 | * Polynomial O(N ^ 2) SHITTY 210 | * Exponential O(2 ^ N) HORRIBLE 211 | * Factorial O(N!) WTF 212 | * 213 | * To give you an idea of how many operations we're talking about. Let's look 214 | * at what these would equal given the (N) number of items. 215 | * 216 | * N = 5 10 20 30 217 | * ----------------------------------------------------------------------- 218 | * O(1) 1 1 1 1 219 | * O(log N) 1.6094... 2.3025... 2.9957... 3.4011... 220 | * O(N) 5 10 20 30 221 | * O(N log N) 8.0471... 23.0258... 59.9146... 102.0359... 222 | * O(N ^ 2) 25 100 400 900 223 | * O(2 ^ N) 32 1024 1,048,576 1,073,741,824 224 | * O(N!) 120 3,628,800 2,432,902,0... 265,252,859,812,191,058,636,308,480,000,000 225 | * 226 | * As you can see, even for relatively small sets of data you could do a *lot* 227 | * of extra work. 228 | * 229 | * With data structures, you can perform 4 primary types of actions: 230 | * Accessing, Searching, Inserting, and Deleting. 231 | * 232 | * It is important to note that data structures may be good at one action but 233 | * bad at another. 234 | * 235 | * Accessing Searching Inserting Deleting 236 | * ------------------------------------------------------------------------- 237 | * Array O(1) O(N) O(N) O(N) 238 | * Linked List O(N) O(N) O(1) O(1) 239 | * Binary Search Tree O(log N) O(log N) O(log N) O(log N) 240 | * 241 | * Or rather... 242 | * 243 | * Accessing Searching Inserting Deleting 244 | * ------------------------------------------------------------------------- 245 | * Array AWESOME!! OKAY OKAY OKAY 246 | * Linked List OKAY OKAY AWESOME!! AWESOME!! 247 | * Binary Search Tree GREAT! GREAT! GREAT! GREAT! 248 | * 249 | * Even further, some actions will have a different "average" performance and a 250 | * "worst case scenario" performance. 251 | * 252 | * There is no perfect data structure, and you choose one over another based on 253 | * the data that you are working with and the things you are going to do with 254 | * it. This is why it is important to know a number of different common data 255 | * structures so that you can choose from them. 256 | */ 257 | 258 | /*** ===================================================================== ***\ 259 | ** - MEMORY -------------------------------------------------------------- ** 260 | * ========================================================================= * 261 | * _.-.. * 262 | * ,'9 )\)`-.,.--. * 263 | * `-.| `. * 264 | * \, , \) * 265 | * `. )._\ (\ * 266 | * |// `-,// * 267 | * ]|| //" * 268 | ** hjw "" "" ** 269 | \*** ===================================================================== ***/ 270 | 271 | /** 272 | * A computer's memory is pretty boring, it's just a bunch of ordered slots 273 | * where you can store information. You hold onto memory addresses in order to 274 | * find information. 275 | * 276 | * Let's imagine a chunk of memory like this: 277 | * 278 | * Values: |1001|0110|1000|0100|0101|1010|0010|0001|1101|1011... 279 | * Addresses: 0 1 2 3 4 5 6 7 8 9 ... 280 | * 281 | * If you've ever wondered why things are zero-indexed in programming languages 282 | * before, it is because of the way that memory works. If you want to read the 283 | * first chunk of memory you read from 0 to 1, the second you read from 1 to 2. 284 | * So the address that you hold onto for each of those is 0 and 1 respectively. 285 | * 286 | * Your computer has much much more memory than this, and it is all just a 287 | * continuation of the pattern above. 288 | * 289 | * Memory is a bit like the wild west, every program running on your machine is 290 | * stored within this same *physical* data structure. Without layers of 291 | * abstraction over it, it would be extremely difficult to use. 292 | * 293 | * But these abstractions serve two additional purposes: 294 | * 295 | * - Storing data in memory in a way that is more efficient and/or faster to 296 | * work with. 297 | * - Storing data in memory in a way that makes it easier to use. 298 | */ 299 | 300 | /*** ===================================================================== ***\ 301 | ** - LISTS --------------------------------------------------------------- ** 302 | * ========================================================================= * 303 | * * _______________________ * 304 | * ()=(_______________________)=() * * 305 | * * | | * 306 | * | ~ ~~~~~~~~~~~~~ | * * * 307 | * * | | * 308 | * * | ~ ~~~~~~~~~~~~~ | * * 309 | * | | * 310 | * | ~ ~~~~~~~~~~~~~ | * * 311 | * * | | * 312 | * * |_____________________| * * * 313 | * ()=(_______________________)=() * 314 | ** ** 315 | \*** ===================================================================== ***/ 316 | 317 | /** 318 | * To demonstrate the raw interaction between memory and a data structure we're 319 | * going to first implement a list. 320 | * 321 | * A list is a representation of an ordered sequence of values where the same 322 | * value may appear many times. 323 | */ 324 | 325 | class List { 326 | 327 | /** 328 | * We start with an empty block of memory which we are going to represent 329 | * with a normal JavaScript array and we'll store the length of the list. 330 | * 331 | * Note that we want to store the length separately because in real life the 332 | * "memory" doesn't have a length you can read from. 333 | */ 334 | 335 | constructor() { 336 | this.memory = []; 337 | this.length = 0; 338 | } 339 | 340 | /** 341 | * First we need a way to retrieve data from our list. 342 | * 343 | * With a plain list, you have very fast memory access because you keep track 344 | * of the address directly. 345 | * 346 | * List access is constant O(1) - "AWESOME!!" 347 | */ 348 | 349 | get(address) { 350 | return this.memory[address]; 351 | } 352 | 353 | /** 354 | * Because lists have an order you can insert stuff at the start, middle, 355 | * or end of them. 356 | * 357 | * For our implementation we're going to focus on adding and removing values 358 | * at the start or end of our list with these four methods: 359 | * 360 | * - Push - Add value to the end 361 | * - Pop - Remove value from the end 362 | * - Unshift - Add value to the start 363 | * - Shift - Remove value from the start 364 | */ 365 | 366 | /* 367 | * Starting with "push" we need a way to add items to the end of the list. 368 | * 369 | * It is as simple as adding a value in the address after the end of our 370 | * list. Because we store the length this is easy to calculate. We just add 371 | * the value and increment our length. 372 | * 373 | * Pushing an item to the end of a list is constant O(1) - "AWESOME!!" 374 | */ 375 | 376 | push(value) { 377 | this.memory[this.length] = value; 378 | this.length++; 379 | } 380 | 381 | /** 382 | * Next we need a way to "pop" items off of the end of our list. 383 | * 384 | * Similar to push all we need to do is remove the value at the address at 385 | * the end of our list. Then just decrement length. 386 | * 387 | * Popping an item from the end of a list is constant O(1) - "AWESOME!!" 388 | */ 389 | 390 | pop() { 391 | // Don't do anything if we don't have any items. 392 | if (this.length === 0) return; 393 | 394 | // Get the last value, stop storing it, and return it. 395 | var lastAddress = this.length - 1; 396 | var value = this.memory[lastAddress]; 397 | delete this.memory[lastAddress]; 398 | this.length--; 399 | 400 | // Also return the value so it can be used. 401 | return value; 402 | } 403 | 404 | /** 405 | * "push" and "pop" both operate on the end of a list, and overall are pretty 406 | * simple operations because they don't need to be concerned with the rest of 407 | * the list. 408 | * 409 | * Let's see what happens when we operate on the begining of the list with 410 | * "unshift" and "shift". 411 | */ 412 | 413 | /** 414 | * In order to add a new item at the beginning of our list, we need to make 415 | * room for our value at the start by sliding all of the values over by one. 416 | * 417 | * [a, b, c, d, e] 418 | * 0 1 2 3 4 419 | * ⬊ ⬊ ⬊ ⬊ ⬊ 420 | * 1 2 3 4 5 421 | * [x, a, b, c, d, e] 422 | * 423 | * In order to slide all of the items over we need to iterate over each one 424 | * moving the prev value over. 425 | * 426 | * Because we have to iterate over every single item in the list: 427 | * 428 | * Unshifting an item to the start of a list is linear O(N) - "OKAY." 429 | */ 430 | 431 | unshift(value) { 432 | // Store the value we are going to add to the start. 433 | var previous = value; 434 | 435 | // Iterate through each item... 436 | for (var address = 0; address < this.length; address++) { 437 | // replacing the "current" value with the "previous" value and storing the 438 | // "current" value for the next iteration. 439 | var current = this.memory[address]; 440 | this.memory[address] = previous; 441 | previous = current; 442 | } 443 | 444 | // Add the last item in a new position at the end of the list. 445 | this.memory[this.length] = previous; 446 | this.length++; 447 | } 448 | 449 | /** 450 | * Finally, we need to write a shift function to move in the opposite 451 | * direction. 452 | * 453 | * We delete the first value and then slide through every single item in the 454 | * list to move it down one address. 455 | * 456 | * [x, a, b, c, d, e] 457 | * 1 2 3 4 5 458 | * ⬋ ⬋ ⬋ ⬋ ⬋ 459 | * 0 1 2 3 4 460 | * [a, b, c, d, e] 461 | * 462 | * Shifting an item from the start of a list is linear O(N) - "OKAY." 463 | */ 464 | 465 | shift() { 466 | // Don't do anything if we don't have any items. 467 | if (this.length === 0) return; 468 | 469 | var value = this.memory[0]; 470 | 471 | // Iterate through each item... 472 | for (var address = 0; address < this.length; address++) { 473 | // and replace them with the next item in the list. 474 | this.memory[address] = this.memory[address + 1]; 475 | } 476 | 477 | // Delete the last item since it is now in the previous address. 478 | delete this.memory[this.length - 1]; 479 | this.length--; 480 | 481 | return value; 482 | } 483 | } 484 | 485 | /** 486 | * Lists are great for fast access and dealing with items at the end. However, 487 | * as we've seen it isn't great at dealing with items not at the end of the 488 | * list and we have to manually hold onto memory addresses. 489 | * 490 | * So let's take a look at a different data structure and how it deals with 491 | * adding, accessing, and removing values without needing to know memory 492 | * addresses. 493 | */ 494 | 495 | /*** ===================================================================== ***\ 496 | ** - HASH TABLES --------------------------------------------------------- ** 497 | * ========================================================================= * 498 | * ((\ * 499 | * ( _ ,-_ \ \ * 500 | * ) / \/ \ \ \ \ * 501 | * ( /)| \/\ \ \| | .'---------------------'. * 502 | * `~()_______)___)\ \ \ \ \ | .' '. * 503 | * |)\ ) `' | | | .'-----------------------------'. * 504 | * / /, | '...............................' * 505 | * ejm | | / \ _____________________ / * 506 | * \ / | |_) (_| | * 507 | * \ / | | | | * 508 | * ) / | | | | * 509 | ** / / (___) (___) ** 510 | \*** ===================================================================== ***/ 511 | 512 | /** 513 | * A hash table is a data structure that's *unordered*. Instead we have "keys" and "values" where we 514 | * computed an address in memory using the key. 515 | * 516 | * The basic idea is that we have keys that are "hashable" (which we'll get to 517 | * in a second) and can be used to add, access, and remove from memory very 518 | * efficiently. 519 | * 520 | * var hashTable = new HashTable(); 521 | * 522 | * hashTable.set('myKey', 'myValue'); 523 | * hashTable.get('myKey'); // >> 'myValue' 524 | */ 525 | 526 | class HashTable { 527 | 528 | /** 529 | * Again we're going to use a plain JavaScript array to represent our memory. 530 | */ 531 | 532 | constructor() { 533 | this.memory = []; 534 | } 535 | 536 | /** 537 | * In order to store key-value pairs in memory from our hash table we need a 538 | * way to take the key and turn it into an address. We do this through an 539 | * operation known as "hashing". 540 | * 541 | * Basically it takes a key and serializes it into a unique number for that 542 | * key. 543 | * 544 | * hashKey("abc") => 96354 545 | * hashKey("xyz") => 119193 546 | * 547 | * You have to be careful though, if you had a really big key you don't want 548 | * to match it to a memory address that does not exist. 549 | * 550 | * So the hashing algorithm needs to limit the size, which means that there 551 | * are a limited number of addresses for an unlimited number of values. 552 | * 553 | * The result is that you can end up with collisions. Places where two keys 554 | * get turned into the same address. 555 | * 556 | * Any real world hash table implementation would have to deal with this, 557 | * however we are just going to glaze over it and pretend that doesn't happen. 558 | */ 559 | 560 | /** 561 | * Let's setup our "hashKey" function. 562 | * 563 | * Don't worry about understanding the logic of this function, just know that 564 | * it accepts a string and outputs a (mostly) unique address that we will use 565 | * in all of our other functions. 566 | */ 567 | 568 | hashKey(key) { 569 | var hash = 0; 570 | for (var index = 0; index < key.length; index++) { 571 | // Oh look– magic. 572 | var code = key.charCodeAt(index); 573 | hash = ((hash << 5) - hash) + code | 0; 574 | } 575 | return hash; 576 | } 577 | 578 | /** 579 | * Next, let's define our "get" function so we have a way of accessing values 580 | * by their key. 581 | * 582 | * HashTable access is constant O(1) - "AWESOME!!" 583 | */ 584 | 585 | get(key) { 586 | // We start by turning our key into an address. 587 | var address = this.hashKey(key); 588 | // Then we simply return whatever is at that address. 589 | return this.memory[address]; 590 | } 591 | 592 | /** 593 | * We also need a way of adding data before we access it, so we will create 594 | * a "set" function that inserts values. 595 | * 596 | * HashTable setting is constant O(1) - "AWESOME!!" 597 | */ 598 | 599 | set(key, value) { 600 | // Again we start by turning the key into an address. 601 | var address = this.hashKey(key); 602 | // Then just set the value at that address. 603 | this.memory[address] = value; 604 | } 605 | 606 | /** 607 | * Finally we just need a way to remove items from our hash table. 608 | * 609 | * HashTable deletion is constant O(1) - "AWESOME!!" 610 | */ 611 | 612 | remove(key) { 613 | // As always, we hash the key to get an address. 614 | var address = this.hashKey(key); 615 | // Then, if it exists, we `delete` it. 616 | if (this.memory[address]) { 617 | delete this.memory[address]; 618 | } 619 | } 620 | } 621 | 622 | /** 623 | * ============================================================================ 624 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 625 | * ============================================================================ 626 | */ 627 | 628 | /** 629 | * From this point going forward we are going to stop interacting directly with 630 | * memory as the rest of these data structures start to be implemented with 631 | * other data structures. 632 | * 633 | * These data structures focus on doing two things: 634 | * 635 | * - Organizing data based on how it is used 636 | * - Abstracting away implementation details 637 | * 638 | * These data structures focus on creating an organization that makes sense for 639 | * various types of programs. They insert a language that allows you discuss 640 | * more complicated logic. All of this while abstracting away implementation 641 | * details so that their implementation can change to be made faster. 642 | */ 643 | 644 | /*** ===================================================================== ***\ 645 | ** - STACKS -------------------------------------------------------------- ** 646 | * ========================================================================= * 647 | * _ . - - -- .. _ * 648 | * |||| .-' /```\ `'-_ /| * 649 | * |||| ( /`` \___/ ```\ ) | | * 650 | * \__/ |`"-//..__ __..\\-"`| | | * 651 | * || |`"||...__`````__...||"`| | | * 652 | * || |`"||...__`````__...||"`| \ | * 653 | * || _,.--|`"||...__`````__...||"`|--.,_ || * 654 | * || .'` |`"||...__`````__...||"`| `'. || * 655 | * || '. `/ |...__`````__...| \ .' || * 656 | * || `'-..__ `` ````` `` __..-'` || * 657 | * `""---,,,_______,,,---""` * 658 | ** ** 659 | \*** ===================================================================== ***/ 660 | 661 | /** 662 | * Stacks are similar to lists in that they have an order, but they limit you 663 | * to only pushing and popping values at the end of the list, Which as we saw 664 | * before are very fast operations when mapping directly to memory. 665 | * 666 | * However, Stacks can also be implemented with other data structures in order 667 | * to add functionality to them. 668 | * 669 | * The most common usage of stacks is places where you have one process adding 670 | * items to the stack, and other process removing them from the end– 671 | * prioritizing items added most recently. 672 | */ 673 | 674 | class Stack { 675 | 676 | /** 677 | * We're going to again be backed by a JavaScript array, but this time it 678 | * represents a list like we implemented before rather than memory. 679 | */ 680 | 681 | constructor() { 682 | this.list = []; 683 | this.length = 0; 684 | } 685 | 686 | /** 687 | * We're going to implement two of the functions from lists "push" and "pop" 688 | * which are going to be identical in terms of functionality. 689 | */ 690 | 691 | /** 692 | * Push to add items to the top of the stack. 693 | */ 694 | 695 | push(value) { 696 | this.length++; 697 | this.list.push(value); 698 | } 699 | 700 | /** 701 | * And pop to remove items from the top of the stack. 702 | */ 703 | 704 | pop() { 705 | // Don't do anything if we don't have any items. 706 | if (this.length === 0) return; 707 | 708 | // Pop the last item off the end of the list and return the value. 709 | this.length--; 710 | return this.list.pop(); 711 | } 712 | 713 | /** 714 | * We're also going to add a function in order to view the item at the top of 715 | * the stack without removing it from the stack. 716 | */ 717 | 718 | peek() { 719 | // Return the last item in "items" without removing it. 720 | return this.list[this.length - 1]; 721 | } 722 | } 723 | 724 | /*** ===================================================================== ***\ 725 | ** - QUEUES -------------------------------------------------------------- ** 726 | * ========================================================================= * 727 | * /:""| ,@@@@@@. * 728 | * |: oo|_ ,@@@@@`oo * 729 | * C _) @@@@C _) * 730 | * ) / "@@@@ '= * 731 | * /`\\ ```)/ * 732 | * || | | /`\\ * 733 | * || | | || | \ * 734 | * ||_| | || | / * 735 | * \( ) | ||_| | * 736 | * |~~~`-`~~~| |))) | * 737 | * (_) | | (_) |~~~/ (_) * 738 | * | |`""....__ __....""`| |`""...._|| / __....""`| | * 739 | * | |`""....__`````__....""`| |`""....__`````__....""`| | * 740 | * | | | ||``` | | ||`|`` | | * 741 | * | | |_||__ | | ||_|__ | | * 742 | * ,| |, jgs (____)) ,| |, ((;:;:) ,| |, * 743 | ** `---` `---` `---` ** 744 | \*** ===================================================================== ***/ 745 | 746 | /** 747 | * Next we're going to build a queue which is complimentary to stacks. The 748 | * difference is that this time you remove items from the start of the queue 749 | * rather than the end. Removing the oldest items rather than the most recent. 750 | * 751 | * Again, because this limits the amount of functionality, there are many 752 | * different ways of implementing it. A good way might be to use a linked list 753 | * which we will see later. 754 | */ 755 | 756 | class Queue { 757 | 758 | /** 759 | * Again, our queue is using a JavaScript array as a list rather than memory. 760 | */ 761 | 762 | constructor() { 763 | this.list = []; 764 | this.length = 0; 765 | } 766 | 767 | /** 768 | * Similar to stacks we're going to define two functions for adding and 769 | * removing items from the queue. The first is "enqueue". 770 | * 771 | * This will push values to the end of the list. 772 | */ 773 | 774 | enqueue(value) { 775 | this.length++; 776 | this.list.push(value); 777 | } 778 | 779 | /** 780 | * Next is "dequeue", instead of removing the item from the end of the list, 781 | * we're going to remove it from the start. 782 | */ 783 | 784 | dequeue() { 785 | // Don't do anything if we don't have any items. 786 | if (this.length === 0) return; 787 | 788 | // Shift the first item off the start of the list and return the value. 789 | this.length--; 790 | return this.list.shift(); 791 | } 792 | 793 | /** 794 | * Same as stacks we're going to define a "peek" function for getting the next 795 | * value without removing it from the stack. 796 | */ 797 | 798 | peek() { 799 | return this.list[0]; 800 | } 801 | } 802 | 803 | /** 804 | * The important thing to note here is that because we used a list to back our 805 | * queue it inherits the performance of "shift" which is linear O(N) "OKAY." 806 | * 807 | * Later we'll see linked lists that will allow us to implement a much faster 808 | * Queue. 809 | */ 810 | 811 | /** 812 | * ============================================================================ 813 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 814 | * ============================================================================ 815 | */ 816 | 817 | /** 818 | * From this point forward we're going to start dealing with data structures 819 | * where the values of the data structure reference one another. 820 | * 821 | * +- Data Structure ---------------------------------------+ 822 | * | +- Item A ---------------+ +- Item B ---------------+ | 823 | * | | Value: 1 | | Value: 2 | | 824 | * | | Reference to: (Item B) | | Reference to: (Item A) | | 825 | * | +------------------------+ +------------------------+ | 826 | * +--------------------------------------------------------+ 827 | * 828 | * The values inside the data structure become their own mini data structures 829 | * in that they contain a value along with additional information including 830 | * references to other items within the overall data structure. 831 | * 832 | * You'll see what I mean by this in a second. 833 | */ 834 | 835 | /*** ===================================================================== ***\ 836 | ** - GRAPHS -------------------------------------------------------------- ** 837 | * ========================================================================= * 838 | * * 839 | * | RICK ASTLEY'S NEVER GONNA... * 840 | * | +-+ * 841 | * | +-+ |-| [^] - GIVE YOU UP * 842 | * | |^| |-| +-+ [-] - LET YOU DOWN * 843 | * | |^| |-| +-+ |*| [/] - RUN AROUND AND DESERT YOU * 844 | * | |^| |-| +-+ |\| |*| [\] - MAKE YOU CRY * 845 | * | |^| |-| |/| |\| +-+ |*| [.] - SAY GOODBYE * 846 | * | |^| |-| |/| |\| |.| |*| [*] - TELL A LIE AND HURT YOU * 847 | * | |^| |-| |/| |\| |.| |*| * 848 | * +-------------------------------- * 849 | ** ** 850 | \*** ===================================================================== ***/ 851 | 852 | /** 853 | * Contrary to the ascii art above, a graph is not a visual chart of some sort. 854 | * 855 | * Instead imagine it like this: 856 | * 857 | * A –→ B ←–––– C → D ↔ E 858 | * ↑ ↕ ↙ ↑ ↘ 859 | * F –→ G → H ← I ––––→ J 860 | * ↓ ↘ ↑ 861 | * K L 862 | * 863 | * We have a bunch of "nodes" (A, B, C, D, ...) that are connected with lines. 864 | * 865 | * These nodes are going to look like this: 866 | * 867 | * Node { 868 | * value: ..., 869 | * lines: [(Node), (Node), ...] 870 | * } 871 | * 872 | * The entire graph will look like this: 873 | * 874 | * Graph { 875 | * nodes: [ 876 | * Node {...}, 877 | * Node {...}, 878 | * ... 879 | * ] 880 | * } 881 | */ 882 | 883 | class Graph { 884 | 885 | /** 886 | * We'll hold onto all of our nodes in a regular JavaScript array. Not 887 | * because there is any particular order to the nodes but because we need a 888 | * way to store references to everything. 889 | */ 890 | 891 | constructor() { 892 | this.nodes = []; 893 | } 894 | 895 | /** 896 | * We can start to add values to our graph by creating nodes without any 897 | * lines. 898 | */ 899 | 900 | addNode(value) { 901 | this.nodes.push({ 902 | value: value, 903 | lines: [] 904 | }); 905 | } 906 | 907 | /** 908 | * Next we need to be able to lookup nodes in the graph. Most of the time 909 | * you'd have another data structure on top of a graph in order to make 910 | * searching faster. 911 | * 912 | * But for our case we're simply going to search through all of nodes to find 913 | * the one with the matching value. This is a slower option, but it works for 914 | * now. 915 | */ 916 | 917 | find(value) { 918 | return this.nodes.find(function(node) { 919 | return node.value === value; 920 | }); 921 | } 922 | 923 | /** 924 | * Next we can connect two nodes by making a "line" from one to the other. 925 | */ 926 | 927 | addLine(startValue, endValue) { 928 | // Find the nodes for each value. 929 | var startNode = this.find(startValue); 930 | var endNode = this.find(endValue); 931 | 932 | // Freak out if we didn't find one or the other. 933 | if (!startNode || !endNode) { 934 | throw new Error('Both nodes need to exist'); 935 | } 936 | 937 | // And add a reference to the endNode from the startNode. 938 | startNode.lines.push(endNode); 939 | } 940 | } 941 | 942 | /** 943 | * Finally you can use a graph like this: 944 | * 945 | * var graph = new Graph(); 946 | * graph.addNode(1); 947 | * graph.addNode(2); 948 | * graph.addLine(1, 2); 949 | * var two = graph.find(1).lines[0]; 950 | * 951 | * This might seem like a lot of work to do very little, but it's actually a 952 | * quite powerful pattern, especially for finding sanity in complex programs. 953 | * 954 | * They do this by optimizing for the connections between data rather than 955 | * operating on the data itself. Once you have one node in the graph, it's 956 | * extremely simple to find all the related items in the graph. 957 | * 958 | * Tons of things can be represented this way, users with friends, the 800 959 | * transitive dependencies in a node_modules folder, the internet itself is a 960 | * graph of webpages connected together by links. 961 | */ 962 | 963 | /*** ===================================================================== ***\ 964 | ** - LINKED LISTS -------------------------------------------------------- ** 965 | * ========================================================================= * 966 | * _______________________ * 967 | * ()=(_______________________)=() ,-----------------,_ * 968 | * | | ," ", * 969 | * | ~ ~~~~~~~~~~~~~ | ,' ,---------------, `, * 970 | * | ,----------------------------, ,----------- * 971 | * | ~ ~~~~~~~~ | | | * 972 | * | `----------------------------' `----------- * 973 | * | ~ ~~~~~~~~~~~~~ | `, `----------------' ,' * 974 | * | | `, ,' * 975 | * |_____________________| `------------------' * 976 | * ()=(_______________________)=() * 977 | ** ** 978 | \*** ===================================================================== ***/ 979 | 980 | /** 981 | * Next we're going to see how a graph-like structure can help optimize ordered 982 | * lists of data. 983 | * 984 | * Linked lists are a very common data structure that is often used to 985 | * implement other data structures because of its ability to efficiently add 986 | * items to the start, middle, and end. 987 | * 988 | * The basic idea of a linked list is similar to a graph. You have nodes that 989 | * point to other nodes. They look sorta like this: 990 | * 991 | * 1 -> 2 -> 3 -> 4 -> 5 992 | * 993 | * Visualizing them as a JSON-like structure looks like this: 994 | * 995 | * { 996 | * value: 1, 997 | * next: { 998 | * value: 2, 999 | * next: { 1000 | * value: 3, 1001 | * next: {...} 1002 | * } 1003 | * } 1004 | * } 1005 | */ 1006 | 1007 | class LinkedList { 1008 | 1009 | /** 1010 | * Unlike a graph, a linked list has a single node that starts off the entire 1011 | * chain. This is known as the "head" of the linked list. 1012 | * 1013 | * We're also going to track the length. 1014 | */ 1015 | 1016 | constructor() { 1017 | this.head = null; 1018 | this.length = 0; 1019 | } 1020 | 1021 | /** 1022 | * First we need a way to retrieve a value in a given position. 1023 | * 1024 | * This works differently than normal lists as we can't just jump to the 1025 | * correct position. Instead we need to move through the individual nodes. 1026 | */ 1027 | 1028 | get(position) { 1029 | // Start with the head of the list. 1030 | var current = this.head; 1031 | 1032 | // Slide through all of the items using node.next until we reach the 1033 | // specified position. 1034 | for (var index = 0; index < position; index++) { 1035 | current = current.next; 1036 | } 1037 | 1038 | // Return the node we found. 1039 | return current; 1040 | } 1041 | 1042 | /** 1043 | * Next we need a way to add nodes to the specified position. 1044 | * 1045 | * We're going for a generic add method that accepts a value and a position. 1046 | */ 1047 | 1048 | add(value, position) { 1049 | // First create a node to hold our value. 1050 | var node = { 1051 | value: value, 1052 | next: null 1053 | }; 1054 | 1055 | // We need to have a special case for nodes being inserted at the head. 1056 | // We'll set the "next" field to the current head and then replace it with 1057 | // our new node. 1058 | if (position === 0) { 1059 | node.next = this.head; 1060 | this.head = node; 1061 | 1062 | // If we're adding a node in any other position we need to splice it in 1063 | // between the current node and the previous node. 1064 | } else { 1065 | // First, find the previous node and the current node. 1066 | var prev = this.get(position - 1); 1067 | var current = prev.next; 1068 | // Then insert the new node in between them by setting its "next" field 1069 | // to the current node and updating the previous node's "next" field to 1070 | // the new one. 1071 | node.next = current; 1072 | prev.next = node; 1073 | } 1074 | 1075 | // Finally just increment the length. 1076 | this.length++; 1077 | } 1078 | 1079 | /** 1080 | * The last method we need is a remove method. We're just going to look up a 1081 | * node by its position and splice it out of the chain. 1082 | */ 1083 | 1084 | remove(position) { 1085 | // If we're removing the first node we simply need to set the head to the 1086 | // next node in the chain 1087 | if (position === 0) { 1088 | this.head = this.head.next; 1089 | 1090 | // For any other position we need to look up the previous node and set it 1091 | // to the node after the current position. 1092 | } else { 1093 | var prev = this.get(position - 1); 1094 | prev.next = prev.next.next; 1095 | } 1096 | 1097 | // Then we just decrement the length. 1098 | this.length--; 1099 | } 1100 | } 1101 | 1102 | /** 1103 | * ============================================================================ 1104 | * ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' 1105 | * ============================================================================ 1106 | */ 1107 | 1108 | /** 1109 | * The remaining two data structures we are going to cover are both in the 1110 | * "tree" family. 1111 | * 1112 | * Much like real life, there are many different types of tree data structures. 1113 | * 1114 | * Binary Trees: 1115 | * AA Tree, AVL Tree, Binary Search Tree, Binary Tree, Cartesian Tree, 1116 | * left child/right sibling tree, order statistic tree, Pagoda, ... 1117 | * 1118 | * B Trees: 1119 | * B Tree, B+ Tree, B* Tree, B Sharp Tree, Dancing Tree, 2-3 Tree, ... 1120 | * 1121 | * Heaps: 1122 | * Heap, Binary Heap, Weak Heap, Binomial Heap, Fibonacci Heap, Leonardo 1123 | * Heap, 2-3 Heap, Soft Heap, Pairing Heap, Leftist Heap, Treap, ... 1124 | * 1125 | * Trees: 1126 | * Trie, Radix Tree, Suffix Tree, Suffix Array, FM-index, B-trie, ... 1127 | * 1128 | * Multi-way Trees: 1129 | * Ternary Tree, K-ary tree, And-or tree, (a,b)-tree, Link/Cut Tree, ... 1130 | * 1131 | * Space Partitioning Trees: 1132 | * Segment Tree, Interval Tree, Range Tree, Bin, Kd Tree, Quadtree, 1133 | * Octree, Z-Order, UB-Tree, R-Tree, X-Tree, Metric Tree, Cover Tree, ... 1134 | * 1135 | * Application-Specific Trees: 1136 | * Abstract Syntax Tree, Parse Tree, Decision Tree, Minimax Tree, ... 1137 | * 1138 | * Little did you know you'd be studying dendrology today... and thats not even 1139 | * all of them. But don't let any of this scare you, most of those don't matter 1140 | * at all. There were just a lot of Computer Science PhDs who had something to 1141 | * prove. 1142 | * 1143 | * Trees are much like graphs or linked lists except they are "unidirectional". 1144 | * All this means is that they can't have loops of references. 1145 | * 1146 | * Tree: Not a Tree: 1147 | * 1148 | * A A 1149 | * ↙ ↘ ↗ ↘ 1150 | * B C B ←–––– C 1151 | * 1152 | * If you can draw a loop between connected nodes in a tree... well, you don't 1153 | * have a tree. 1154 | * 1155 | * Trees have many different uses, they can be used to optimize searching or 1156 | * sorting. They can organize programs better. They can give you a 1157 | * representation that is easier to work with. 1158 | */ 1159 | 1160 | /*** ===================================================================== ***\ 1161 | ** - TREES --------------------------------------------------------------- ** 1162 | * ========================================================================= * 1163 | * ccee88oo \ | / * 1164 | * C8O8O8Q8PoOb o8oo '-.;;;.-, ooooO8O8QOb o8bDbo * 1165 | * dOB69QO8PdUOpugoO9bD -==;;;;;==-aadOB69QO8PdUOpugoO9bD * 1166 | * CgggbU8OU qOp qOdoUOdcb .-';;;'-. CgggOU ddqOp qOdoUOdcb * 1167 | * 6OuU /p u gcoUodpP / | \ jgs ooSec cdac pdadfoof * 1168 | * \\\// /douUP ' \\\d\\\dp/pddoo * 1169 | * \\\//// \\ \\//// * 1170 | * |||/\ \\/// * 1171 | * |||\/ |||| * 1172 | * ||||| /||| * 1173 | ** .............//||||\.......................//|||\\..................... ** 1174 | \*** ===================================================================== ***/ 1175 | 1176 | /** 1177 | * We'll start off with an extremely simple tree structure. It doesn't have any 1178 | * special rules to it and looks someting like this: 1179 | * 1180 | * Tree { 1181 | * root: { 1182 | * value: 1, 1183 | * children: [{ 1184 | * value: 2, 1185 | * children: [...] 1186 | * }, { 1187 | * value: 3, 1188 | * children: [...] 1189 | * }] 1190 | * } 1191 | * } 1192 | */ 1193 | 1194 | class Tree { 1195 | 1196 | /** 1197 | * The tree has to start with a single parent, the "root" of the tree. 1198 | */ 1199 | 1200 | constructor() { 1201 | this.root = null; 1202 | } 1203 | 1204 | /** 1205 | * We need a way to traverse our tree and call a function on each node in the 1206 | * tree. 1207 | */ 1208 | 1209 | traverse(callback) { 1210 | // We'll define a walk function that we can call recursively on every node 1211 | // in the tree. 1212 | function walk(node) { 1213 | // First call the callback on the node. 1214 | callback(node); 1215 | // Then recursively call the walk function on all of its children. 1216 | node.children.forEach(walk); 1217 | } 1218 | 1219 | // Now kick the traversal process off. 1220 | walk(this.root); 1221 | } 1222 | 1223 | /** 1224 | * Next we need a way to add nodes to our tree. 1225 | */ 1226 | 1227 | add(value, parentValue) { 1228 | var newNode = { 1229 | value: value, 1230 | children: [] 1231 | }; 1232 | 1233 | // If there is no root, just set it to the new node. 1234 | if (this.root === null) { 1235 | this.root = newNode; 1236 | return; 1237 | } 1238 | 1239 | // Otherwise traverse the entire tree and find a node with a matching value 1240 | // and add the new node to its children. 1241 | this.traverse(function(node) { 1242 | if (node.value === parentValue) { 1243 | node.children.push(newNode); 1244 | } 1245 | }); 1246 | } 1247 | } 1248 | 1249 | /** 1250 | * This is one of the most basic trees you could have and is probably only 1251 | * useful if the data you are representing actually resembles a tree. 1252 | * 1253 | * But with some extra rules a tree can serve a lot of different purposes. 1254 | */ 1255 | 1256 | /*** ===================================================================== ***\ 1257 | ** - BINARY SEARCH TREES ------------------------------------------------- ** 1258 | * ========================================================================= * 1259 | * 0 0 1 0 1 0 0 1 0 1 1 1 0 1 ,@@@@@@@@@@@@@@, 0 0 1 0 1 0 0 1 0 1 1 1 0 * 1260 | * 0 1 0 1 0 1 0 1 1 0 1 1 0 @@` '@@ 0 1 0 1 0 1 1 0 1 0 1 0 * 1261 | * 1 1 0 0 0 1 0 0 1 1 1 0 @@` 8O8PoOb o8o '@@ 0 0 1 0 0 1 0 0 1 1 1 * 1262 | * 0 0 1 1 0 1 0 1 0 0 0 @@ dOB69QO8PdUgoO9bD @@ 1 0 1 1 0 1 0 1 0 0 * 1263 | * ===================== @@ CgbU8OU qOp qOdOdcb @@ 0 1 1 0 1 0 1 0 1 0 * 1264 | * @@ 6OU /p u gcoUpP @@ 1 0 1 1 0 1 0 0 1 1 * 1265 | * ===================== @@ \\// /doP @@ 0 1 1 0 0 1 0 0 1 0 * 1266 | * 1 1 0 0 1 1 0 1 1 0 0 @@ \\// @@ 1 0 1 0 0 1 1 0 1 1 * 1267 | * 0 1 1 0 1 0 1 1 0 1 1 0 @@, ||| ,@@ 0 1 1 0 1 1 0 0 1 0 1 * 1268 | * 1 0 1 0 1 1 0 0 1 0 0 1 0 @@, //|\ ,@@ 0 1 0 1 0 1 1 0 0 1 1 0 * 1269 | ** 1 0 1 0 0 1 1 0 1 0 1 0 1 `@@@@@@@@@@@@@@' 0 1 1 1 0 0 1 0 1 0 1 1 ** 1270 | \*** ===================================================================== ***/ 1271 | 1272 | /** 1273 | * Binary search trees are a fairly common form of tree for their ability to 1274 | * efficiently access, search, insert, and delete values all while keeping them 1275 | * in a sorted order. 1276 | * 1277 | * Imagine taking a sequence of numbers: 1278 | * 1279 | * 1 2 3 4 5 6 7 1280 | * 1281 | * And turning it into a tree starting from the center. 1282 | * 1283 | * 4 1284 | * / \ 1285 | * 2 6 1286 | * / \ / \ 1287 | * 1 3 5 7 1288 | * -^--^--^--^--^--^--^- 1289 | * 1 2 3 4 5 6 7 1290 | * 1291 | * This is how a binary tree works. Each node can have two children: 1292 | * 1293 | * - Left: Less than parent node's value. 1294 | * - Right: Greater than parent node's value. 1295 | * 1296 | * > Note: In order to make this work all values must be unique in the tree. 1297 | * 1298 | * This makes the traversal to find a value very efficient. Say we're trying to 1299 | * find the number 5 in our tree: 1300 | * 1301 | * (4) <--- 5 > 4, so move right. 1302 | * / \ 1303 | * 2 (6) <--- 5 < 6, so move left. 1304 | * / \ / \ 1305 | * 1 3 (5) 7 <--- We've reached 5! 1306 | * 1307 | * Notice how we only had to do 3 checks to reach the number 5. If we were to 1308 | * expand this tree to 1000 items. We'd go: 1309 | * 1310 | * 500 -> 250 -> 125 -> 62 -> 31 -> 15 -> 7 -> 3 -> 4 -> 5 1311 | * 1312 | * Only 10 checks for 1000 items! 1313 | * 1314 | * The other important thing about binary search trees is that they are similar 1315 | * to linked lists in the sense that you only need to update the immediately 1316 | * surrounding items when adding or removing a value. 1317 | */ 1318 | 1319 | class BinarySearchTree { 1320 | 1321 | /** 1322 | * Same as the previous Tree, we need to have a "root" of the binary search 1323 | * tree. 1324 | */ 1325 | 1326 | constructor() { 1327 | this.root = null; 1328 | } 1329 | 1330 | /** 1331 | * In order to test if the value exists in the tree, we first need to search 1332 | * through the tree. 1333 | */ 1334 | 1335 | contains(value) { 1336 | // We start at the root. 1337 | var current = this.root; 1338 | 1339 | // We're going to keep running as long as we have another node to visit. 1340 | // If we reach a `left` or `right` that is `null` then this loop ends. 1341 | while (current) { 1342 | 1343 | // If the value is greater than the current.value we move to the right 1344 | if (value > current.value) { 1345 | current = current.right; 1346 | 1347 | // If the value is less than the current.value we move to the left. 1348 | } else if (value < current.value) { 1349 | current = current.left; 1350 | 1351 | // Otherwise we must be equal values and we return true. 1352 | } else { 1353 | return true; 1354 | } 1355 | } 1356 | 1357 | // If we haven't matched anything then we return false. 1358 | return false; 1359 | } 1360 | 1361 | /** 1362 | * In order to add items to this tree we are going to do the same traversal 1363 | * as before, bouncing between left and right nodes depending on them being 1364 | * less than or greater than the value we're adding. 1365 | * 1366 | * However, this time when we reach a `left` or `right` that is `null` we're 1367 | * going to add a new node in that position. 1368 | */ 1369 | 1370 | add(value) { 1371 | // First let's setup our node. 1372 | var node = { 1373 | value: value, 1374 | left: null, 1375 | right: null 1376 | }; 1377 | 1378 | // Special case for when there isn't any root node and we just need to add 1379 | // one. 1380 | if (this.root === null) { 1381 | this.root = node; 1382 | return; 1383 | } 1384 | 1385 | // We start at the root. 1386 | var current = this.root; 1387 | 1388 | // We're going to loop until we've either added our item or discovered it 1389 | // already exists in the tree. 1390 | while (true) { 1391 | 1392 | // If the value is greater than the current.value we move to the right. 1393 | if (value > current.value) { 1394 | 1395 | // If `right` does not exist, set it to our node, and stop traversing. 1396 | if (!current.right) { 1397 | current.right = node; 1398 | break; 1399 | } 1400 | 1401 | // Otherwise just move on to the right node. 1402 | current = current.right; 1403 | 1404 | // If the value is less than the current.value we move to the left. 1405 | } else if (value < current.value) { 1406 | 1407 | // If `left` does not exist, set it to our node, and stop traversing. 1408 | if (!current.left) { 1409 | current.left = node; 1410 | break; 1411 | } 1412 | 1413 | // Otherwise just move on to the left node. 1414 | current = current.left; 1415 | 1416 | // If the number isn't less than or greater, then it must be the same and 1417 | // we don't do anything. 1418 | } else { 1419 | break; 1420 | } 1421 | } 1422 | } 1423 | } 1424 | 1425 | /*** ===================================================================== ***\ 1426 | ** - YOU REACHED THE END! ------------------------------------------------ ** 1427 | * ========================================================================= * 1428 | * .''. * 1429 | * .''. *''* :_\/_: . * 1430 | * :_\/_: . .:.*_\/_* : /\ : .'.:.'. * 1431 | * .''.: /\ : _\(/_ ':'* /\ * : '..'. -=:o:=- * 1432 | * :_\/_:'.:::. /)\*''* .|.* '.\'/.'_\(/_'.':'.' * 1433 | * : /\ : ::::: '*_\/_* | | -= o =- /)\ ' * * 1434 | * '..' ':::' * /\ * |'| .'/.\'. '._____ * 1435 | * * __*..* | | : |. |' .---"| * 1436 | * _* .-' '-. | | .--'| || | _| | * 1437 | * .-'| _.| | || '-__ | | | || | * 1438 | * |' | |. | || | | | | || | * 1439 | * _____________| '-' ' "" '-' '-.' '` |____________ * 1440 | ** jgs~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ** 1441 | \*** ===================================================================== ***/ 1442 | 1443 | /** 1444 | * I know that was probably a bit dense, but hopefully it gave you a good 1445 | * amount of knowledge. If you enjoyed it, would you mind giving the repo a 1446 | * star and following me on twitter (@thejameskyle)? 1447 | * 1448 | * You can also check out my other code walkthrough, "The Super Tiny Compiler" 1449 | * here ------> https://github.com/thejameskyle/the-super-tiny-compiler 1450 | */ 1451 | 1452 | // Just exporting everything for the tests... 1453 | module.exports = { 1454 | List: List, 1455 | HashTable: HashTable, 1456 | Stack: Stack, 1457 | Queue: Queue, 1458 | Graph: Graph, 1459 | LinkedList: LinkedList, 1460 | Tree: Tree, 1461 | BinarySearchTree: BinarySearchTree 1462 | }; 1463 | --------------------------------------------------------------------------------