├── README.markdown
├── _vendor
├── chai.js
├── mocha.css
├── mocha.js
└── underscore.js
├── a_star
└── README.markdown
├── big_o_notation
└── README.MD
├── binary_trees
├── README.markdown
├── javascript
│ ├── README.md
│ ├── bst.js
│ ├── bst_test.js
│ └── index.html
└── ruby
│ ├── Guardfile
│ ├── lib
│ └── .gitkeep
│ └── test
│ └── binary_search_tree_test.rb
├── bitwise_binary_operators
├── README.md
└── javascript
│ ├── README.md
│ ├── hexToDecimal-test.js
│ ├── index.html
│ └── rgbToHex-test.js
├── bloom_filters
└── README.markdown
├── dungeon_generation
└── README.md
├── graphs
└── README.md
├── hash_array_mapped_tries
└── README.markdown
├── hash_tables
└── README.md
├── heaps
└── README.md
├── huffman_coding
├── javascript
│ ├── compression.js
│ ├── index.html
│ └── test.js
└── readme.md
├── linked_lists
├── README.markdown
├── javascript
│ ├── ListNode.js
│ ├── ListNode_test.js
│ ├── README.md
│ ├── linkedList.js
│ ├── linkedList_test.js
│ └── test.html
└── ruby
│ └── linked_list_test.rb
├── luhn_algorithm
├── README.markdown
└── luhn_test.rb
├── md5
├── README.markdown
├── md5.rb
└── md5_test.rb
├── pathfinding
├── Guardfile
├── lib
│ ├── landscape.rb
│ └── pathfinder.rb
└── test
│ ├── fixtures
│ ├── landscape1.txt
│ └── landscape2.txt
│ ├── landscape_test.rb
│ └── pathfinder_test.rb
├── red_black_trees
└── README.markdown
├── resources
├── number_generator.rb
└── sample_numbers.txt
├── sha_1
└── README.markdown
├── topics_wishlist.markdown
└── tries
└── README.md
/README.markdown:
--------------------------------------------------------------------------------
1 | ## Data Structures & Algorithms
2 |
3 | In the process of becoming or practicing as a web application developer, it's easy to lose sight of Computer Science.
4 |
5 | This collection of exercises and experiments seeks to help you build an understanding of those foundations.
6 |
7 | ## Local Setup
8 |
9 | - Fork this repo
10 | - Clone your forked repo
11 | - `cd data_structures_and_algorithms`
12 | - Set the remote
13 | - `git remote add upstream https://github.com/turingschool/data_structures_and_algorithms.git`
14 |
15 | If there have been changes to this main repo - you can pull them down in the following way
16 |
17 | - Make sure you are on a master branch, with no uncommitted work (makes this easier)
18 | - `git fetch upstream master`
19 |
20 | ### Included Topics
21 |
22 | * binary trees - README|Ruby|JavaScript
23 | * Pathfinding Algorithm with A* - README|Ruby?
24 | * luhn algorithm (checksumming) - README|Ruby
25 | * graphs - README
26 | * linked lists - README|Ruby|JavaScript
27 | * bloom filters - README
28 | * Hash Array Mapped Trie - README
29 | * Hash Maps - README
30 | * Heaps - README
31 | * Huffman Coding - README|JavaScript
32 | * MD5 Hashing - README|Ruby
33 | * Red/Black Trees - README
34 | * SHA-1 - README
35 | * tries - README
36 |
37 | #### To-Do / Would like to cover
38 |
39 | * Skip Lists
40 | * Persistent Data Structures
41 | * Tries (more detail)
42 | * Hashing algorithm implementation (maybe start with MurmurHash?)
43 | * Dungeon Generation
44 |
--------------------------------------------------------------------------------
/_vendor/mocha.css:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | body {
4 | margin:0;
5 | }
6 |
7 | #mocha {
8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | margin: 60px 50px;
10 | }
11 |
12 | #mocha ul,
13 | #mocha li {
14 | margin: 0;
15 | padding: 0;
16 | }
17 |
18 | #mocha ul {
19 | list-style: none;
20 | }
21 |
22 | #mocha h1,
23 | #mocha h2 {
24 | margin: 0;
25 | }
26 |
27 | #mocha h1 {
28 | margin-top: 15px;
29 | font-size: 1em;
30 | font-weight: 200;
31 | }
32 |
33 | #mocha h1 a {
34 | text-decoration: none;
35 | color: inherit;
36 | }
37 |
38 | #mocha h1 a:hover {
39 | text-decoration: underline;
40 | }
41 |
42 | #mocha .suite .suite h1 {
43 | margin-top: 0;
44 | font-size: .8em;
45 | }
46 |
47 | #mocha .hidden {
48 | display: none;
49 | }
50 |
51 | #mocha h2 {
52 | font-size: 12px;
53 | font-weight: normal;
54 | cursor: pointer;
55 | }
56 |
57 | #mocha .suite {
58 | margin-left: 15px;
59 | }
60 |
61 | #mocha .test {
62 | margin-left: 15px;
63 | overflow: hidden;
64 | }
65 |
66 | #mocha .test.pending:hover h2::after {
67 | content: '(pending)';
68 | font-family: arial, sans-serif;
69 | }
70 |
71 | #mocha .test.pass.medium .duration {
72 | background: #c09853;
73 | }
74 |
75 | #mocha .test.pass.slow .duration {
76 | background: #b94a48;
77 | }
78 |
79 | #mocha .test.pass::before {
80 | content: '✓';
81 | font-size: 12px;
82 | display: block;
83 | float: left;
84 | margin-right: 5px;
85 | color: #00d6b2;
86 | }
87 |
88 | #mocha .test.pass .duration {
89 | font-size: 9px;
90 | margin-left: 5px;
91 | padding: 2px 5px;
92 | color: #fff;
93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
96 | -webkit-border-radius: 5px;
97 | -moz-border-radius: 5px;
98 | -ms-border-radius: 5px;
99 | -o-border-radius: 5px;
100 | border-radius: 5px;
101 | }
102 |
103 | #mocha .test.pass.fast .duration {
104 | display: none;
105 | }
106 |
107 | #mocha .test.pending {
108 | color: #0b97c4;
109 | }
110 |
111 | #mocha .test.pending::before {
112 | content: '◦';
113 | color: #0b97c4;
114 | }
115 |
116 | #mocha .test.fail {
117 | color: #c00;
118 | }
119 |
120 | #mocha .test.fail pre {
121 | color: black;
122 | }
123 |
124 | #mocha .test.fail::before {
125 | content: '✖';
126 | font-size: 12px;
127 | display: block;
128 | float: left;
129 | margin-right: 5px;
130 | color: #c00;
131 | }
132 |
133 | #mocha .test pre.error {
134 | color: #c00;
135 | max-height: 300px;
136 | overflow: auto;
137 | }
138 |
139 | #mocha .test .html-error {
140 | overflow: auto;
141 | color: black;
142 | line-height: 1.5;
143 | display: block;
144 | float: left;
145 | clear: left;
146 | font: 12px/1.5 monaco, monospace;
147 | margin: 5px;
148 | padding: 15px;
149 | border: 1px solid #eee;
150 | max-width: 85%; /*(1)*/
151 | max-width: calc(100% - 42px); /*(2)*/
152 | max-height: 300px;
153 | word-wrap: break-word;
154 | border-bottom-color: #ddd;
155 | -webkit-border-radius: 3px;
156 | -webkit-box-shadow: 0 1px 3px #eee;
157 | -moz-border-radius: 3px;
158 | -moz-box-shadow: 0 1px 3px #eee;
159 | border-radius: 3px;
160 | }
161 |
162 | #mocha .test .html-error pre.error {
163 | border: none;
164 | -webkit-border-radius: none;
165 | -webkit-box-shadow: none;
166 | -moz-border-radius: none;
167 | -moz-box-shadow: none;
168 | padding: 0;
169 | margin: 0;
170 | margin-top: 18px;
171 | max-height: none;
172 | }
173 |
174 | /**
175 | * (1): approximate for browsers not supporting calc
176 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
177 | * ^^ seriously
178 | */
179 | #mocha .test pre {
180 | display: block;
181 | float: left;
182 | clear: left;
183 | font: 12px/1.5 monaco, monospace;
184 | margin: 5px;
185 | padding: 15px;
186 | border: 1px solid #eee;
187 | max-width: 85%; /*(1)*/
188 | max-width: calc(100% - 42px); /*(2)*/
189 | word-wrap: break-word;
190 | border-bottom-color: #ddd;
191 | -webkit-border-radius: 3px;
192 | -webkit-box-shadow: 0 1px 3px #eee;
193 | -moz-border-radius: 3px;
194 | -moz-box-shadow: 0 1px 3px #eee;
195 | border-radius: 3px;
196 | }
197 |
198 | #mocha .test h2 {
199 | position: relative;
200 | }
201 |
202 | #mocha .test a.replay {
203 | position: absolute;
204 | top: 3px;
205 | right: 0;
206 | text-decoration: none;
207 | vertical-align: middle;
208 | display: block;
209 | width: 15px;
210 | height: 15px;
211 | line-height: 15px;
212 | text-align: center;
213 | background: #eee;
214 | font-size: 15px;
215 | -moz-border-radius: 15px;
216 | border-radius: 15px;
217 | -webkit-transition: opacity 200ms;
218 | -moz-transition: opacity 200ms;
219 | transition: opacity 200ms;
220 | opacity: 0.3;
221 | color: #888;
222 | }
223 |
224 | #mocha .test:hover a.replay {
225 | opacity: 1;
226 | }
227 |
228 | #mocha-report.pass .test.fail {
229 | display: none;
230 | }
231 |
232 | #mocha-report.fail .test.pass {
233 | display: none;
234 | }
235 |
236 | #mocha-report.pending .test.pass,
237 | #mocha-report.pending .test.fail {
238 | display: none;
239 | }
240 | #mocha-report.pending .test.pass.pending {
241 | display: block;
242 | }
243 |
244 | #mocha-error {
245 | color: #c00;
246 | font-size: 1.5em;
247 | font-weight: 100;
248 | letter-spacing: 1px;
249 | }
250 |
251 | #mocha-stats {
252 | position: fixed;
253 | top: 15px;
254 | right: 10px;
255 | font-size: 12px;
256 | margin: 0;
257 | color: #888;
258 | z-index: 1;
259 | }
260 |
261 | #mocha-stats .progress {
262 | float: right;
263 | padding-top: 0;
264 |
265 | /**
266 | * Set safe initial values, so mochas .progress does not inherit these
267 | * properties from Bootstrap .progress (which causes .progress height to
268 | * equal line height set in Bootstrap).
269 | */
270 | height: auto;
271 | box-shadow: none;
272 | background-color: initial;
273 | }
274 |
275 | #mocha-stats em {
276 | color: black;
277 | }
278 |
279 | #mocha-stats a {
280 | text-decoration: none;
281 | color: inherit;
282 | }
283 |
284 | #mocha-stats a:hover {
285 | border-bottom: 1px solid #eee;
286 | }
287 |
288 | #mocha-stats li {
289 | display: inline-block;
290 | margin: 0 5px;
291 | list-style: none;
292 | padding-top: 11px;
293 | }
294 |
295 | #mocha-stats canvas {
296 | width: 40px;
297 | height: 40px;
298 | }
299 |
300 | #mocha code .comment { color: #ddd; }
301 | #mocha code .init { color: #2f6fad; }
302 | #mocha code .string { color: #5890ad; }
303 | #mocha code .keyword { color: #8a6343; }
304 | #mocha code .number { color: #2f6fad; }
305 |
306 | @media screen and (max-device-width: 480px) {
307 | #mocha {
308 | margin: 60px 0px;
309 | }
310 |
311 | #mocha #stats {
312 | position: absolute;
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/_vendor/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.8.3
2 | // http://underscorejs.org
3 | // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4 | // Underscore may be freely distributed under the MIT license.
5 |
6 | (function() {
7 |
8 | // Baseline setup
9 | // --------------
10 |
11 | // Establish the root object, `window` in the browser, or `exports` on the server.
12 | var root = this;
13 |
14 | // Save the previous value of the `_` variable.
15 | var previousUnderscore = root._;
16 |
17 | // Save bytes in the minified (but not gzipped) version:
18 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
19 |
20 | // Create quick reference variables for speed access to core prototypes.
21 | var
22 | push = ArrayProto.push,
23 | slice = ArrayProto.slice,
24 | toString = ObjProto.toString,
25 | hasOwnProperty = ObjProto.hasOwnProperty;
26 |
27 | // All **ECMAScript 5** native function implementations that we hope to use
28 | // are declared here.
29 | var
30 | nativeIsArray = Array.isArray,
31 | nativeKeys = Object.keys,
32 | nativeBind = FuncProto.bind,
33 | nativeCreate = Object.create;
34 |
35 | // Naked function reference for surrogate-prototype-swapping.
36 | var Ctor = function(){};
37 |
38 | // Create a safe reference to the Underscore object for use below.
39 | var _ = function(obj) {
40 | if (obj instanceof _) return obj;
41 | if (!(this instanceof _)) return new _(obj);
42 | this._wrapped = obj;
43 | };
44 |
45 | // Export the Underscore object for **Node.js**, with
46 | // backwards-compatibility for the old `require()` API. If we're in
47 | // the browser, add `_` as a global object.
48 | if (typeof exports !== 'undefined') {
49 | if (typeof module !== 'undefined' && module.exports) {
50 | exports = module.exports = _;
51 | }
52 | exports._ = _;
53 | } else {
54 | root._ = _;
55 | }
56 |
57 | // Current version.
58 | _.VERSION = '1.8.3';
59 |
60 | // Internal function that returns an efficient (for current engines) version
61 | // of the passed-in callback, to be repeatedly applied in other Underscore
62 | // functions.
63 | var optimizeCb = function(func, context, argCount) {
64 | if (context === void 0) return func;
65 | switch (argCount == null ? 3 : argCount) {
66 | case 1: return function(value) {
67 | return func.call(context, value);
68 | };
69 | case 2: return function(value, other) {
70 | return func.call(context, value, other);
71 | };
72 | case 3: return function(value, index, collection) {
73 | return func.call(context, value, index, collection);
74 | };
75 | case 4: return function(accumulator, value, index, collection) {
76 | return func.call(context, accumulator, value, index, collection);
77 | };
78 | }
79 | return function() {
80 | return func.apply(context, arguments);
81 | };
82 | };
83 |
84 | // A mostly-internal function to generate callbacks that can be applied
85 | // to each element in a collection, returning the desired result — either
86 | // identity, an arbitrary callback, a property matcher, or a property accessor.
87 | var cb = function(value, context, argCount) {
88 | if (value == null) return _.identity;
89 | if (_.isFunction(value)) return optimizeCb(value, context, argCount);
90 | if (_.isObject(value)) return _.matcher(value);
91 | return _.property(value);
92 | };
93 | _.iteratee = function(value, context) {
94 | return cb(value, context, Infinity);
95 | };
96 |
97 | // An internal function for creating assigner functions.
98 | var createAssigner = function(keysFunc, undefinedOnly) {
99 | return function(obj) {
100 | var length = arguments.length;
101 | if (length < 2 || obj == null) return obj;
102 | for (var index = 1; index < length; index++) {
103 | var source = arguments[index],
104 | keys = keysFunc(source),
105 | l = keys.length;
106 | for (var i = 0; i < l; i++) {
107 | var key = keys[i];
108 | if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
109 | }
110 | }
111 | return obj;
112 | };
113 | };
114 |
115 | // An internal function for creating a new object that inherits from another.
116 | var baseCreate = function(prototype) {
117 | if (!_.isObject(prototype)) return {};
118 | if (nativeCreate) return nativeCreate(prototype);
119 | Ctor.prototype = prototype;
120 | var result = new Ctor;
121 | Ctor.prototype = null;
122 | return result;
123 | };
124 |
125 | var property = function(key) {
126 | return function(obj) {
127 | return obj == null ? void 0 : obj[key];
128 | };
129 | };
130 |
131 | // Helper for collection methods to determine whether a collection
132 | // should be iterated as an array or as an object
133 | // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
134 | // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
135 | var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
136 | var getLength = property('length');
137 | var isArrayLike = function(collection) {
138 | var length = getLength(collection);
139 | return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
140 | };
141 |
142 | // Collection Functions
143 | // --------------------
144 |
145 | // The cornerstone, an `each` implementation, aka `forEach`.
146 | // Handles raw objects in addition to array-likes. Treats all
147 | // sparse array-likes as if they were dense.
148 | _.each = _.forEach = function(obj, iteratee, context) {
149 | iteratee = optimizeCb(iteratee, context);
150 | var i, length;
151 | if (isArrayLike(obj)) {
152 | for (i = 0, length = obj.length; i < length; i++) {
153 | iteratee(obj[i], i, obj);
154 | }
155 | } else {
156 | var keys = _.keys(obj);
157 | for (i = 0, length = keys.length; i < length; i++) {
158 | iteratee(obj[keys[i]], keys[i], obj);
159 | }
160 | }
161 | return obj;
162 | };
163 |
164 | // Return the results of applying the iteratee to each element.
165 | _.map = _.collect = function(obj, iteratee, context) {
166 | iteratee = cb(iteratee, context);
167 | var keys = !isArrayLike(obj) && _.keys(obj),
168 | length = (keys || obj).length,
169 | results = Array(length);
170 | for (var index = 0; index < length; index++) {
171 | var currentKey = keys ? keys[index] : index;
172 | results[index] = iteratee(obj[currentKey], currentKey, obj);
173 | }
174 | return results;
175 | };
176 |
177 | // Create a reducing function iterating left or right.
178 | function createReduce(dir) {
179 | // Optimized iterator function as using arguments.length
180 | // in the main function will deoptimize the, see #1991.
181 | function iterator(obj, iteratee, memo, keys, index, length) {
182 | for (; index >= 0 && index < length; index += dir) {
183 | var currentKey = keys ? keys[index] : index;
184 | memo = iteratee(memo, obj[currentKey], currentKey, obj);
185 | }
186 | return memo;
187 | }
188 |
189 | return function(obj, iteratee, memo, context) {
190 | iteratee = optimizeCb(iteratee, context, 4);
191 | var keys = !isArrayLike(obj) && _.keys(obj),
192 | length = (keys || obj).length,
193 | index = dir > 0 ? 0 : length - 1;
194 | // Determine the initial value if none is provided.
195 | if (arguments.length < 3) {
196 | memo = obj[keys ? keys[index] : index];
197 | index += dir;
198 | }
199 | return iterator(obj, iteratee, memo, keys, index, length);
200 | };
201 | }
202 |
203 | // **Reduce** builds up a single result from a list of values, aka `inject`,
204 | // or `foldl`.
205 | _.reduce = _.foldl = _.inject = createReduce(1);
206 |
207 | // The right-associative version of reduce, also known as `foldr`.
208 | _.reduceRight = _.foldr = createReduce(-1);
209 |
210 | // Return the first value which passes a truth test. Aliased as `detect`.
211 | _.find = _.detect = function(obj, predicate, context) {
212 | var key;
213 | if (isArrayLike(obj)) {
214 | key = _.findIndex(obj, predicate, context);
215 | } else {
216 | key = _.findKey(obj, predicate, context);
217 | }
218 | if (key !== void 0 && key !== -1) return obj[key];
219 | };
220 |
221 | // Return all the elements that pass a truth test.
222 | // Aliased as `select`.
223 | _.filter = _.select = function(obj, predicate, context) {
224 | var results = [];
225 | predicate = cb(predicate, context);
226 | _.each(obj, function(value, index, list) {
227 | if (predicate(value, index, list)) results.push(value);
228 | });
229 | return results;
230 | };
231 |
232 | // Return all the elements for which a truth test fails.
233 | _.reject = function(obj, predicate, context) {
234 | return _.filter(obj, _.negate(cb(predicate)), context);
235 | };
236 |
237 | // Determine whether all of the elements match a truth test.
238 | // Aliased as `all`.
239 | _.every = _.all = function(obj, predicate, context) {
240 | predicate = cb(predicate, context);
241 | var keys = !isArrayLike(obj) && _.keys(obj),
242 | length = (keys || obj).length;
243 | for (var index = 0; index < length; index++) {
244 | var currentKey = keys ? keys[index] : index;
245 | if (!predicate(obj[currentKey], currentKey, obj)) return false;
246 | }
247 | return true;
248 | };
249 |
250 | // Determine if at least one element in the object matches a truth test.
251 | // Aliased as `any`.
252 | _.some = _.any = function(obj, predicate, context) {
253 | predicate = cb(predicate, context);
254 | var keys = !isArrayLike(obj) && _.keys(obj),
255 | length = (keys || obj).length;
256 | for (var index = 0; index < length; index++) {
257 | var currentKey = keys ? keys[index] : index;
258 | if (predicate(obj[currentKey], currentKey, obj)) return true;
259 | }
260 | return false;
261 | };
262 |
263 | // Determine if the array or object contains a given item (using `===`).
264 | // Aliased as `includes` and `include`.
265 | _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
266 | if (!isArrayLike(obj)) obj = _.values(obj);
267 | if (typeof fromIndex != 'number' || guard) fromIndex = 0;
268 | return _.indexOf(obj, item, fromIndex) >= 0;
269 | };
270 |
271 | // Invoke a method (with arguments) on every item in a collection.
272 | _.invoke = function(obj, method) {
273 | var args = slice.call(arguments, 2);
274 | var isFunc = _.isFunction(method);
275 | return _.map(obj, function(value) {
276 | var func = isFunc ? method : value[method];
277 | return func == null ? func : func.apply(value, args);
278 | });
279 | };
280 |
281 | // Convenience version of a common use case of `map`: fetching a property.
282 | _.pluck = function(obj, key) {
283 | return _.map(obj, _.property(key));
284 | };
285 |
286 | // Convenience version of a common use case of `filter`: selecting only objects
287 | // containing specific `key:value` pairs.
288 | _.where = function(obj, attrs) {
289 | return _.filter(obj, _.matcher(attrs));
290 | };
291 |
292 | // Convenience version of a common use case of `find`: getting the first object
293 | // containing specific `key:value` pairs.
294 | _.findWhere = function(obj, attrs) {
295 | return _.find(obj, _.matcher(attrs));
296 | };
297 |
298 | // Return the maximum element (or element-based computation).
299 | _.max = function(obj, iteratee, context) {
300 | var result = -Infinity, lastComputed = -Infinity,
301 | value, computed;
302 | if (iteratee == null && obj != null) {
303 | obj = isArrayLike(obj) ? obj : _.values(obj);
304 | for (var i = 0, length = obj.length; i < length; i++) {
305 | value = obj[i];
306 | if (value > result) {
307 | result = value;
308 | }
309 | }
310 | } else {
311 | iteratee = cb(iteratee, context);
312 | _.each(obj, function(value, index, list) {
313 | computed = iteratee(value, index, list);
314 | if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
315 | result = value;
316 | lastComputed = computed;
317 | }
318 | });
319 | }
320 | return result;
321 | };
322 |
323 | // Return the minimum element (or element-based computation).
324 | _.min = function(obj, iteratee, context) {
325 | var result = Infinity, lastComputed = Infinity,
326 | value, computed;
327 | if (iteratee == null && obj != null) {
328 | obj = isArrayLike(obj) ? obj : _.values(obj);
329 | for (var i = 0, length = obj.length; i < length; i++) {
330 | value = obj[i];
331 | if (value < result) {
332 | result = value;
333 | }
334 | }
335 | } else {
336 | iteratee = cb(iteratee, context);
337 | _.each(obj, function(value, index, list) {
338 | computed = iteratee(value, index, list);
339 | if (computed < lastComputed || computed === Infinity && result === Infinity) {
340 | result = value;
341 | lastComputed = computed;
342 | }
343 | });
344 | }
345 | return result;
346 | };
347 |
348 | // Shuffle a collection, using the modern version of the
349 | // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
350 | _.shuffle = function(obj) {
351 | var set = isArrayLike(obj) ? obj : _.values(obj);
352 | var length = set.length;
353 | var shuffled = Array(length);
354 | for (var index = 0, rand; index < length; index++) {
355 | rand = _.random(0, index);
356 | if (rand !== index) shuffled[index] = shuffled[rand];
357 | shuffled[rand] = set[index];
358 | }
359 | return shuffled;
360 | };
361 |
362 | // Sample **n** random values from a collection.
363 | // If **n** is not specified, returns a single random element.
364 | // The internal `guard` argument allows it to work with `map`.
365 | _.sample = function(obj, n, guard) {
366 | if (n == null || guard) {
367 | if (!isArrayLike(obj)) obj = _.values(obj);
368 | return obj[_.random(obj.length - 1)];
369 | }
370 | return _.shuffle(obj).slice(0, Math.max(0, n));
371 | };
372 |
373 | // Sort the object's values by a criterion produced by an iteratee.
374 | _.sortBy = function(obj, iteratee, context) {
375 | iteratee = cb(iteratee, context);
376 | return _.pluck(_.map(obj, function(value, index, list) {
377 | return {
378 | value: value,
379 | index: index,
380 | criteria: iteratee(value, index, list)
381 | };
382 | }).sort(function(left, right) {
383 | var a = left.criteria;
384 | var b = right.criteria;
385 | if (a !== b) {
386 | if (a > b || a === void 0) return 1;
387 | if (a < b || b === void 0) return -1;
388 | }
389 | return left.index - right.index;
390 | }), 'value');
391 | };
392 |
393 | // An internal function used for aggregate "group by" operations.
394 | var group = function(behavior) {
395 | return function(obj, iteratee, context) {
396 | var result = {};
397 | iteratee = cb(iteratee, context);
398 | _.each(obj, function(value, index) {
399 | var key = iteratee(value, index, obj);
400 | behavior(result, value, key);
401 | });
402 | return result;
403 | };
404 | };
405 |
406 | // Groups the object's values by a criterion. Pass either a string attribute
407 | // to group by, or a function that returns the criterion.
408 | _.groupBy = group(function(result, value, key) {
409 | if (_.has(result, key)) result[key].push(value); else result[key] = [value];
410 | });
411 |
412 | // Indexes the object's values by a criterion, similar to `groupBy`, but for
413 | // when you know that your index values will be unique.
414 | _.indexBy = group(function(result, value, key) {
415 | result[key] = value;
416 | });
417 |
418 | // Counts instances of an object that group by a certain criterion. Pass
419 | // either a string attribute to count by, or a function that returns the
420 | // criterion.
421 | _.countBy = group(function(result, value, key) {
422 | if (_.has(result, key)) result[key]++; else result[key] = 1;
423 | });
424 |
425 | // Safely create a real, live array from anything iterable.
426 | _.toArray = function(obj) {
427 | if (!obj) return [];
428 | if (_.isArray(obj)) return slice.call(obj);
429 | if (isArrayLike(obj)) return _.map(obj, _.identity);
430 | return _.values(obj);
431 | };
432 |
433 | // Return the number of elements in an object.
434 | _.size = function(obj) {
435 | if (obj == null) return 0;
436 | return isArrayLike(obj) ? obj.length : _.keys(obj).length;
437 | };
438 |
439 | // Split a collection into two arrays: one whose elements all satisfy the given
440 | // predicate, and one whose elements all do not satisfy the predicate.
441 | _.partition = function(obj, predicate, context) {
442 | predicate = cb(predicate, context);
443 | var pass = [], fail = [];
444 | _.each(obj, function(value, key, obj) {
445 | (predicate(value, key, obj) ? pass : fail).push(value);
446 | });
447 | return [pass, fail];
448 | };
449 |
450 | // Array Functions
451 | // ---------------
452 |
453 | // Get the first element of an array. Passing **n** will return the first N
454 | // values in the array. Aliased as `head` and `take`. The **guard** check
455 | // allows it to work with `_.map`.
456 | _.first = _.head = _.take = function(array, n, guard) {
457 | if (array == null) return void 0;
458 | if (n == null || guard) return array[0];
459 | return _.initial(array, array.length - n);
460 | };
461 |
462 | // Returns everything but the last entry of the array. Especially useful on
463 | // the arguments object. Passing **n** will return all the values in
464 | // the array, excluding the last N.
465 | _.initial = function(array, n, guard) {
466 | return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
467 | };
468 |
469 | // Get the last element of an array. Passing **n** will return the last N
470 | // values in the array.
471 | _.last = function(array, n, guard) {
472 | if (array == null) return void 0;
473 | if (n == null || guard) return array[array.length - 1];
474 | return _.rest(array, Math.max(0, array.length - n));
475 | };
476 |
477 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
478 | // Especially useful on the arguments object. Passing an **n** will return
479 | // the rest N values in the array.
480 | _.rest = _.tail = _.drop = function(array, n, guard) {
481 | return slice.call(array, n == null || guard ? 1 : n);
482 | };
483 |
484 | // Trim out all falsy values from an array.
485 | _.compact = function(array) {
486 | return _.filter(array, _.identity);
487 | };
488 |
489 | // Internal implementation of a recursive `flatten` function.
490 | var flatten = function(input, shallow, strict, startIndex) {
491 | var output = [], idx = 0;
492 | for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
493 | var value = input[i];
494 | if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
495 | //flatten current level of array or arguments object
496 | if (!shallow) value = flatten(value, shallow, strict);
497 | var j = 0, len = value.length;
498 | output.length += len;
499 | while (j < len) {
500 | output[idx++] = value[j++];
501 | }
502 | } else if (!strict) {
503 | output[idx++] = value;
504 | }
505 | }
506 | return output;
507 | };
508 |
509 | // Flatten out an array, either recursively (by default), or just one level.
510 | _.flatten = function(array, shallow) {
511 | return flatten(array, shallow, false);
512 | };
513 |
514 | // Return a version of the array that does not contain the specified value(s).
515 | _.without = function(array) {
516 | return _.difference(array, slice.call(arguments, 1));
517 | };
518 |
519 | // Produce a duplicate-free version of the array. If the array has already
520 | // been sorted, you have the option of using a faster algorithm.
521 | // Aliased as `unique`.
522 | _.uniq = _.unique = function(array, isSorted, iteratee, context) {
523 | if (!_.isBoolean(isSorted)) {
524 | context = iteratee;
525 | iteratee = isSorted;
526 | isSorted = false;
527 | }
528 | if (iteratee != null) iteratee = cb(iteratee, context);
529 | var result = [];
530 | var seen = [];
531 | for (var i = 0, length = getLength(array); i < length; i++) {
532 | var value = array[i],
533 | computed = iteratee ? iteratee(value, i, array) : value;
534 | if (isSorted) {
535 | if (!i || seen !== computed) result.push(value);
536 | seen = computed;
537 | } else if (iteratee) {
538 | if (!_.contains(seen, computed)) {
539 | seen.push(computed);
540 | result.push(value);
541 | }
542 | } else if (!_.contains(result, value)) {
543 | result.push(value);
544 | }
545 | }
546 | return result;
547 | };
548 |
549 | // Produce an array that contains the union: each distinct element from all of
550 | // the passed-in arrays.
551 | _.union = function() {
552 | return _.uniq(flatten(arguments, true, true));
553 | };
554 |
555 | // Produce an array that contains every item shared between all the
556 | // passed-in arrays.
557 | _.intersection = function(array) {
558 | var result = [];
559 | var argsLength = arguments.length;
560 | for (var i = 0, length = getLength(array); i < length; i++) {
561 | var item = array[i];
562 | if (_.contains(result, item)) continue;
563 | for (var j = 1; j < argsLength; j++) {
564 | if (!_.contains(arguments[j], item)) break;
565 | }
566 | if (j === argsLength) result.push(item);
567 | }
568 | return result;
569 | };
570 |
571 | // Take the difference between one array and a number of other arrays.
572 | // Only the elements present in just the first array will remain.
573 | _.difference = function(array) {
574 | var rest = flatten(arguments, true, true, 1);
575 | return _.filter(array, function(value){
576 | return !_.contains(rest, value);
577 | });
578 | };
579 |
580 | // Zip together multiple lists into a single array -- elements that share
581 | // an index go together.
582 | _.zip = function() {
583 | return _.unzip(arguments);
584 | };
585 |
586 | // Complement of _.zip. Unzip accepts an array of arrays and groups
587 | // each array's elements on shared indices
588 | _.unzip = function(array) {
589 | var length = array && _.max(array, getLength).length || 0;
590 | var result = Array(length);
591 |
592 | for (var index = 0; index < length; index++) {
593 | result[index] = _.pluck(array, index);
594 | }
595 | return result;
596 | };
597 |
598 | // Converts lists into objects. Pass either a single array of `[key, value]`
599 | // pairs, or two parallel arrays of the same length -- one of keys, and one of
600 | // the corresponding values.
601 | _.object = function(list, values) {
602 | var result = {};
603 | for (var i = 0, length = getLength(list); i < length; i++) {
604 | if (values) {
605 | result[list[i]] = values[i];
606 | } else {
607 | result[list[i][0]] = list[i][1];
608 | }
609 | }
610 | return result;
611 | };
612 |
613 | // Generator function to create the findIndex and findLastIndex functions
614 | function createPredicateIndexFinder(dir) {
615 | return function(array, predicate, context) {
616 | predicate = cb(predicate, context);
617 | var length = getLength(array);
618 | var index = dir > 0 ? 0 : length - 1;
619 | for (; index >= 0 && index < length; index += dir) {
620 | if (predicate(array[index], index, array)) return index;
621 | }
622 | return -1;
623 | };
624 | }
625 |
626 | // Returns the first index on an array-like that passes a predicate test
627 | _.findIndex = createPredicateIndexFinder(1);
628 | _.findLastIndex = createPredicateIndexFinder(-1);
629 |
630 | // Use a comparator function to figure out the smallest index at which
631 | // an object should be inserted so as to maintain order. Uses binary search.
632 | _.sortedIndex = function(array, obj, iteratee, context) {
633 | iteratee = cb(iteratee, context, 1);
634 | var value = iteratee(obj);
635 | var low = 0, high = getLength(array);
636 | while (low < high) {
637 | var mid = Math.floor((low + high) / 2);
638 | if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
639 | }
640 | return low;
641 | };
642 |
643 | // Generator function to create the indexOf and lastIndexOf functions
644 | function createIndexFinder(dir, predicateFind, sortedIndex) {
645 | return function(array, item, idx) {
646 | var i = 0, length = getLength(array);
647 | if (typeof idx == 'number') {
648 | if (dir > 0) {
649 | i = idx >= 0 ? idx : Math.max(idx + length, i);
650 | } else {
651 | length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
652 | }
653 | } else if (sortedIndex && idx && length) {
654 | idx = sortedIndex(array, item);
655 | return array[idx] === item ? idx : -1;
656 | }
657 | if (item !== item) {
658 | idx = predicateFind(slice.call(array, i, length), _.isNaN);
659 | return idx >= 0 ? idx + i : -1;
660 | }
661 | for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
662 | if (array[idx] === item) return idx;
663 | }
664 | return -1;
665 | };
666 | }
667 |
668 | // Return the position of the first occurrence of an item in an array,
669 | // or -1 if the item is not included in the array.
670 | // If the array is large and already in sort order, pass `true`
671 | // for **isSorted** to use binary search.
672 | _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
673 | _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
674 |
675 | // Generate an integer Array containing an arithmetic progression. A port of
676 | // the native Python `range()` function. See
677 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
678 | _.range = function(start, stop, step) {
679 | if (stop == null) {
680 | stop = start || 0;
681 | start = 0;
682 | }
683 | step = step || 1;
684 |
685 | var length = Math.max(Math.ceil((stop - start) / step), 0);
686 | var range = Array(length);
687 |
688 | for (var idx = 0; idx < length; idx++, start += step) {
689 | range[idx] = start;
690 | }
691 |
692 | return range;
693 | };
694 |
695 | // Function (ahem) Functions
696 | // ------------------
697 |
698 | // Determines whether to execute a function as a constructor
699 | // or a normal function with the provided arguments
700 | var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
701 | if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
702 | var self = baseCreate(sourceFunc.prototype);
703 | var result = sourceFunc.apply(self, args);
704 | if (_.isObject(result)) return result;
705 | return self;
706 | };
707 |
708 | // Create a function bound to a given object (assigning `this`, and arguments,
709 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
710 | // available.
711 | _.bind = function(func, context) {
712 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
713 | if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
714 | var args = slice.call(arguments, 2);
715 | var bound = function() {
716 | return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
717 | };
718 | return bound;
719 | };
720 |
721 | // Partially apply a function by creating a version that has had some of its
722 | // arguments pre-filled, without changing its dynamic `this` context. _ acts
723 | // as a placeholder, allowing any combination of arguments to be pre-filled.
724 | _.partial = function(func) {
725 | var boundArgs = slice.call(arguments, 1);
726 | var bound = function() {
727 | var position = 0, length = boundArgs.length;
728 | var args = Array(length);
729 | for (var i = 0; i < length; i++) {
730 | args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
731 | }
732 | while (position < arguments.length) args.push(arguments[position++]);
733 | return executeBound(func, bound, this, this, args);
734 | };
735 | return bound;
736 | };
737 |
738 | // Bind a number of an object's methods to that object. Remaining arguments
739 | // are the method names to be bound. Useful for ensuring that all callbacks
740 | // defined on an object belong to it.
741 | _.bindAll = function(obj) {
742 | var i, length = arguments.length, key;
743 | if (length <= 1) throw new Error('bindAll must be passed function names');
744 | for (i = 1; i < length; i++) {
745 | key = arguments[i];
746 | obj[key] = _.bind(obj[key], obj);
747 | }
748 | return obj;
749 | };
750 |
751 | // Memoize an expensive function by storing its results.
752 | _.memoize = function(func, hasher) {
753 | var memoize = function(key) {
754 | var cache = memoize.cache;
755 | var address = '' + (hasher ? hasher.apply(this, arguments) : key);
756 | if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
757 | return cache[address];
758 | };
759 | memoize.cache = {};
760 | return memoize;
761 | };
762 |
763 | // Delays a function for the given number of milliseconds, and then calls
764 | // it with the arguments supplied.
765 | _.delay = function(func, wait) {
766 | var args = slice.call(arguments, 2);
767 | return setTimeout(function(){
768 | return func.apply(null, args);
769 | }, wait);
770 | };
771 |
772 | // Defers a function, scheduling it to run after the current call stack has
773 | // cleared.
774 | _.defer = _.partial(_.delay, _, 1);
775 |
776 | // Returns a function, that, when invoked, will only be triggered at most once
777 | // during a given window of time. Normally, the throttled function will run
778 | // as much as it can, without ever going more than once per `wait` duration;
779 | // but if you'd like to disable the execution on the leading edge, pass
780 | // `{leading: false}`. To disable execution on the trailing edge, ditto.
781 | _.throttle = function(func, wait, options) {
782 | var context, args, result;
783 | var timeout = null;
784 | var previous = 0;
785 | if (!options) options = {};
786 | var later = function() {
787 | previous = options.leading === false ? 0 : _.now();
788 | timeout = null;
789 | result = func.apply(context, args);
790 | if (!timeout) context = args = null;
791 | };
792 | return function() {
793 | var now = _.now();
794 | if (!previous && options.leading === false) previous = now;
795 | var remaining = wait - (now - previous);
796 | context = this;
797 | args = arguments;
798 | if (remaining <= 0 || remaining > wait) {
799 | if (timeout) {
800 | clearTimeout(timeout);
801 | timeout = null;
802 | }
803 | previous = now;
804 | result = func.apply(context, args);
805 | if (!timeout) context = args = null;
806 | } else if (!timeout && options.trailing !== false) {
807 | timeout = setTimeout(later, remaining);
808 | }
809 | return result;
810 | };
811 | };
812 |
813 | // Returns a function, that, as long as it continues to be invoked, will not
814 | // be triggered. The function will be called after it stops being called for
815 | // N milliseconds. If `immediate` is passed, trigger the function on the
816 | // leading edge, instead of the trailing.
817 | _.debounce = function(func, wait, immediate) {
818 | var timeout, args, context, timestamp, result;
819 |
820 | var later = function() {
821 | var last = _.now() - timestamp;
822 |
823 | if (last < wait && last >= 0) {
824 | timeout = setTimeout(later, wait - last);
825 | } else {
826 | timeout = null;
827 | if (!immediate) {
828 | result = func.apply(context, args);
829 | if (!timeout) context = args = null;
830 | }
831 | }
832 | };
833 |
834 | return function() {
835 | context = this;
836 | args = arguments;
837 | timestamp = _.now();
838 | var callNow = immediate && !timeout;
839 | if (!timeout) timeout = setTimeout(later, wait);
840 | if (callNow) {
841 | result = func.apply(context, args);
842 | context = args = null;
843 | }
844 |
845 | return result;
846 | };
847 | };
848 |
849 | // Returns the first function passed as an argument to the second,
850 | // allowing you to adjust arguments, run code before and after, and
851 | // conditionally execute the original function.
852 | _.wrap = function(func, wrapper) {
853 | return _.partial(wrapper, func);
854 | };
855 |
856 | // Returns a negated version of the passed-in predicate.
857 | _.negate = function(predicate) {
858 | return function() {
859 | return !predicate.apply(this, arguments);
860 | };
861 | };
862 |
863 | // Returns a function that is the composition of a list of functions, each
864 | // consuming the return value of the function that follows.
865 | _.compose = function() {
866 | var args = arguments;
867 | var start = args.length - 1;
868 | return function() {
869 | var i = start;
870 | var result = args[start].apply(this, arguments);
871 | while (i--) result = args[i].call(this, result);
872 | return result;
873 | };
874 | };
875 |
876 | // Returns a function that will only be executed on and after the Nth call.
877 | _.after = function(times, func) {
878 | return function() {
879 | if (--times < 1) {
880 | return func.apply(this, arguments);
881 | }
882 | };
883 | };
884 |
885 | // Returns a function that will only be executed up to (but not including) the Nth call.
886 | _.before = function(times, func) {
887 | var memo;
888 | return function() {
889 | if (--times > 0) {
890 | memo = func.apply(this, arguments);
891 | }
892 | if (times <= 1) func = null;
893 | return memo;
894 | };
895 | };
896 |
897 | // Returns a function that will be executed at most one time, no matter how
898 | // often you call it. Useful for lazy initialization.
899 | _.once = _.partial(_.before, 2);
900 |
901 | // Object Functions
902 | // ----------------
903 |
904 | // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
905 | var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
906 | var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
907 | 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
908 |
909 | function collectNonEnumProps(obj, keys) {
910 | var nonEnumIdx = nonEnumerableProps.length;
911 | var constructor = obj.constructor;
912 | var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
913 |
914 | // Constructor is a special case.
915 | var prop = 'constructor';
916 | if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
917 |
918 | while (nonEnumIdx--) {
919 | prop = nonEnumerableProps[nonEnumIdx];
920 | if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
921 | keys.push(prop);
922 | }
923 | }
924 | }
925 |
926 | // Retrieve the names of an object's own properties.
927 | // Delegates to **ECMAScript 5**'s native `Object.keys`
928 | _.keys = function(obj) {
929 | if (!_.isObject(obj)) return [];
930 | if (nativeKeys) return nativeKeys(obj);
931 | var keys = [];
932 | for (var key in obj) if (_.has(obj, key)) keys.push(key);
933 | // Ahem, IE < 9.
934 | if (hasEnumBug) collectNonEnumProps(obj, keys);
935 | return keys;
936 | };
937 |
938 | // Retrieve all the property names of an object.
939 | _.allKeys = function(obj) {
940 | if (!_.isObject(obj)) return [];
941 | var keys = [];
942 | for (var key in obj) keys.push(key);
943 | // Ahem, IE < 9.
944 | if (hasEnumBug) collectNonEnumProps(obj, keys);
945 | return keys;
946 | };
947 |
948 | // Retrieve the values of an object's properties.
949 | _.values = function(obj) {
950 | var keys = _.keys(obj);
951 | var length = keys.length;
952 | var values = Array(length);
953 | for (var i = 0; i < length; i++) {
954 | values[i] = obj[keys[i]];
955 | }
956 | return values;
957 | };
958 |
959 | // Returns the results of applying the iteratee to each element of the object
960 | // In contrast to _.map it returns an object
961 | _.mapObject = function(obj, iteratee, context) {
962 | iteratee = cb(iteratee, context);
963 | var keys = _.keys(obj),
964 | length = keys.length,
965 | results = {},
966 | currentKey;
967 | for (var index = 0; index < length; index++) {
968 | currentKey = keys[index];
969 | results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
970 | }
971 | return results;
972 | };
973 |
974 | // Convert an object into a list of `[key, value]` pairs.
975 | _.pairs = function(obj) {
976 | var keys = _.keys(obj);
977 | var length = keys.length;
978 | var pairs = Array(length);
979 | for (var i = 0; i < length; i++) {
980 | pairs[i] = [keys[i], obj[keys[i]]];
981 | }
982 | return pairs;
983 | };
984 |
985 | // Invert the keys and values of an object. The values must be serializable.
986 | _.invert = function(obj) {
987 | var result = {};
988 | var keys = _.keys(obj);
989 | for (var i = 0, length = keys.length; i < length; i++) {
990 | result[obj[keys[i]]] = keys[i];
991 | }
992 | return result;
993 | };
994 |
995 | // Return a sorted list of the function names available on the object.
996 | // Aliased as `methods`
997 | _.functions = _.methods = function(obj) {
998 | var names = [];
999 | for (var key in obj) {
1000 | if (_.isFunction(obj[key])) names.push(key);
1001 | }
1002 | return names.sort();
1003 | };
1004 |
1005 | // Extend a given object with all the properties in passed-in object(s).
1006 | _.extend = createAssigner(_.allKeys);
1007 |
1008 | // Assigns a given object with all the own properties in the passed-in object(s)
1009 | // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1010 | _.extendOwn = _.assign = createAssigner(_.keys);
1011 |
1012 | // Returns the first key on an object that passes a predicate test
1013 | _.findKey = function(obj, predicate, context) {
1014 | predicate = cb(predicate, context);
1015 | var keys = _.keys(obj), key;
1016 | for (var i = 0, length = keys.length; i < length; i++) {
1017 | key = keys[i];
1018 | if (predicate(obj[key], key, obj)) return key;
1019 | }
1020 | };
1021 |
1022 | // Return a copy of the object only containing the whitelisted properties.
1023 | _.pick = function(object, oiteratee, context) {
1024 | var result = {}, obj = object, iteratee, keys;
1025 | if (obj == null) return result;
1026 | if (_.isFunction(oiteratee)) {
1027 | keys = _.allKeys(obj);
1028 | iteratee = optimizeCb(oiteratee, context);
1029 | } else {
1030 | keys = flatten(arguments, false, false, 1);
1031 | iteratee = function(value, key, obj) { return key in obj; };
1032 | obj = Object(obj);
1033 | }
1034 | for (var i = 0, length = keys.length; i < length; i++) {
1035 | var key = keys[i];
1036 | var value = obj[key];
1037 | if (iteratee(value, key, obj)) result[key] = value;
1038 | }
1039 | return result;
1040 | };
1041 |
1042 | // Return a copy of the object without the blacklisted properties.
1043 | _.omit = function(obj, iteratee, context) {
1044 | if (_.isFunction(iteratee)) {
1045 | iteratee = _.negate(iteratee);
1046 | } else {
1047 | var keys = _.map(flatten(arguments, false, false, 1), String);
1048 | iteratee = function(value, key) {
1049 | return !_.contains(keys, key);
1050 | };
1051 | }
1052 | return _.pick(obj, iteratee, context);
1053 | };
1054 |
1055 | // Fill in a given object with default properties.
1056 | _.defaults = createAssigner(_.allKeys, true);
1057 |
1058 | // Creates an object that inherits from the given prototype object.
1059 | // If additional properties are provided then they will be added to the
1060 | // created object.
1061 | _.create = function(prototype, props) {
1062 | var result = baseCreate(prototype);
1063 | if (props) _.extendOwn(result, props);
1064 | return result;
1065 | };
1066 |
1067 | // Create a (shallow-cloned) duplicate of an object.
1068 | _.clone = function(obj) {
1069 | if (!_.isObject(obj)) return obj;
1070 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
1071 | };
1072 |
1073 | // Invokes interceptor with the obj, and then returns obj.
1074 | // The primary purpose of this method is to "tap into" a method chain, in
1075 | // order to perform operations on intermediate results within the chain.
1076 | _.tap = function(obj, interceptor) {
1077 | interceptor(obj);
1078 | return obj;
1079 | };
1080 |
1081 | // Returns whether an object has a given set of `key:value` pairs.
1082 | _.isMatch = function(object, attrs) {
1083 | var keys = _.keys(attrs), length = keys.length;
1084 | if (object == null) return !length;
1085 | var obj = Object(object);
1086 | for (var i = 0; i < length; i++) {
1087 | var key = keys[i];
1088 | if (attrs[key] !== obj[key] || !(key in obj)) return false;
1089 | }
1090 | return true;
1091 | };
1092 |
1093 |
1094 | // Internal recursive comparison function for `isEqual`.
1095 | var eq = function(a, b, aStack, bStack) {
1096 | // Identical objects are equal. `0 === -0`, but they aren't identical.
1097 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
1098 | if (a === b) return a !== 0 || 1 / a === 1 / b;
1099 | // A strict comparison is necessary because `null == undefined`.
1100 | if (a == null || b == null) return a === b;
1101 | // Unwrap any wrapped objects.
1102 | if (a instanceof _) a = a._wrapped;
1103 | if (b instanceof _) b = b._wrapped;
1104 | // Compare `[[Class]]` names.
1105 | var className = toString.call(a);
1106 | if (className !== toString.call(b)) return false;
1107 | switch (className) {
1108 | // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1109 | case '[object RegExp]':
1110 | // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
1111 | case '[object String]':
1112 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
1113 | // equivalent to `new String("5")`.
1114 | return '' + a === '' + b;
1115 | case '[object Number]':
1116 | // `NaN`s are equivalent, but non-reflexive.
1117 | // Object(NaN) is equivalent to NaN
1118 | if (+a !== +a) return +b !== +b;
1119 | // An `egal` comparison is performed for other numeric values.
1120 | return +a === 0 ? 1 / +a === 1 / b : +a === +b;
1121 | case '[object Date]':
1122 | case '[object Boolean]':
1123 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
1124 | // millisecond representations. Note that invalid dates with millisecond representations
1125 | // of `NaN` are not equivalent.
1126 | return +a === +b;
1127 | }
1128 |
1129 | var areArrays = className === '[object Array]';
1130 | if (!areArrays) {
1131 | if (typeof a != 'object' || typeof b != 'object') return false;
1132 |
1133 | // Objects with different constructors are not equivalent, but `Object`s or `Array`s
1134 | // from different frames are.
1135 | var aCtor = a.constructor, bCtor = b.constructor;
1136 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
1137 | _.isFunction(bCtor) && bCtor instanceof bCtor)
1138 | && ('constructor' in a && 'constructor' in b)) {
1139 | return false;
1140 | }
1141 | }
1142 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
1143 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
1144 |
1145 | // Initializing stack of traversed objects.
1146 | // It's done here since we only need them for objects and arrays comparison.
1147 | aStack = aStack || [];
1148 | bStack = bStack || [];
1149 | var length = aStack.length;
1150 | while (length--) {
1151 | // Linear search. Performance is inversely proportional to the number of
1152 | // unique nested structures.
1153 | if (aStack[length] === a) return bStack[length] === b;
1154 | }
1155 |
1156 | // Add the first object to the stack of traversed objects.
1157 | aStack.push(a);
1158 | bStack.push(b);
1159 |
1160 | // Recursively compare objects and arrays.
1161 | if (areArrays) {
1162 | // Compare array lengths to determine if a deep comparison is necessary.
1163 | length = a.length;
1164 | if (length !== b.length) return false;
1165 | // Deep compare the contents, ignoring non-numeric properties.
1166 | while (length--) {
1167 | if (!eq(a[length], b[length], aStack, bStack)) return false;
1168 | }
1169 | } else {
1170 | // Deep compare objects.
1171 | var keys = _.keys(a), key;
1172 | length = keys.length;
1173 | // Ensure that both objects contain the same number of properties before comparing deep equality.
1174 | if (_.keys(b).length !== length) return false;
1175 | while (length--) {
1176 | // Deep compare each member
1177 | key = keys[length];
1178 | if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
1179 | }
1180 | }
1181 | // Remove the first object from the stack of traversed objects.
1182 | aStack.pop();
1183 | bStack.pop();
1184 | return true;
1185 | };
1186 |
1187 | // Perform a deep comparison to check if two objects are equal.
1188 | _.isEqual = function(a, b) {
1189 | return eq(a, b);
1190 | };
1191 |
1192 | // Is a given array, string, or object empty?
1193 | // An "empty" object has no enumerable own-properties.
1194 | _.isEmpty = function(obj) {
1195 | if (obj == null) return true;
1196 | if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
1197 | return _.keys(obj).length === 0;
1198 | };
1199 |
1200 | // Is a given value a DOM element?
1201 | _.isElement = function(obj) {
1202 | return !!(obj && obj.nodeType === 1);
1203 | };
1204 |
1205 | // Is a given value an array?
1206 | // Delegates to ECMA5's native Array.isArray
1207 | _.isArray = nativeIsArray || function(obj) {
1208 | return toString.call(obj) === '[object Array]';
1209 | };
1210 |
1211 | // Is a given variable an object?
1212 | _.isObject = function(obj) {
1213 | var type = typeof obj;
1214 | return type === 'function' || type === 'object' && !!obj;
1215 | };
1216 |
1217 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
1218 | _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
1219 | _['is' + name] = function(obj) {
1220 | return toString.call(obj) === '[object ' + name + ']';
1221 | };
1222 | });
1223 |
1224 | // Define a fallback version of the method in browsers (ahem, IE < 9), where
1225 | // there isn't any inspectable "Arguments" type.
1226 | if (!_.isArguments(arguments)) {
1227 | _.isArguments = function(obj) {
1228 | return _.has(obj, 'callee');
1229 | };
1230 | }
1231 |
1232 | // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
1233 | // IE 11 (#1621), and in Safari 8 (#1929).
1234 | if (typeof /./ != 'function' && typeof Int8Array != 'object') {
1235 | _.isFunction = function(obj) {
1236 | return typeof obj == 'function' || false;
1237 | };
1238 | }
1239 |
1240 | // Is a given object a finite number?
1241 | _.isFinite = function(obj) {
1242 | return isFinite(obj) && !isNaN(parseFloat(obj));
1243 | };
1244 |
1245 | // Is the given value `NaN`? (NaN is the only number which does not equal itself).
1246 | _.isNaN = function(obj) {
1247 | return _.isNumber(obj) && obj !== +obj;
1248 | };
1249 |
1250 | // Is a given value a boolean?
1251 | _.isBoolean = function(obj) {
1252 | return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
1253 | };
1254 |
1255 | // Is a given value equal to null?
1256 | _.isNull = function(obj) {
1257 | return obj === null;
1258 | };
1259 |
1260 | // Is a given variable undefined?
1261 | _.isUndefined = function(obj) {
1262 | return obj === void 0;
1263 | };
1264 |
1265 | // Shortcut function for checking if an object has a given property directly
1266 | // on itself (in other words, not on a prototype).
1267 | _.has = function(obj, key) {
1268 | return obj != null && hasOwnProperty.call(obj, key);
1269 | };
1270 |
1271 | // Utility Functions
1272 | // -----------------
1273 |
1274 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1275 | // previous owner. Returns a reference to the Underscore object.
1276 | _.noConflict = function() {
1277 | root._ = previousUnderscore;
1278 | return this;
1279 | };
1280 |
1281 | // Keep the identity function around for default iteratees.
1282 | _.identity = function(value) {
1283 | return value;
1284 | };
1285 |
1286 | // Predicate-generating functions. Often useful outside of Underscore.
1287 | _.constant = function(value) {
1288 | return function() {
1289 | return value;
1290 | };
1291 | };
1292 |
1293 | _.noop = function(){};
1294 |
1295 | _.property = property;
1296 |
1297 | // Generates a function for a given object that returns a given property.
1298 | _.propertyOf = function(obj) {
1299 | return obj == null ? function(){} : function(key) {
1300 | return obj[key];
1301 | };
1302 | };
1303 |
1304 | // Returns a predicate for checking whether an object has a given set of
1305 | // `key:value` pairs.
1306 | _.matcher = _.matches = function(attrs) {
1307 | attrs = _.extendOwn({}, attrs);
1308 | return function(obj) {
1309 | return _.isMatch(obj, attrs);
1310 | };
1311 | };
1312 |
1313 | // Run a function **n** times.
1314 | _.times = function(n, iteratee, context) {
1315 | var accum = Array(Math.max(0, n));
1316 | iteratee = optimizeCb(iteratee, context, 1);
1317 | for (var i = 0; i < n; i++) accum[i] = iteratee(i);
1318 | return accum;
1319 | };
1320 |
1321 | // Return a random integer between min and max (inclusive).
1322 | _.random = function(min, max) {
1323 | if (max == null) {
1324 | max = min;
1325 | min = 0;
1326 | }
1327 | return min + Math.floor(Math.random() * (max - min + 1));
1328 | };
1329 |
1330 | // A (possibly faster) way to get the current timestamp as an integer.
1331 | _.now = Date.now || function() {
1332 | return new Date().getTime();
1333 | };
1334 |
1335 | // List of HTML entities for escaping.
1336 | var escapeMap = {
1337 | '&': '&',
1338 | '<': '<',
1339 | '>': '>',
1340 | '"': '"',
1341 | "'": ''',
1342 | '`': '`'
1343 | };
1344 | var unescapeMap = _.invert(escapeMap);
1345 |
1346 | // Functions for escaping and unescaping strings to/from HTML interpolation.
1347 | var createEscaper = function(map) {
1348 | var escaper = function(match) {
1349 | return map[match];
1350 | };
1351 | // Regexes for identifying a key that needs to be escaped
1352 | var source = '(?:' + _.keys(map).join('|') + ')';
1353 | var testRegexp = RegExp(source);
1354 | var replaceRegexp = RegExp(source, 'g');
1355 | return function(string) {
1356 | string = string == null ? '' : '' + string;
1357 | return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
1358 | };
1359 | };
1360 | _.escape = createEscaper(escapeMap);
1361 | _.unescape = createEscaper(unescapeMap);
1362 |
1363 | // If the value of the named `property` is a function then invoke it with the
1364 | // `object` as context; otherwise, return it.
1365 | _.result = function(object, property, fallback) {
1366 | var value = object == null ? void 0 : object[property];
1367 | if (value === void 0) {
1368 | value = fallback;
1369 | }
1370 | return _.isFunction(value) ? value.call(object) : value;
1371 | };
1372 |
1373 | // Generate a unique integer id (unique within the entire client session).
1374 | // Useful for temporary DOM ids.
1375 | var idCounter = 0;
1376 | _.uniqueId = function(prefix) {
1377 | var id = ++idCounter + '';
1378 | return prefix ? prefix + id : id;
1379 | };
1380 |
1381 | // By default, Underscore uses ERB-style template delimiters, change the
1382 | // following template settings to use alternative delimiters.
1383 | _.templateSettings = {
1384 | evaluate : /<%([\s\S]+?)%>/g,
1385 | interpolate : /<%=([\s\S]+?)%>/g,
1386 | escape : /<%-([\s\S]+?)%>/g
1387 | };
1388 |
1389 | // When customizing `templateSettings`, if you don't want to define an
1390 | // interpolation, evaluation or escaping regex, we need one that is
1391 | // guaranteed not to match.
1392 | var noMatch = /(.)^/;
1393 |
1394 | // Certain characters need to be escaped so that they can be put into a
1395 | // string literal.
1396 | var escapes = {
1397 | "'": "'",
1398 | '\\': '\\',
1399 | '\r': 'r',
1400 | '\n': 'n',
1401 | '\u2028': 'u2028',
1402 | '\u2029': 'u2029'
1403 | };
1404 |
1405 | var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
1406 |
1407 | var escapeChar = function(match) {
1408 | return '\\' + escapes[match];
1409 | };
1410 |
1411 | // JavaScript micro-templating, similar to John Resig's implementation.
1412 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
1413 | // and correctly escapes quotes within interpolated code.
1414 | // NB: `oldSettings` only exists for backwards compatibility.
1415 | _.template = function(text, settings, oldSettings) {
1416 | if (!settings && oldSettings) settings = oldSettings;
1417 | settings = _.defaults({}, settings, _.templateSettings);
1418 |
1419 | // Combine delimiters into one regular expression via alternation.
1420 | var matcher = RegExp([
1421 | (settings.escape || noMatch).source,
1422 | (settings.interpolate || noMatch).source,
1423 | (settings.evaluate || noMatch).source
1424 | ].join('|') + '|$', 'g');
1425 |
1426 | // Compile the template source, escaping string literals appropriately.
1427 | var index = 0;
1428 | var source = "__p+='";
1429 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1430 | source += text.slice(index, offset).replace(escaper, escapeChar);
1431 | index = offset + match.length;
1432 |
1433 | if (escape) {
1434 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1435 | } else if (interpolate) {
1436 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1437 | } else if (evaluate) {
1438 | source += "';\n" + evaluate + "\n__p+='";
1439 | }
1440 |
1441 | // Adobe VMs need the match returned to produce the correct offest.
1442 | return match;
1443 | });
1444 | source += "';\n";
1445 |
1446 | // If a variable is not specified, place data values in local scope.
1447 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1448 |
1449 | source = "var __t,__p='',__j=Array.prototype.join," +
1450 | "print=function(){__p+=__j.call(arguments,'');};\n" +
1451 | source + 'return __p;\n';
1452 |
1453 | try {
1454 | var render = new Function(settings.variable || 'obj', '_', source);
1455 | } catch (e) {
1456 | e.source = source;
1457 | throw e;
1458 | }
1459 |
1460 | var template = function(data) {
1461 | return render.call(this, data, _);
1462 | };
1463 |
1464 | // Provide the compiled source as a convenience for precompilation.
1465 | var argument = settings.variable || 'obj';
1466 | template.source = 'function(' + argument + '){\n' + source + '}';
1467 |
1468 | return template;
1469 | };
1470 |
1471 | // Add a "chain" function. Start chaining a wrapped Underscore object.
1472 | _.chain = function(obj) {
1473 | var instance = _(obj);
1474 | instance._chain = true;
1475 | return instance;
1476 | };
1477 |
1478 | // OOP
1479 | // ---------------
1480 | // If Underscore is called as a function, it returns a wrapped object that
1481 | // can be used OO-style. This wrapper holds altered versions of all the
1482 | // underscore functions. Wrapped objects may be chained.
1483 |
1484 | // Helper function to continue chaining intermediate results.
1485 | var result = function(instance, obj) {
1486 | return instance._chain ? _(obj).chain() : obj;
1487 | };
1488 |
1489 | // Add your own custom functions to the Underscore object.
1490 | _.mixin = function(obj) {
1491 | _.each(_.functions(obj), function(name) {
1492 | var func = _[name] = obj[name];
1493 | _.prototype[name] = function() {
1494 | var args = [this._wrapped];
1495 | push.apply(args, arguments);
1496 | return result(this, func.apply(_, args));
1497 | };
1498 | });
1499 | };
1500 |
1501 | // Add all of the Underscore functions to the wrapper object.
1502 | _.mixin(_);
1503 |
1504 | // Add all mutator Array functions to the wrapper.
1505 | _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1506 | var method = ArrayProto[name];
1507 | _.prototype[name] = function() {
1508 | var obj = this._wrapped;
1509 | method.apply(obj, arguments);
1510 | if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
1511 | return result(this, obj);
1512 | };
1513 | });
1514 |
1515 | // Add all accessor Array functions to the wrapper.
1516 | _.each(['concat', 'join', 'slice'], function(name) {
1517 | var method = ArrayProto[name];
1518 | _.prototype[name] = function() {
1519 | return result(this, method.apply(this._wrapped, arguments));
1520 | };
1521 | });
1522 |
1523 | // Extracts the result from a wrapped and chained object.
1524 | _.prototype.value = function() {
1525 | return this._wrapped;
1526 | };
1527 |
1528 | // Provide unwrapping proxy for some methods used in engine operations
1529 | // such as arithmetic and JSON stringification.
1530 | _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
1531 |
1532 | _.prototype.toString = function() {
1533 | return '' + this._wrapped;
1534 | };
1535 |
1536 | // AMD registration happens at the end for compatibility with AMD loaders
1537 | // that may not enforce next-turn semantics on modules. Even though general
1538 | // practice for AMD registration is to be anonymous, underscore registers
1539 | // as a named module because, like jQuery, it is a base library that is
1540 | // popular enough to be bundled in a third party lib, but not be part of
1541 | // an AMD load request. Those cases could generate an error when an
1542 | // anonymous define() is called outside of a loader request.
1543 | if (typeof define === 'function' && define.amd) {
1544 | define('underscore', [], function() {
1545 | return _;
1546 | });
1547 | }
1548 | }.call(this));
1549 |
--------------------------------------------------------------------------------
/a_star/README.markdown:
--------------------------------------------------------------------------------
1 | ## Pathfinding with A\*
2 |
3 | The A\* algorithm is a way of finding a path between two points of a graph or map.
4 |
5 | ### An Example Application
6 |
7 | Imagine you have a character `C` who wants to move to the target `T`. Blank spaces on the map are traversable, but obstructions are marked as `O`:
8 |
9 | ```plain
10 | T |
11 | OOOOO |
12 | |
13 | OOOO |
14 | C |
15 | ```
16 |
17 | How can `C` move to `T` in the fewest steps? The A\* algorithm helps find a path.
18 |
19 | ### The Algorithm
20 |
21 | In pseudocode:
22 |
23 | ```plain
24 | function A*(start,goal)
25 | closedset := the empty set // The set of nodes already evaluated.
26 | openset := {start} // The set of tentative nodes to be evaluated, initially containing the start node
27 | came_from := the empty map // The map of navigated nodes.
28 |
29 | g_score[start] := 0 // Cost from start along best known path.
30 | // Estimated total cost from start to goal through y.
31 | f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)
32 |
33 | while openset is not empty
34 | current := the node in openset having the lowest f_score[] value
35 | if current = goal
36 | return reconstruct_path(came_from, goal)
37 |
38 | remove current from openset
39 | add current to closedset
40 | for each neighbor in neighbor_nodes(current)
41 | tentative_g_score := g_score[current] + dist_between(current,neighbor)
42 | tentative_f_score := tentative_g_score + heuristic_cost_estimate(neighbor, goal)
43 | if neighbor in closedset and tentative_f_score >= f_score[neighbor]
44 | continue
45 |
46 | if neighbor not in openset or tentative_f_score < f_score[neighbor]
47 | came_from[neighbor] := current
48 | g_score[neighbor] := tentative_g_score
49 | f_score[neighbor] := tentative_f_score
50 | if neighbor not in openset
51 | add neighbor to openset
52 |
53 | return failure
54 | ```
55 |
56 | ### References
57 |
58 | * [Wikipedia](http://en.wikipedia.org/wiki/A*_search_algorithm)
59 | * [Ruby Quiz #98](http://rubyquiz.com/quiz98.html)
60 |
--------------------------------------------------------------------------------
/big_o_notation/README.MD:
--------------------------------------------------------------------------------
1 | ## Big O Notation
2 |
3 | ### Resources
4 |
5 | - [Understand Big O](https://www.youtube.com/watch?v=v4cd1O4zkGw)
6 | - [BigOCheatsheet](http://bigocheatsheet.com/)
7 | - [A Sample Big O Test in JSPerf](https://jsperf.com/big-o/1)
--------------------------------------------------------------------------------
/binary_trees/README.markdown:
--------------------------------------------------------------------------------
1 | ## Binary Search Trees
2 |
3 | A binary search tree is a fundamental data structure useful for organizing large sets of data.
4 |
5 | More on Wikipedia: http://en.wikipedia.org/wiki/Binary_search_tree
6 |
7 | ### Overview
8 |
9 | A binary tree is built from *nodes*. Each node has:
10 |
11 | * A) An element of data
12 | * B) A link to the *left*. All nodes to the left have data elements less/lower than this node's data element.
13 | * C) A link to the *right*. All nodes to the right have data elementes more/greater than this node's data element.
14 |
15 | ### Searching
16 |
17 | Your implementation should be able to confirm or deny the presence of a piece of data in the list.
18 |
19 | #### Balancing
20 |
21 | The worst case binary tree comes from a list that's already sorted before insertion to the tree. How can you avoid that problem?
22 |
23 | ### Sorting
24 |
25 | ### Implementation Tips
26 |
27 | * Start with modeling a node
28 | * Then attach one node to another
29 | * Then attach multiple nodes together
30 | * Then implement search when there's just a single node
31 | * Then implement search for multiple nodes
32 | * Then implement sorted output for a single node
33 | * Then implement sorted output for multiple nodes
34 |
--------------------------------------------------------------------------------
/binary_trees/javascript/README.md:
--------------------------------------------------------------------------------
1 | # Binary Trees Problem
2 |
3 | ## Running the Tests
4 |
5 | You can run the tests in this folder in the browser.
6 |
7 | To run in the browser, open the `index.html` page and you should see your tests.
8 |
--------------------------------------------------------------------------------
/binary_trees/javascript/bst.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turingschool/data_structures_and_algorithms/f9e9b47900e84e55d93be51600e51bb9297868aa/binary_trees/javascript/bst.js
--------------------------------------------------------------------------------
/binary_trees/javascript/bst_test.js:
--------------------------------------------------------------------------------
1 | describe('TreeNode', function(){
2 | it('should have data', function() {
3 | var node = new TreeNode(0);
4 | expect(node.data).to.eq(0);
5 | });
6 |
7 | xit('should have a default null value for left and right nodes', function(){
8 | var node = new TreeNode(0);
9 | expect(node.left).to.eq(null);
10 | expect(node.right).to.eq(null);
11 | });
12 |
13 | xit('can have a left node', function(){
14 | var node1 = new TreeNode(1);
15 | var node2 = new TreeNode(0, node1);
16 | expect(node2.left.data).to.eq(1);
17 | });
18 |
19 | xit('can assign a right node', function(){
20 | var node1 = new TreeNode(1);
21 | var node2 = new TreeNode(0, null, node1);
22 | expect(node2.right.data).to.eq(1);
23 | });
24 | });
25 |
26 | describe('BST', function() {
27 | var tree;
28 |
29 | beforeEach(function(){
30 | tree = new BST();
31 | });
32 |
33 | context('when list is empty', function(){
34 | xit('rootNode is null', function(){
35 | expect(tree.rootNode).to.eq(null);
36 | });
37 | });
38 |
39 | describe('.push', function(){
40 | // push adds a datum to the tree. In order to
41 | // provide a nicer interface, we will accept raw numbers as inputs to
42 | // push, and handle wrapping the data in a Node internally
43 | context('when the tree is empty', function(){
44 | xit('creates a new root node', function(){
45 | tree.push(1);
46 | expect(tree.rootNode instanceof TreeNode).to.be.true;
47 | expect(tree.rootNode.data).to.eq(1)
48 | });
49 | });
50 |
51 | context('when tree has only a rootNode', function(){
52 | xit('smaller data is added to the left', function(){
53 | tree.push(5);
54 | expect(tree.rootNode.data).to.eq(5);
55 | tree.push(4);
56 | expect(tree.rootNode.data).to.eq(5);
57 | expect(tree.rootNode.left instanceof TreeNode).to.eq(true, 'left node not set');
58 | expect(tree.rootNode.left.data).to.eq(4);
59 | expect(tree.rootNode.right).to.eq(null);
60 | });
61 |
62 | xit('larger data is added to the right', function(){
63 | tree.push(5);
64 | expect(tree.rootNode.data).to.eq(5);
65 | tree.push(6);
66 | expect(tree.rootNode.data).to.eq(5);
67 | expect(tree.rootNode.right instanceof TreeNode).to.eq(true, 'right node not set');
68 | expect(tree.rootNode.right.data).to.eq(6);
69 | expect(tree.rootNode.left).to.eq(null);
70 | });
71 |
72 | xit('data equal to the rootNode is added to the left', function(){
73 | tree.push(5);
74 | expect(tree.rootNode.data).to.eq(5);
75 | tree.push(5);
76 | expect(tree.rootNode.left instanceof TreeNode).to.eq(true, 'left node not set');
77 | expect(tree.rootNode.left.data).to.eq(5);
78 | expect(tree.rootNode.right).to.eq(null);
79 | });
80 | });
81 |
82 | context('when there are multiple nodes', function(){
83 | xit('continues adding smaller data to the left down the tree', function(){
84 | tree.push(5);
85 | tree.push(4);
86 | tree.push(3);
87 | expect(tree.rootNode.data).to.eq(5, 'rootNode was not set correctly');
88 | expect(tree.rootNode.left.data).to.eq(4, 'first node to the left not set correctly');
89 | expect(tree.rootNode.left.left.data).to.eq(3, 'last node to the left not set correctly');
90 | });
91 |
92 | xit('continues adding larger data to the left down the tree', function(){
93 | tree.push(5);
94 | tree.push(6);
95 | tree.push(7);
96 | expect(tree.rootNode.data).to.eq(5, 'rootNode was not set correctly');
97 | expect(tree.rootNode.right.data).to.eq(6, 'first node to the right not set correctly');
98 | expect(tree.rootNode.right.right.data).to.eq(7, 'last node to the right not set correctly');
99 | });
100 |
101 | xit('creates a tree structure with multiple nodes', function(){
102 | // Node(1)
103 | // /
104 | // Node(2)
105 | // / \
106 | // / Node(3)
107 | // RootNode(4)
108 | // \ Node(5)
109 | // \ /
110 | // Node(6)
111 | // \
112 | // Node(7)
113 | tree.push(4);
114 | tree.push(6);
115 | tree.push(7);
116 | tree.push(2);
117 | tree.push(3);
118 | tree.push(5);
119 | tree.push(1);
120 |
121 | expect(tree.rootNode.data).to.eq(4)
122 |
123 | expect(tree.rootNode.left.data).to.eq(2);
124 | expect(tree.rootNode.right.data).to.eq(6);
125 |
126 | expect(tree.rootNode.left.left.data).to.eq(1);
127 | expect(tree.rootNode.left.right.data).to.eq(3);
128 |
129 | expect(tree.rootNode.right.left.data).to.eq(5);
130 | expect(tree.rootNode.right.right.data).to.eq(7);
131 | });
132 | });
133 | });
134 |
135 | describe('.find', function(){
136 | context('in an empty tree', function(){
137 | xit('returns null', function(){
138 | expect(tree.find(6)).to.eq(null);
139 | });
140 | });
141 |
142 | context('in a tree with 1 node', function(){
143 | beforeEach(function(){
144 | tree.push(5);
145 | });
146 |
147 | xit('can find a match', function(){
148 | var result = tree.find(5);
149 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
150 | expect(result.data).to.eq(5);
151 | });
152 |
153 | xit('returns null if no match', function(){
154 | var result = tree.find(80);
155 | expect(result).to.eq(null);
156 | });
157 | });
158 |
159 | context('in a complex tree', function(){
160 | beforeEach(function(){
161 | // Node(1)
162 | // /
163 | // Node(2)
164 | // / \
165 | // / Node(3)
166 | // RootNode(4)
167 | // \ Node(5)
168 | // \ /
169 | // Node(6)
170 | // \
171 | // Node(7)
172 | tree.push(4);
173 | tree.push(6);
174 | tree.push(7);
175 | tree.push(2);
176 | tree.push(3);
177 | tree.push(5);
178 | tree.push(1);
179 | });
180 |
181 | xit('can find the root', function(){
182 | var result = tree.find(4);
183 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
184 | expect(result.data).to.eq(4);
185 | });
186 |
187 | xit('can find results to the immediate left', function(){
188 | var result = tree.find(2);
189 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
190 | expect(result.data).to.eq(2);
191 | });
192 |
193 | xit('can find results to the far left', function(){
194 | var result = tree.find(1);
195 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
196 | expect(result.data).to.eq(1);
197 | });
198 |
199 | xit('can find results to the immediate right', function(){
200 | var result = tree.find(6);
201 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
202 | expect(result.data).to.eq(6);
203 | });
204 |
205 | xit('can find nested results', function(){
206 | var result = tree.find(5);
207 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
208 | expect(result.data).to.eq(5);
209 |
210 | var result = tree.find(3);
211 | expect(result instanceof TreeNode).to.eq(true, 'is not returning a TreeNode');
212 | expect(result.data).to.eq(3);
213 | });
214 |
215 | xit('can return null if none found', function(){
216 | var result = tree.find(80);
217 | expect(result).to.eq(null);
218 | });
219 | });
220 | });
221 |
222 | describe('.toArray', function(){
223 | context('with an empty tree', function(){
224 | xit('returns an empty array', function(){
225 | expect(tree.toArray()).to.deep.eq([]);
226 | });
227 | });
228 |
229 | context('with nodes', function(){
230 | xit('pulls data from the tree into an array, starting with the left branches of the tree', function(){
231 | tree.push(5);
232 | tree.push(4);
233 | tree.push(6);
234 | tree.push(7);
235 | tree.push(3);
236 | expect(tree.toArray()).to.deep.eq([5,4,3,6,7]);
237 | });
238 | });
239 | });
240 |
241 | describe('.sort', function(){
242 | context('with an empty tree', function(){
243 | xit('returns an empty array', function(){
244 | expect(tree.sort()).to.deep.eq([]);
245 | });
246 | });
247 |
248 | context('with nodes', function(){
249 | xit('returns a sorted array of tree elements', function(){
250 | tree.push(5)
251 | tree.push(4)
252 | tree.push(6)
253 | tree.push(7)
254 | tree.push(3)
255 | tree.push(2)
256 | tree.push(2102)
257 | expect(tree.sort()).to.deep.eq([2,3,4,5,6,7,2102]);
258 | });
259 | });
260 | });
261 |
262 | describe('.min and .max', function(){
263 | // note that given the inherent left/right structure of a binary search tree
264 | //it is possible to find the min or max elements without searching the entire tree
265 | context('with an empty tree', function(){
266 | xit('min returns null', function(){
267 | expect(tree.min()).to.eq(null);
268 | });
269 |
270 | xit('max returns null', function(){
271 | expect(tree.max()).to.eq(null);
272 | });
273 | });
274 |
275 | context('with nodes', function(){
276 | beforeEach(function(){
277 | // Node(1)
278 | // /
279 | // Node(2)
280 | // / \
281 | // / Node(3)
282 | // RootNode(4)
283 | // \ Node(5)
284 | // \ /
285 | // Node(6)
286 | // \
287 | // Node(7)
288 | tree.push(4);
289 | tree.push(6);
290 | tree.push(7);
291 | tree.push(2);
292 | tree.push(3);
293 | tree.push(5);
294 | tree.push(1);
295 | });
296 |
297 | xit('finds the min value', function(){
298 | expect(tree.min()).to.eq(1);
299 | });
300 |
301 | xit('finds the max value', function(){
302 | expect(tree.max()).to.eq(7);
303 | });
304 | });
305 | });
306 |
307 | describe('.postOrdered', function(){
308 | context('with an empty tree', function(){
309 | xit('returns an empty array', function(){
310 | expect(tree.postOrdered()).to.deep.eq([]);
311 | });
312 | });
313 | context('with a complex tree', function(){
314 | // post_order should return the elements of the tree from a 'bottom-up' perspective,
315 | // starting at the bottom-left-most element, then working right, and then progressively
316 | // up the tree
317 | // so, for example the tree:
318 | // 4
319 | // / \
320 | // 2 5
321 | // / \
322 | // 1 3
323 | // should produce post_ordered output [1,3,2,5,4]
324 | xit('should give back elements in post-order', function(){
325 | tree.push(4);
326 | tree.push(2);
327 | tree.push(5);
328 | tree.push(1);
329 | tree.push(3);
330 | expect(tree.postOrdered()).to.deep.eq([1,3,2,5,4]);
331 | });
332 | });
333 | });
334 | });
335 |
--------------------------------------------------------------------------------
/binary_trees/javascript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Linked List Test Suite
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/binary_trees/ruby/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | guard :minitest do
5 | watch(%r{^test/(.*)\/?(.*)\.rb$})
6 | watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
7 | end
8 |
--------------------------------------------------------------------------------
/binary_trees/ruby/lib/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turingschool/data_structures_and_algorithms/f9e9b47900e84e55d93be51600e51bb9297868aa/binary_trees/ruby/lib/.gitkeep
--------------------------------------------------------------------------------
/binary_trees/ruby/test/binary_search_tree_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require 'minitest/pride'
4 | require 'minitest/spec'
5 | require_relative '../lib/binary_search_tree'
6 |
7 | describe Node do
8 | # A Node represents a location in the binary tree
9 | # It holds data and includes a reference to its left and right nodes
10 |
11 | it "has data" do
12 | assert_equal 0, Node.new(0).data
13 | end
14 |
15 | it "has a left node" do
16 | skip
17 | assert_equal 1, Node.new(0, Node.new(1)).left.data
18 | end
19 |
20 | it "has a right node" do
21 | skip
22 | assert_equal 2, Node.new(0, nil, Node.new(2)).right.data
23 | end
24 | end
25 |
26 | describe BinarySearchTree do
27 | before do
28 | @tree = BinarySearchTree.new
29 | end
30 | describe "#root_node" do
31 | it "is nil for an empty list" do
32 | skip
33 | assert_nil BinarySearchTree.new.root_node
34 | end
35 |
36 | it "adds a new root node when pushed" do
37 | skip
38 | @tree.push(1)
39 | assert_equal 1, @tree.root_node.data
40 | end
41 | end
42 |
43 | describe "#push" do
44 | # push adds a datum to the tree. In order to
45 | # provide a nicer interface, we will accept raw numbers as inputs to
46 | # push, and handle wrapping the data in a Node internally
47 | it "adds data smaller than the root node to the left of the root" do
48 | skip
49 | @tree.push(5) #root
50 | @tree.push(4)
51 | assert_equal 4, @tree.root_node.left.data
52 | end
53 |
54 | it "adds data equal to the root node to the left of the root" do
55 | skip
56 | @tree.push(5) #root
57 | @tree.push(5)
58 | assert_equal 5, @tree.root_node.left.data
59 | end
60 |
61 | it "adds data larger than the root node to the right of the root" do
62 | skip
63 | @tree.push(5) #root
64 | @tree.push(7)
65 | assert_equal 7, @tree.root_node.right.data
66 | end
67 |
68 | it "continues adding smaller data to the left down the tree" do
69 | skip
70 | @tree.push(5) #root
71 | @tree.push(4)
72 | @tree.push(3)
73 | assert_equal 3, @tree.root_node.left.left.data
74 | end
75 |
76 | it "continues adding larger data to the right down the tree" do
77 | skip
78 | @tree.push(5) #root
79 | @tree.push(6)
80 | @tree.push(7)
81 | assert_equal 7, @tree.root_node.right.right.data
82 | end
83 | end
84 |
85 | describe "#count" do
86 | # count tells us the number of nodes in the tree
87 | it "is 0 for an empty tree" do
88 | skip
89 | assert_equal 0, @tree.count
90 | end
91 |
92 | it "is 1 for a tree with a root node" do
93 | skip
94 | @tree.push(5)
95 | assert_equal 1, @tree.count
96 | end
97 |
98 | it "continues to count elements as they are added" do
99 | skip
100 | @tree.push(6)
101 | @tree.push(4)
102 | @tree.push(3)
103 | @tree.push(2)
104 | assert_equal 4, @tree.count
105 | end
106 | end
107 |
108 | describe "#include?" do
109 | # include? tells us whether a piece of data exists in the tree
110 | it "is false for an empty tree" do
111 | skip
112 | assert_equal false, @tree.include?(5)
113 | end
114 |
115 | it "is true for the data of the root node" do
116 | skip
117 | @tree.push(4)
118 | assert_equal true, @tree.include?(4)
119 | end
120 |
121 | it "finds data lower in the tree" do
122 | skip
123 | @tree.push(4)
124 | @tree.push(6)
125 | @tree.push(3356)
126 | @tree.push(1)
127 | assert_equal true, @tree.include?(6)
128 | assert_equal true, @tree.include?(3356)
129 | assert_equal false, @tree.include?(11111)
130 | assert_equal true, @tree.include?(1)
131 | end
132 | end
133 |
134 | describe "#to_array" do
135 | it "is empty for empty tree" do
136 | skip
137 | assert_equal [], @tree.to_array
138 | end
139 |
140 | it "pulls data from the tree into an array, starting with the left branches of the tree" do
141 | skip
142 | @tree.push(5)
143 | @tree.push(4)
144 | @tree.push(6)
145 | @tree.push(7)
146 | @tree.push(3)
147 | assert_equal [5,4,3,6,7], @tree.to_array
148 | end
149 | end
150 |
151 | describe "#sort" do
152 | it "returns empty array for empty tree" do
153 | skip
154 | assert_equal [], @tree.sort
155 | end
156 |
157 | it "returns a sorted array of the tree elements" do
158 | skip
159 | @tree.push(5)
160 | @tree.push(4)
161 | @tree.push(6)
162 | @tree.push(7)
163 | @tree.push(3)
164 | @tree.push(2)
165 | @tree.push(2102)
166 | assert_equal [2,3,4,5,6,7,2102], @tree.sort
167 | end
168 | end
169 |
170 | describe "#min" do
171 | # note that given the inherent left/right structure of a binary search tree
172 | # it is possible to find the min or max elements without searching the entire tree
173 | it "is nil for an empty tree" do
174 | skip
175 | assert_nil @tree.min
176 | end
177 |
178 | it "finds the minimum value in the tree" do
179 | skip
180 | @tree.push(5)
181 | @tree.push(4)
182 | @tree.push(6)
183 | @tree.push(7)
184 | @tree.push(3)
185 | @tree.push(1)
186 | assert_equal 1, @tree.min
187 | end
188 | end
189 |
190 | describe "#max" do
191 | # note that given the inherent left/right structure of a binary search tree
192 | # it is possible to find the min or max elements without searching the entire tree
193 | it "is nil for an empty tree" do
194 | skip
195 | assert_nil @tree.max
196 | end
197 |
198 | it "finds the maximum value in the tree" do
199 | skip
200 | @tree.push(5)
201 | @tree.push(4)
202 | @tree.push(6)
203 | @tree.push(7)
204 | @tree.push(3)
205 | @tree.push(1)
206 | assert_equal 7, @tree.max
207 | end
208 | end
209 |
210 | describe "#post_ordered" do
211 | # post_order should return the elements of the tree from a 'bottom-up' perspective,
212 | # starting at the bottom-left-most element, then working right, and then progressively
213 | # up the tree
214 | # so, for example the tree:
215 | # 4
216 | # / \
217 | # 2 5
218 | # / \
219 | # 1 3
220 | # should produce post_ordered output [1,3,2,5,4]
221 |
222 | it "should be empty for empty tree" do
223 | skip
224 | assert_equal [], @tree.post_ordered
225 | end
226 |
227 | it "should give back elements in post-order" do
228 | skip
229 | @tree.push(4)
230 | @tree.push(2)
231 | @tree.push(5)
232 | @tree.push(1)
233 | @tree.push(3)
234 |
235 | assert_equal [1,3,2,5,4], @tree.post_ordered
236 | end
237 | end
238 |
239 | describe "#min_height" do
240 | it "is 0 for empty tree" do
241 | skip
242 | assert_equal 0, @tree.min_height
243 | end
244 |
245 | it "is 1 for tree with root node only" do
246 | skip
247 | @tree.push(1)
248 | assert_equal 1, @tree.min_height
249 | end
250 |
251 | it "finds shortest path from root node to a leaf" do
252 | skip
253 | # 4
254 | # / \
255 | # 2 6
256 | # / \
257 | # 1 3
258 | @tree.push(4)
259 | @tree.push(2)
260 | @tree.push(1)
261 | @tree.push(3)
262 | @tree.push(6)
263 | assert_equal 2, @tree.min_height
264 | end
265 | end
266 |
267 | describe "#max_height" do
268 | it "is 0 for empty tree" do
269 | skip
270 | assert_equal 0, @tree.max_height
271 | end
272 |
273 | it "is 1 for tree with root node only" do
274 | skip
275 | @tree.push(1)
276 | assert_equal 1, @tree.max_height
277 | end
278 |
279 | it "finds shortest path from root node to a leaf" do
280 | skip
281 | # 4
282 | # / \
283 | # 2 6
284 | # / \
285 | # 1 3
286 | @tree.push(4)
287 | @tree.push(2)
288 | @tree.push(1)
289 | @tree.push(3)
290 | @tree.push(6)
291 | assert_equal 3, @tree.max_height
292 | end
293 | end
294 |
295 | describe "#balanced?" do
296 | # A binary tree is balanced if its max depth and min depth are within
297 | # 1 of each other.
298 | it "is balanced for an empty tree" do
299 | skip
300 | assert @tree.balanced?
301 | end
302 |
303 | it "is balanced for a nice tidy tree" do
304 | skip
305 | # 4
306 | # / \
307 | # 2 6
308 | # / \ \ \
309 | # 1 3 5 7
310 | @tree.push(4)
311 | @tree.push(2)
312 | @tree.push(1)
313 | @tree.push(3)
314 | @tree.push(6)
315 | @tree.push(5)
316 | @tree.push(7)
317 | assert_equal 3, @tree.min_height
318 | assert_equal 3, @tree.max_height
319 | assert @tree.balanced?
320 | end
321 |
322 | it "is false for tightly ordered tree" do
323 | skip
324 | @tree.push(1)
325 | @tree.push(2)
326 | @tree.push(3)
327 | @tree.push(4)
328 | refute @tree.balanced?
329 | end
330 | end
331 |
332 | describe "#balance!" do
333 | it "re-balances unbalanced tree" do
334 | skip
335 | @tree.push(1)
336 | @tree.push(2)
337 | @tree.push(3)
338 | @tree.push(4)
339 | refute @tree.balanced?
340 | @tree.balance!
341 | assert @tree.balanced?
342 | end
343 |
344 | it "balances without removing elements from the tree" do
345 | skip
346 | @tree.push(1)
347 | @tree.push(2)
348 | @tree.push(3)
349 | @tree.push(4)
350 | assert_equal [1,2,3,4], @tree.sort
351 | @tree.balance!
352 | assert_equal [1,2,3,4], @tree.sort
353 | end
354 | end
355 | end
356 |
--------------------------------------------------------------------------------
/bitwise_binary_operators/README.md:
--------------------------------------------------------------------------------
1 | - Note: This explanation is currently based in JavaScript
2 |
3 | # Color & Bitwise Binary Operators
4 |
5 | ## What is a Bit
6 |
7 | A bit is a basic unit of information. AKA a binary digit.
8 |
9 | It can only have one of two values. These values are most commonly represented as a 1 or a 0.
10 |
11 | Remember taking those punch cards style tests when you were little? Where you circled in the little dots? That was where the concept of a bit came in. Paper could be fed into a computer, and depending on whether holes were punched in or not was the data was passed around.
12 |
13 | ## What is Decimal
14 |
15 | Our integer numbering system is base 10. Meaning, we use 10 different symbols to represent numbers.
16 |
17 | | Decimal |
18 | |-------------|
19 | | 0 |
20 | | 1 |
21 | | 2 |
22 | | 3 |
23 | | 4 |
24 | | 5 |
25 | | 6 |
26 | | 7 |
27 | | 8 |
28 | | 9 |
29 |
30 | So in order to get a decimal number from, say, a string - we would use the following code.
31 |
32 | ```javascript
33 | var num = '7';
34 | parseInt(num, 10);
35 | ```
36 |
37 | [parseInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) is a function we're going to hear about a lot in this lesson.
38 |
39 | It acceptes two parameters:
40 | - string
41 | - The value to parse. If it's not a string, the function converts it to one using `toString`.
42 | - radix
43 | - And integer between 2 and 36 that is the base in the mathematical numeral system.
44 |
45 | If you recall, we want to convert this string to a decimal integer - so we pass `10` in as our radix.
46 |
47 | `parseInt` will usually default to base ten if no radix is specified, but it is best practice to **always specify this parameter** to avoid confusion and guarantee predicatable behavior.
48 |
49 | ## What is Binary
50 |
51 | Computers count using binary, which is a number system made up of zeros and ones (bits).
52 |
53 | So if we wanted to convert a Number to binary, we could do so in the following way.
54 |
55 | ```javascript
56 | var num = 10;
57 | num.toString(2);
58 | ```
59 |
60 | [toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) is a function we will also be using often in this lesson.
61 |
62 | Here you are calling the Number prototype toString method and passing it a radix of 2.
63 |
64 | Note: If you don't specify a radix, toString will default to base 10 (decimal)
65 |
66 | Putting things all together, if you wanted to write a decimal to binary converter that could handle string AND integer input - you might write something like:
67 |
68 | ```javascript
69 | parseInt(n, 10).toString(2);
70 | // if string, convert to base ten number type
71 | // if already number type, convert to string and convert back to Number
72 | // call Number's prototype function toString() and tell it base 2
73 | ```
74 |
75 | Note: What if the decimal is a negative number? Try reading through the top answer on this [StackOverflow](http://stackoverflow.com/questions/9939760/how-do-i-convert-an-integer-to-binary-in-javascript) and using the `>>>` (right logical shift)
76 |
77 | ## What is Hexadecimal
78 |
79 | Hexadecimal is base 16, meaning it uses sixteen characters to display numbers.
80 |
81 | | Decimal | Hexadecimal |
82 | |---------|-------------|
83 | | 0 - 10 | 0 - 9 |
84 | | 10 - 15 | A - F |
85 | | 16 - 25 | 10 - 19 |
86 | | 26 | 1A |
87 | | 27 | 1B |
88 | | ... etc | ... etc |
89 |
90 | So if we wanted to convert a decimal to hex
91 |
92 | ```javascript
93 | var num = 11;
94 | num.toString(16); // "b"
95 |
96 | var num = '11';
97 | parseInt(num, 10).toString(16)
98 | ```
99 |
100 | If you want to see the entire graph, try running the following code in a console
101 |
102 | ```javascript
103 | for(var i = 0; i < 100; i++){
104 | console.log(i, ' - ', i.toString(16));
105 | }
106 | ```
107 | Hexadecimal was widely adopted because it is so easy to convert from hexadecimal to binary (the language of computers). Basically, hexadecimal is used to display binary in a shorter string.
108 |
109 | Binary is base 2, hexadecimal is base 16.
110 |
111 | 2 to the power of 4 is 16
112 |
113 | So you need a 4 digit binary to map to a one digit hexadecimal symbol.
114 |
115 | | Hexadecimal | Binary |
116 | |-------------|--------|
117 | | 0 | 0000 |
118 | | 1 | 0001 |
119 | | 2 | 0010 |
120 | | 3 | 0011 |
121 | | 4 | 0100 |
122 | | 5 | 0101 |
123 | | 6 | 0110 |
124 | | 7 | 0111 |
125 | | 8 | 1000 |
126 | | 9 | 1001 |
127 | | A | 1010 |
128 | | B | 1011 |
129 | | C | 1100 |
130 | | D | 1101 |
131 | | E | 1110 |
132 | | F | 1111 |
133 |
134 | ## What is RGB
135 |
136 | Color or a TV or computer screen is controlled by adjusting three settings: Red, Green and Blue.
137 |
138 | Each color value can range between 0 to 255
139 |
140 | If all colors are set to zero (0, 0, 0) - the absense of light sets the screen to black.
141 |
142 | If all three colors are set as high as possible (255, 255, 255) - the screen will be white.
143 |
144 | The reason for 0 to 255 is because 8 digits in a binary system is the same as 255.
145 |
146 | RGB values are encoded as 8-bit integers.
147 |
148 | 1111 1111 in binary equals 255.
149 |
150 | - Blue: Bits from 0-7
151 | - Green: Bits from 8-15
152 | - Red: Bits from 16-23
153 |
154 | ## What is a Bitwise Operation
155 |
156 | A bitwise operation proccesses bits one at a time. In other languages, they can be refered to as bit `shifters` which might make what they do a little clearer.
157 |
158 | There is an [MDN article on how to use bitwise operators in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators).
159 |
160 | > Bitwise operators treat their operands as a sequence of 32 bits (zeroes and ones), rather than as decimal, hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.
161 |
162 | Which basically means, these operators convert numbers to their bits and work with them at the bit level.
163 |
164 | #### An Example
165 |
166 | Integers are stored, in memory, as a series of bits. For example, the number 6 when stored as a 32-bit `int` is:
167 |
168 | ```
169 | 00000000 00000000 00000000 00000110
170 | ```
171 |
172 | So if you shifted the bit patter to the left one position with a left shift operator `(6 << 1)`, it would be
173 |
174 | ```
175 | 00000000 00000000 00000000 00001100
176 | ```
177 |
178 | Which equals `12` in decimal.
179 |
180 | Take a second to scroll up and look at the hexadecimal to binary table above and compare the 2 outcomes.
181 |
182 | 0110 is 6 (in both hexadecimal and decimal symbols)
183 |
184 | 1100 is 'c' in hexadecimal
185 |
186 | If you then convert hexadecimal to decimal `parseInt('c', 16)`
187 |
188 | You get 12.
189 |
190 | #### An Example with Color
191 |
192 | Bitwise operators are not something we use every day in JavaScript - but in the case of converting rgb to hex codes, it's super effective.
193 |
194 | ```javascript
195 | var hex = 'FFEBCD'; //blanchedalmond
196 | var rgb = parseInt(hex, 16); // 16772045
197 | // if we convert to a series of bits rgb = "111111111110101111001101"
198 |
199 | // 0xFF is the same as 11111111
200 | var r = (rgb >> 16) & 0xFF; // 255
201 | var g = (rgb >> 8) & 0xFF; // 235
202 | var b = rgb & 0xFF; // 205
203 | ```
204 |
205 | `(rbg >> 16)` = 255
206 |
207 | What happens is we right shift by 16 bits
208 |
209 | so
210 |
211 | rbg is "111111111110101111001101"
212 |
213 | The r value is "11111111"
214 |
215 | `(rgb >> 8)` = 235
216 |
217 | So we shift right 8 bits
218 |
219 | The g value is "11101011"
220 |
221 | But then for blue, we do something interesting and take the entire bit sequence "111111111110101111001101"
222 |
223 | How does this work?
224 |
225 | Now it's time to explain the `Bitwise AND` or `&`
226 |
227 | ```
228 | a & b
229 | ```
230 |
231 | The Bitwise AND operator (`&`) returns a one in each position for the which the corresponding bits are both operands and ones.
232 |
233 | So if `0xFF` is the same as `11111111`...
234 |
235 | then when we call `111111111110101111001101` & `11111111`
236 |
237 | We get `11001101`
238 |
239 | In other words, we get the last 8 bits.
240 |
241 | Mind blown? That's okay. Play around with it a little bit and [read through the docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators).
242 |
243 | # Next Steps
244 |
245 | Open javascript/index.html to view tests
246 |
247 | Note: Knowing just a little bit about `.match()`, `.eval()` and `.test()` in relation to basic regex may save you some time - Learn about [regex in JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
248 |
249 | #### hexToDecimalConverter
250 |
251 | Start by getting the `javascript/hexToDecimal-test.js` passing
252 |
253 | #### rgbToHex
254 |
255 | Then get the rgbToHex tests passing
256 |
257 | #### Bonus round
258 |
259 | Knowing what you now know, can you create any of the following?
260 |
261 | - In CodePen: A random rgb color generator that changes the background of a div every few seconds
262 |
263 | - In CodePen: A script that changes the color of a div by converting the current time of day to rgb.
264 |
265 | - Work backwards from this line of code in jQuery to figure out what the bitwise operators here are doing? [Code](https://github.com/jquery/jquery/blob/2d4f53416e5f74fa98e0c1d66b6f3c285a12f0ce/external/sizzle/dist/sizzle.js#L150) and [full cdn](https://code.jquery.com/jquery-3.1.1.js)
266 |
267 | - A decimal to hex function and test suite that _handles negative numbers correctly_
268 |
269 | - A converter that handles [HSL and HSV](https://en.wikipedia.org/wiki/HSL_and_HSV)
270 |
271 | # Resources
272 |
273 | ## Good Resources
274 |
275 | - [What is a bit](https://en.wikipedia.org/wiki/Bit)
276 | - [MDN JavaScrpt Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators)
277 | - http://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work
278 |
279 | ## Meh Resources
280 | - http://rainyjune.net/node/341
281 | - [javascript-bit-manipulation](http://www.i-programmer.info/programming/javascript/2550-javascript-bit-manipulation.html)
282 | - [Color, Hexadecimal Numbers & Bitwise Binary Operators](http://www.webwasp.co.uk/tutorials/220/color.php)
283 | - [using-logical-bitshift-for-rgb-values](http://stackoverflow.com/questions/5751689/using-logical-bitshift-for-rgb-values)
284 |
--------------------------------------------------------------------------------
/bitwise_binary_operators/javascript/README.md:
--------------------------------------------------------------------------------
1 | # Bitwise Binary Operators Problem
2 |
3 | ## Running the Tests
4 |
5 | You can run the tests in this folder in the browser.
6 |
7 | To run in the browser, open the `index.html` page and you should see your tests.
8 |
--------------------------------------------------------------------------------
/bitwise_binary_operators/javascript/hexToDecimal-test.js:
--------------------------------------------------------------------------------
1 | describe('hexToDecimal', function(){
2 | it('should convert a single decimal number', function() {
3 | var subject = '1';
4 | expect(hexToDecimal(subject)).to.eq(1);
5 | });
6 |
7 | xit('should convert one letter', function() {
8 | var subject = 'c';
9 | expect(hexToDecimal(subject)).to.eq(12);
10 | });
11 |
12 | xit('should convert 10', function() {
13 | var subject = '10';
14 | expect(hexToDecimal(subject)).to.eq(16);
15 | });
16 |
17 | xit('should convert multiple letters', function() {
18 | var subject = 'af';
19 | expect(hexToDecimal(subject)).to.eq(175);
20 | });
21 |
22 | xit('should convert large numbers', function() {
23 | var subject = '100';
24 | expect(hexToDecimal(subject)).to.eq(256);
25 | });
26 |
27 | xit('should convert large numbers and letters', function() {
28 | var subject = '19ace';
29 | expect(hexToDecimal(subject)).to.eq(105166);
30 | });
31 |
32 | xit('should return null for an invalid hex code', function(){
33 | var subject = 'bananarama';
34 | expect(hexToDecimal(subject)).to.eq(null);
35 | });
36 |
37 | xit('should convert white', function() {
38 | var subject = 'ffffff';
39 | expect(hexToDecimal(subject)).to.eq(16777215);
40 | });
41 |
42 | xit('should convert papayawhip', function() {
43 | var subject = 'ffefd5';
44 | expect(hexToDecimal(subject)).to.eq(16773077);
45 | });
46 | });
--------------------------------------------------------------------------------
/bitwise_binary_operators/javascript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bitwise Binary Operators Test Suite
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/bitwise_binary_operators/javascript/rgbToHex-test.js:
--------------------------------------------------------------------------------
1 | describe('colorToHex', function(){
2 | it('should convert white', function() {
3 | var white = 'rgb(255, 255, 255)';
4 | expect(colorToHex(white)).to.eq('#ffffff')
5 | });
6 |
7 | xit('should convert papayawhip (and be able to handle missing rgb)', function() {
8 | var papayawhip = '(255, 239, 213)';
9 | expect(colorToHex(papayawhip)).to.eq('#ffefd5')
10 | });
11 |
12 | xit('should convert steelblue (and be able to handle missing spaces)', function() {
13 | var steelblue = '(70,130,180)';
14 | expect(colorToHex(steelblue)).to.eq('#4682b4')
15 | });
16 |
17 | xit('should convert magenta', function() {
18 | var magenta = 'rgb(255, 0, 255)';
19 | expect(colorToHex(magenta)).to.eq('#ff00ff')
20 | });
21 |
22 | xit('should convert yellow', function() {
23 | var yellow = 'rgb(255, 255, 0)';
24 | expect(colorToHex(yellow)).to.eq('#ffff00')
25 | });
26 |
27 | xit('should convert green', function() {
28 | var green = 'rgb(0, 255, 0)';
29 | expect(colorToHex(green)).to.eq('#00ff00')
30 | });
31 |
32 | // It starts getting tricky here!
33 |
34 | xit('should convert black', function() {
35 | var black = 'rgb(0, 0, 0)';
36 | expect(colorToHex(black)).to.eq('#000000')
37 | });
38 |
39 | xit('should return the hex value if accidently given a hex', function() {
40 | expect(colorToHex('#ffffff')).to.eq('#ffffff');
41 | });
42 | })
--------------------------------------------------------------------------------
/bloom_filters/README.markdown:
--------------------------------------------------------------------------------
1 | ## Bloom Filters
2 |
3 | ### Background
4 |
5 | A [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter) is a special-purpose
6 | data structure used to store _sets_ of data and determine if a given element is
7 | present in the set.
8 |
9 | There are other data structures we could use for this purpose ([Hash Maps](/hash_tables) or Sets come to mind),
10 | but Bloom Filters are particularly useful due to their space consumption properties.
11 | A Bloom Filter containing a given number of elements will consume much less space
12 | than a HashMap or Set containing the same elements.
13 |
14 | This is possible because Bloom Filters are a _probabilistic_ data structure -- they
15 | can tell you that an item is _probably in_ the set or that it is _definitely not in_ the set,
16 | but not that it is _definitely in_ the set. In other words, a Bloom Filter can
17 | sometimes give false positives, but never false negatives.
18 |
19 | This may sound silly at first, but in many applications, this type of behavior is actually
20 | perfectly acceptable, and if you can get by with "probable inclusion" in an application,
21 | you can take advantage of the great space savings a bloom filter provides.
22 |
23 | ### Construction
24 |
25 | To see how a Bloom Filter derives these properties, let's look at how one is constructed.
26 |
27 | A Bloom Filter is built on 2 main principles:
28 |
29 | 1. Bit Vector to represent the set of words
30 | 2. Collection of 2 or more hash functions for computing attribute presence
31 |
32 | Instead of using a more sophisticated storage mechanism like an array, a Bloom Filter
33 | uses a simple "bit vector" -- simply a binary integer which we will treat as a
34 | collection of 0/1 bits rather than as a single composite number.
35 |
36 | However to keep things a bit simpler, we can also represent the vector
37 | as a simple array of 8 0's.
38 |
39 | Let's imagine a simple 8-element array with no items in the set:
40 |
41 | ```
42 | set = [0,0,0,0,0,0,0,0]
43 | ```
44 |
45 | To add an element to the set, we'll use our hashing functions to generate
46 | `n` different hashes for the target string. For simplicity, we'll use MD5,
47 | SHA1, and SHA2:
48 |
49 | ```
50 | require "digest"
51 | element = "pizza"
52 | d1 = Digest::MD5.hexdigest(element)
53 | d2 = Digest::SHA1.hexdigest(element)
54 | d3 = Digest::SHA2.hexdigest(element)
55 | ```
56 |
57 | Each of these digests will give us a hexadecimal number representing a hash
58 | value of our input.
59 |
60 | Next we need to convert these hexadecimal digests into numbers, and modulo
61 | those numbers by the length of the bit array.
62 |
63 | ```
64 | index1 = d1.hex % set.length
65 | => 0
66 | index2 = d2.hex % set.length
67 | => 7
68 | index3 = d3.hex % set.length
69 | => 6
70 | ```
71 |
72 | Now, as a final insertion step, we need to toggle "on" all of the bits
73 | at these positions:
74 |
75 | ```
76 | set[index1] = 1
77 | set[index2] = 1
78 | set[index3] = 1
79 | ```
80 |
81 | At this point our "set" will look like:
82 |
83 | ```
84 | [1, 0, 0, 0, 0, 0, 1, 1]
85 | ```
86 |
87 | Now, to determine if an element is in the set, we would reverse the process,
88 | computing the hashes and vector indices, and determining whether these indices
89 | are present in the vector (set to "1").
90 |
91 | ### Challenges
92 |
93 | 1. Implement a `BloomFilter` class which we can instantiate, `#add` elements to, and check for `#presence?` of an element
94 | 2. Implement the `BloomFilter` using a bit vector instead of an array
95 | 3. Customize your filter to accept a variable size argument for the size of the bit vector.
96 | 4. Implement logic for detecting false positives in the filter. How does the number of false
97 | positives change as we change the size of the storage vector.
98 |
99 | ### More Reading:
100 |
101 | * https://www.jasondavies.com/bloomfilter/
102 | * http://billmill.org/bloomfilter-tutorial/
103 |
--------------------------------------------------------------------------------
/dungeon_generation/README.md:
--------------------------------------------------------------------------------
1 | ### Dungeon Generation
2 |
3 | Try to write an algorithm that generates a random layout of an
4 | imaginary "dungeon" for a game.
5 |
6 | * http://rubyquiz.com/quiz80.html
7 | * https://github.com/adonaac/blog/issues/7
8 |
--------------------------------------------------------------------------------
/graphs/README.md:
--------------------------------------------------------------------------------
1 | ## Graphs and Graph Algorithms
2 |
3 | The term "graph" refers to a large family of data structures that appear
4 | frequently in computer science. At a deeper level a graph is a mathematical
5 | concept that has to do with modeling pieces of data and connections between
6 | them.
7 |
8 | Since we often deal with systems that can be modeled in this way (groups of
9 | nodes with various connections between them), graphs can be a useful data
10 | structure with a variety of applications.
11 |
12 | ### Terminology
13 |
14 | There are a lot of general terms that get thrown around when discussing graphs,
15 | so let's run through some of them.
16 |
17 | * __Vertices:__ These are the "points" in a graph. We'll often want to treat them as a
18 | composite data type that wraps some other piece of data, similar to nodes in a binary
19 | tree or linked list.
20 |
21 | * __Edges:__ Edges are the connections between vertices. Mathematically we might say they
22 | are a "set" unto themselves (in addition to the "set" of vertices which contain the graph's
23 | data), but in programming we would often represent them as object references.
24 |
25 | * __Adjacency:__ 2 vertices are adjacent if there is an edge connecting them.
26 |
27 | * __Graph:__ A data structure consisting of a set of Vertices and a set of Edges. Useful for
28 | modeling data where there are connections between different pieces of data.
29 |
30 | * __Loop:__ An edge connecting a vertex to itself
31 |
32 | * __Degree:__ The Degree of a vertex is the number of edges connecting to it. A self loop
33 | counts twice.
34 |
35 | ### Represeting Graphs
36 |
37 | There are a lot of ways to represent a graphs, but they largely fall into 2 categories -- textual/mathematical
38 | and graphical.
39 |
40 | When representing a graph graphically, it's common to represent vertices as circles containing identifiers
41 | and edges as lines between them. An unconnected vertex would be floating on the side with no lines to it.
42 |
43 | Here's one example:
44 |
45 | 
46 |
47 | When representing a graph textually, it's common to represent it as a set of vertices:
48 |
49 | ```
50 | {1,2,3,4,5,6,7,8}
51 | ```
52 |
53 | And a set of Edges representing connections between pairs of vertices:
54 |
55 | ```
56 | {(1,7), (2,6), (3,1), (3,5), (4,6), (5,4), (5,2), (6,8), (7,2), (7,8)}
57 | ```
58 |
59 | Mathematically, a graph is often represented as 2 _sets_ -- one of edges and one of vertices.
60 |
61 | ### Graph Types
62 |
63 | Within the broader family of "graphs", we'll often categorize individual graphs based on
64 | various properties. Let's run through a few of these:
65 |
66 | * __Undirected:__ A graph where edges point in both directions at once. An undirected graph `A <-> B`
67 | would allow you to traverse A to B _or_ B to A
68 |
69 | * __Directed:__ A graph where edges point in only one direction. A directed graph `A -> B` would
70 | allow you to traverse from A to B but not from B to A.
71 |
72 | * __Cyclic:__ A graph where a path exists from a vertex back to itself. This could be done via traversing
73 | multiple other vertices, or via a self-referential edge which points from the vertex back to itself.
74 | The opposite of a Cyclic graph would be an __Acyclic Graph__ -- no cycles exist.
75 |
76 | * __Weighted:__ A graph where edges are labeled with an additional piece of data representing a "weight".
77 | This is often used to represent a graph where some edges are more costly to traverse than others
78 | (pathfinding with variable terrain, for example).
79 |
80 | * __Regular:__ A graph where all vertices have the same degree -- i.e. every vertex has the same number
81 | of connections to other vertices
82 |
83 | * __Connected:__ A graph where all vertices can be reached from any other vertex -- i.e. every vertex is
84 | connected via some sequence of edges. (Opposite would be a __Disconnected Graph__)
85 |
86 | * __Strongly Connected:__ A graph where every vertex is reachable from every other vertex.
87 |
88 | ### Categorizing a Graph
89 |
90 | An example graph can often be categorized across several of the types mentioned above.
91 |
92 | For example a graph could be Cyclic and Directed, or Undirected and Weighted. Many of
93 | the graphs graphs we interact with in computer science fall into a few common categories.
94 | Let's look at some of them:
95 |
96 | * Undirected Weighted Graph (e.g. terrain, map)
97 | * Directed Acyclic Graph (e.g. git history, spreadsheets, resource dependency tracking)
98 | * Directed Acyclic Regular Graph with Degree 1
99 | * Directed Acyclic Regular Graph with Degree 2
100 |
101 | ### Programming Challenges
102 |
103 | In the context of Graph manipulation, there are a number of common programming
104 | challenges we can look at. A few topics include:
105 |
106 | * Detecting Cycles -- Can we envision an algorithm for traversing a graph and determining if any
107 | "cycles" exist?
108 | * Detecting Connectivity -- Given a set of edges and set of vertices, are all vertices connected?
109 | * Minimum "Cuts" to Disconnect -- Given a connected graph, what is the minimum set of cuts we could
110 | make to disconnect it.
111 | * Shortest/Least Expensive Path -- Find the shortest path between 2 vertices in the graph. Often using
112 | a search algorithm like Breadth-First-Search. To account for variably expensive moves, add weights
113 | and use an algorithm like Dijkstra's Algorithm to find the least expensive path.
114 |
115 | ### More Reading
116 |
117 | * [Princeton Intro to Graph Theory](https://www.cs.princeton.edu/courses/archive/fall06/cos341/handouts/graph1.pdf)
118 | * [Project Euler problem 107](https://projecteuler.net/problem=107)
119 | * [Project Euler problem 79](https://projecteuler.net/problem=79)
120 | * [Euler 79 Discussion](http://alexmic.net/password-derivation-project-euler/)
121 | * [Cycle Detection](http://www.geeksforgeeks.org/detect-cycle-in-a-graph/)
122 | * [Shortest Path](http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/)
123 |
--------------------------------------------------------------------------------
/hash_array_mapped_tries/README.markdown:
--------------------------------------------------------------------------------
1 | ## Hash Array Mapped Trie
2 |
3 | A Hash Array Mapped Trie (HAMT) is a data structure for implementing
4 | a traditional Hash-Map on top of a Trie rather than a traditional
5 | Array-based Hash-Table. The structure is more complex than
6 | a simple Hash Table, but provides a few key benefits, including:
7 |
8 | * Ability to grow the map indefinitely without re-sizing or chaining
9 | * Ability to share repeated structure between multiple maps to allow
10 | for cheap copying
11 |
12 | This last property makes it especially interesting from the perspective
13 | of immutability, which is why Rich Hickey used it as the [foundation](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentHashMap.java)
14 | for many of the immutable collection data structures in Clojure.
15 |
16 | The data structure was invented by Phil Bagwell, and you
17 | can find the original paper on it [here](http://lampwww.epfl.ch/papers/idealhashtrees.pdf).
18 |
19 | ### HAMT Structure
20 |
21 | To implement this data structure, we'll rely on a few key
22 | tools:
23 |
24 | 1. A Hashing Algorithm for uniquely differentiating pieces of data.
25 | Many languages already provide this -- in Ruby you can access an
26 | object's hashcode by calling `#hash` on it, or you can use a hashing function
27 | like the `SHA1` implementation including in the `digest` library.
28 | 2. A trie with very high branching factor -- this lets us store lots
29 | of data in a very shallow (and speedy) structure.
30 | 3. Bitwise operations to "consume" the data's hash code in small chunks,
31 | turning a hash code into a "path" to the data's location in the trie.
32 |
33 | So what does all this look like in practice? Let's look at
34 | an example creating a HAMT of order 32.
35 |
36 | Within the trie, each level can store 3 things:
37 |
38 | 1. A key
39 | 2. An associated value
40 | 3. Connections to up to 32 nested child trees
41 |
42 | When we want to insert a key-value pair, we'll use the key's
43 | hash code to choose a path through the trie until we find
44 | an empty position to insert it.
45 |
46 | For retrieval, we simply do the same thing in reverse -- hash
47 | the key, find the pathway through the trie represented by
48 | this hashcode, and check tree nodes until we either find the
49 | desired key or "bottom out" at the end of the tree.
50 |
51 | ### Insertion Algorithm
52 |
53 | Let's walk through the insertion process in more detail.
54 |
55 | To insert a piece of data, we need to find an appropriate path
56 | in the trie in which to place it. As we'll see, this path
57 | is ultimately determined by the key's hash value.
58 |
59 | As we walk down the trie, we'll be looking for 3 possible cases:
60 |
61 | 1. The current trie node is empty, so we can insert our new key
62 | and value here
63 | 2. The current trie node is not empty, but its key is equal
64 | to the one we are trying to insert, so we can overwrite its value
65 | 3. The current trie node is not empty, and its key value is not
66 | equal to ours, so we need to go deeper in the trie.
67 |
68 | #### Insertion Case 1
69 |
70 | Consider inserting a new K/V pair into an empty trie.
71 | We'll insert the key "pizza" with the value "yum".
72 | Our trie is empty so far, so the root tree node has no
73 | key and value, so we can insert our pair there.
74 |
75 | Pretty easy so far.
76 |
77 | #### Insertion Case 2
78 |
79 | Let's get the second easy case out of the way -- overwriting
80 | that K/V pair. We can insert the key "pizza" again,
81 | this time with the value of "real yum".
82 |
83 | We find that the root node is not empty, but its key is equal to
84 | the one we're trying to insert, so we simply change the value.
85 |
86 | Also pretty easy.
87 |
88 | #### Insertion Case 3
89 |
90 | Here is where things start to get more interesting.
91 |
92 | Let's insert the key "calzone" with the value "aw yiss".
93 |
94 | We first check the current (root) node -- it does have a
95 | key and value, and the key is *not* the one we're trying
96 | to insert. We need to go deeper into the trie to find
97 | a place for our new pair.
98 |
99 | To insert a key, we first need to generate its
100 | hash value. Again, in Ruby, we can use one of the hashing
101 | functions included in the Digest library. This gives us a (large) numeric
102 | value representing a unique digest of that piece of data.
103 |
104 | For example:
105 |
106 | ```ruby
107 | [1] pry(main)> require "digest"
108 | => true
109 | [2] pry(main)> Digest::SHA1.hexdigest("calzone").to_i(16)
110 | => 334703588949583183218034173573122019749278332384
111 | ```
112 |
113 | To walk the trie and an appropriate location for this element,
114 | we'll "consume" this hash-code in 5-bit chunks.
115 |
116 | Why 5 bits at a time?
117 |
118 | This is determined by the branching factor of the tree
119 | -- with an order-32 trie, we have 32 possible children from each
120 | node in the tree. A 5-bit hash-code chunk allows us to concisely
121 | represent all 32 possible child branches using a single bitmap.
122 | (`2 ** 5 == 32`)
123 |
124 | To get the numeric value of the first 5 bits of our hashcode,
125 | we can bitwise `AND` it with a 5-bit number containing all "on" bits:
126 |
127 | ```
128 | [13] pry(main)> 31.to_s(2)
129 | => "11111"
130 | [14] pry(main)> Digest::SHA1.hexdigest("calzone").to_i(16) & 31
131 | => 0
132 | ```
133 |
134 | This tells us that the "right-most" 5 bits of the number
135 | 334703588949583183218034173573122019749278332384 ("calzone"'s hash code)
136 | are `00000`, or 0.
137 |
138 | This tells us the position in the current node's children array
139 | to insert this element.
140 |
141 | Thus we can move to the `0`th subtree under our current one
142 | and retry our insertion algorithm. In our case, "calzone"
143 | is only the second element to be inserted in the trie, so
144 | the `0`th child of the "pizza" node will be empty, and we
145 | can insert our data there.
146 |
147 | #### Consuming the hash code
148 |
149 | We mentioned that we would "consume" the key's hash code in 5-bit
150 | chunks. This helps us fully exploit the wide branching factor of the
151 | trie to insert a lot of elements in a fairly shallow data structure.
152 |
153 | If we simply re-use the same 5 (rightmost) bits that we used in the
154 | previous example, we effectively turn our trie into a collection
155 | of 32 linked lists, since all elements that share an initial 5-bit
156 | value will stack up on one another in a chain.
157 |
158 | We would prefer to get more of a "zig-zag" effect, and we can achieve
159 | this by making sure we use a different 5-bit chunk at each layer in
160 | the trie.
161 |
162 | To do this, we'll use another bit-wise operator, the **right shift**.
163 |
164 | A bitwise shift simply takes the bits that make a number and slides
165 | them in one direction in another.
166 |
167 | In the case of a left shift, we move the existing bits to the left,
168 | usually padding them with 0's on the righthand side.
169 |
170 | For example:
171 |
172 | ```ruby
173 | [20] pry(main)> 15.to_s(2)
174 | => "1111"
175 | [21] pry(main)> (15 << 4).to_s(2)
176 | => "11110000"
177 | ```
178 |
179 | In our case, we just want to consume the next 5 bits of our
180 | hash code value, so we can use a right shift of 5 bits.
181 |
182 | Consider our "calzone" example from before:
183 |
184 | ```ruby
185 | [24] pry(main)> (Digest::SHA1.hexdigest("calzone").to_i(16) >> 5) & 31
186 | => 15
187 | ```
188 |
189 | We now get a completely different subtrie index, helping us avoid
190 | the "stacking" behavior we would get if we just re-used the existing one.
191 | As we walk down the trie, we want to use this technique to shift off 5 bits at each
192 | layer.
193 |
194 | ### Retrieval Algorithm
195 |
196 | The retrieval process is effectively the same. We'll simply retrieve the located
197 | value rather than inserting one. Consider the same 3 cases:
198 |
199 | 1. The current tree node is empty -- this means we have "bottomed out",
200 | so our key must not exist in the trie
201 | 2. The current tree node contains the key you're searching for, so
202 | retrieve its value.
203 | 3. The current tree node is not empty, but doesn't contain the key
204 | we're looking for. Use another 5-bit slice of the hash code to identify
205 | the next step to take into the trie.
206 |
207 | ## HAMT Performance
208 |
209 | The strength of the HAMT is its wide branching factor. The 32-bit factor
210 | is common because it can be manipulated efficiently on 32-bit processors,
211 | but you could in theory use an even larger factor if needed.
212 |
213 | This branching factor allows us to store a large amount of keys and values
214 | in a relatively shallow tree which will still be very quick to traverse.
215 |
216 | For example in just 6 layers, we could store `33,554,432` (`32 ** 5`, assuming
217 | the root only stores 1 pair) keys and values.
218 |
219 | This means that in reality, the performance of our Tree will be logarithmic,
220 | as opposed to the than the Constant-time performance offered by many
221 | traditional Hash Map implementations. However the log base is `32`,
222 | which grows at such a small rate that its difference to constant time is
223 | fairly negligible.
224 |
225 | ## Recommended List of Operations
226 |
227 | Try implementing the following basic operations on your HAMT:
228 |
229 | * `set(key,val)`
230 | * `get(key)`
231 | * `keys`
232 | * `vals`
233 | * `get_in(key_path)`
234 |
235 | ## Other Considerations -- Structural Sharing
236 |
237 | We mentioned the ability of our tries to potentially share duplicated
238 | structure with other tries. This is a common approach to creating
239 | immutable or "persistent" hash maps and is used in several functional languages like
240 | Clojure, Scala, and Frege.
241 |
242 | The goal for this technique is to preserve every intermediate state of the Map
243 | (i.e. they "persist"). Thus each operation on the map should generate a new
244 | map value rather than modifying an existing one in place.
245 |
246 | This would be problematic if we had to completely copy every node in the trie
247 | each time we changed anything. But because of the trie's
248 | nested structure, we have a better option.
249 |
250 | Whenever we need to change the trie, we duplicate the node in question
251 | as well as all the nodes within its path to the root.
252 |
253 | Thus we get a new root node (this represents the "new" Map produced by our
254 | operation), and a new path to the internal node that was actually changed.
255 |
256 | The nodes that we copy can continue referring to the other existing
257 | nodes so that those don't have to be copied. In practice this allows
258 | us to produce a "copy" of the entire trie by actually copying only
259 | a handful of nodes.
260 |
--------------------------------------------------------------------------------
/hash_tables/README.md:
--------------------------------------------------------------------------------
1 | ## Hash Tables (aka Hash Maps)
2 |
3 | A Hash Map is one of the most fundamental and commonly-used
4 | collection data structures. An implementation appears in most
5 | modern programming languages, and its versatility and performance
6 | characteristics make it something of a "swiss army knife" of
7 | data structures.
8 |
9 | So why is a Hash Map (this, by the way, is where Ruby gets the name for its `Hash` class)
10 | so powerful? As we will see, a Hash Map has 2 essential properties:
11 |
12 | 1. Ability to associate between arbitrary keys and arbitrary values
13 | 2. Ability to insert and retrieve values in constant time
14 |
15 | ### Associativity
16 |
17 | So what do we mean by "associate"? We say a data structure
18 | is associative when it allows us to define a relationship
19 | between 2 values and retrieve one in response to the other.
20 |
21 | We've actually already worked frequently with one fundamental
22 | associative data structure: the __Array__.
23 |
24 | Arrays define associative relationships between numeric indices and values contained in
25 | the array -- if we want to look something up in an array,
26 | we need to either know its numeric index so that we can go
27 | directly to that position in the array, __or__ we have to
28 | iterate through every element in the array and look at
29 | each one to see if it's the element we want.
30 |
31 | This is great if our data is ordered and if we are able to
32 | consistently retrieve it by going directly to its numeric
33 | index, but that isn't always the case.
34 |
35 | I often want to associate between _arbitrary_ keys
36 | and values (strings, objects, other arrays, etc)? For example, I want
37 | to associate the string "pizza" with the value "awesome",
38 | and I don't want to have to define an explicit ordering
39 | in the process. Additionally, I want to be able to add a whole lot of keys and
40 | values into the map and maintain a speedy lookup time.
41 |
42 | This is where a Hash Table comes in.
43 |
44 | ### Hash Table Structure
45 |
46 | To implement this data structure, we'll rely on a few key
47 | tools:
48 |
49 | 1. A Hashing Algorithm for uniquely differentiating pieces of data.
50 | Many languages already provide this -- in this example we'll look at
51 | using the SHA-1 implementation included with Ruby's Digest library.
52 | 2. An internal array which we'll ultimately use to store data
53 | 3. An additional abstraction for handling "collisions" between
54 | hashcodes within the data structure.
55 |
56 | To some extent, a Hash Table is a bit of Data Structure "sleight of hand"
57 | -- it allows us to translate arbitrary data (i.e. hash keys) into
58 | numeric array indices, and thus take advantage of the speedy
59 | index lookups we get out of the box with an array.
60 |
61 | ### Hash Function Basics
62 |
63 | This ability to translate arbitrary data to numeric array
64 | indices is the fundamental operation of a hash table, and
65 | the Hashing function is what makes it possible.
66 |
67 | Hash functions are a special type of algorithm designed
68 | to turn arbitrarily long data into consistent-length
69 | hash "digests" that represent that data.
70 |
71 | Importantly, a good hash function will do several things:
72 |
73 | 1. Be fast (this is important to help us maintain our hash table performance)
74 | 2. Be 1-way (given the input you can generate the digest, but with the digest
75 | there is no way to guess the input)
76 | 3. Be collision-resistant (it should be highly unlikely to find 2 inputs that
77 | generate the same digest value)
78 | 4. Be consistent -- hashing the same value should always yield the same digest
79 |
80 | Let's look at a ruby example using SHA-1:
81 |
82 | ```ruby
83 | [13] pry(main)> require "digest"
84 | => true
85 | [14] pry(main)> Digest::SHA1.hexdigest("pizza")
86 | => "1f6ccd2be75f1cc94a22a773eea8f8aeb5c68217"
87 | ```
88 |
89 | Here I used SHA1 to hash the string "pizza" into a 40-character hexadecimal
90 | digest number. One thing to note is that a SHA1 hash will always be 40 hexadecimal
91 | digits (160 bits) -- this is true whether I hash the string "pizza" or the
92 | entire contents of _War and Peace_.
93 |
94 | Additionally keep in mind that the digest produced is actually a _number_. Ruby
95 | happens to represent it for us in this example as a string of hexadecimal
96 | characters, but we can convert it to its actual numeric value like so:
97 |
98 | ```
99 | [14] pry(main)> Digest::SHA1.hexdigest("pizza")
100 | => "1f6ccd2be75f1cc94a22a773eea8f8aeb5c68217"
101 | [15] pry(main)> Digest::SHA1.hexdigest("pizza").to_i(16)
102 | => 975987071262755080377722350727279193143145743181
103 | ```
104 |
105 | We'll exploit this property of the hash digests in the next step.
106 |
107 | ### Hash Table Algorithm
108 |
109 | So how does it work? In short, when creating a new Hash Table, we'll
110 | allocate an internal array to actually store our data. Later on
111 | we may introduce additional abstractions around Nodes, Elements, or Chains,
112 | but an array will be the fundamental storage and access mechanism.
113 |
114 | When asked to insert a Key/Value pair into the array, we need to
115 | map it to a numeric index within our internal array. Here's where
116 | we will leverage the hash function -- it produces a numeric
117 | representation of the data in question (the digest). Our hash
118 | table will use this numeric digest, modulo the length of our
119 | array, to determine which spot the element should be inserted into.
120 |
121 | Let's look at a rough example in ruby:
122 |
123 | ```ruby
124 | require "digest"
125 |
126 | table = Array.new(10) # 10-element hash table to start
127 | key = "pizza"
128 | value = "awesome"
129 |
130 | digest = Digest::SHA1.hexdigest(key).to_i(16) # 179405067335283640084579532467505022408577155607
131 | position = digest % table.length # 7
132 |
133 | table[position] = value
134 | ```
135 |
136 | The hashing function produces a numeric digest of our data,
137 | and we use the array indices to map this to a numeric
138 | position in the element list.
139 |
140 | When we want to retrieve an element, we will follow the same
141 | process, but simply read from that array index rather
142 | than writing to it.
143 |
144 | Congrats! You made a naive but somwewhat functional hash table.
145 |
146 | ### Handling Collisions
147 |
148 | The example above gives us a good overview of the basic
149 | concept of a hash table, but it leaves out an important
150 | ingredient: resolving hash index collisions.
151 |
152 | Most Hashing Functions are designed to be *collision resistant* --
153 | that is, it should be relatively impossible to find 2 inputs that
154 | hash to the same output.
155 |
156 | However consider what would happen if we wanted to insert
157 | the key "aardwolf" pointing at the value "strange critter".
158 |
159 | "aardwolf" hashes to 582992241920298993175351113381634332712414316697,
160 | which comes out to 7, modulo 10 -- the same as the "pizza" key we previously
161 | inserted. With our current implementation, we don't have a way to distinguish
162 | these keys.
163 |
164 | The problem is that we aren't actually utilizing
165 | the entire space of possible hash values (1461501637330902918203684832716283019655932542975
166 | possibilities in the case of SHA1). Rather, the number of slots we have available is limited by the size
167 | of the internal array we are using for data storage.
168 |
169 | So the enormous
170 | count of possibile values produced by our hash function gets reduced
171 | down to a fairly small amount once we start mod-ing it by the length
172 | of our table.
173 |
174 | This illustrates 2 interesting points about a Hash Table:
175 |
176 | 1. Determining the initial size of the table is a trade-off
177 | between efficient use of space and likelihood of collisions.
178 | Using a very large table will likely end up in lots of unused spaces,
179 | but we'll have a lower chance that 2 inputs hash to the same position.
180 | 2. Even with a large hash table collisions are still inevitable, so
181 | a viable implementation needs to be able to handle these cases.
182 |
183 | ### Chaining
184 |
185 | There are many ways to handle the collision problem, but they
186 | generally fall into 2 camps:
187 |
188 | 1. Use a secondary data structure to allow each hash "bucket"
189 | to contain multiple pairs of keys and values. Then when we retrieve
190 | the bucket index for a given key, we can filter through the secondary
191 | structure to find the specific K/V we're looking for.
192 | 2. Dynamically resize the table as it fills to avoid collisions by
193 | creating additional space
194 |
195 | In reality, many production implementations use some combination
196 | of these approaches. For now we're going to discuss the first
197 | approach, which is sometimes referred to as "Chaining" the hash
198 | table.
199 |
200 | The idea is relatively straightforward: Instead of simply dumping
201 | values into the table indicies indicated by a key's hash value,
202 | we will use each bucket to store a Linked List of table "nodes",
203 | each containing a key, a value, and potential link to the next
204 | node in the chain.
205 |
206 | Thus when we insert a K/V pair, we have 2 possible cases:
207 |
208 | 1. This is the first pair to be inserted into that bucket,
209 | so it becomes the "head" of the chain in that bucket.
210 | 2. There is already a chain in that bucket, so we need to
211 | append this new pair to the tail of the existing chain.
212 |
213 | Similarly, when retrieving values, we have 3 cases:
214 |
215 | 1. There is no value in the appropriate bucket (so our
216 | key is not their)
217 | 2. There is a value in the appropriate bucket, and its
218 | head node contains the key we are looking for. Thus we
219 | can read the value from that node.
220 | 3. There is a value in the appropriate bucket, but the head
221 | node does not contain the key we are looking for. Thus we need
222 | to keep looking through nodes in this chain until we find
223 | the key we're looking for. Reaching the tail without finding it means our
224 | key is not there.
225 |
226 | #### Chaining Drawbacks
227 |
228 | Let's briefly discuss the pros and cons of this approach.
229 |
230 | Pros:
231 |
232 | * Flexible
233 | * Can still start our table with relatively small number
234 | of buckets
235 |
236 | Cons:
237 |
238 | * Additional complexity in insertion / lookup process
239 | * Performance degrades as chain lengths grow
240 |
241 | The key with the chaining approach is to make sure none of your
242 | buckets get too big. We could in theory have a chained hash
243 | table with 1 bucket, but obviously it would just become a
244 | linked list with linear lookup time.
245 |
246 | However if we can have a balance of a fairly large table
247 | size with short chains of a handful of links each, our overall
248 | lookup time will remain constant. This is why, as we mentioned,
249 | more sophisticated implementations will generally use some combination
250 | of chaining and dynamic resizing.
251 |
252 | Another possible optimization includes using a more sophisticated
253 | data structure such as a BST or Red-Black Tree for chaining within the buckets.
254 | This allows the lookup time within each chain to be even faster.
255 |
256 | This approach has lots of interesting applications, and starts
257 | to blur the line between a traditional Hash Table and another
258 | related data structure, the [Hash-Array Mapped Trie](https://github.com/turingschool/data_structures_and_algorithms/blob/master/hash_array_mapped_tries/README.markdown).
259 |
--------------------------------------------------------------------------------
/heaps/README.md:
--------------------------------------------------------------------------------
1 | ## Heap
2 |
3 | A heap falls with in the family of tree-based data structures.
4 |
5 | A heap can be useful for efficient sorting (heapsort), priority queues (like a stack) and locating a minimum or maximum in constant time
6 |
7 | More on Wikipedia:
8 |
9 | https://en.wikipedia.org/wiki/Heap_(data_structure)
10 |
11 | https://en.wikipedia.org/wiki/Binary_heap
12 |
13 | ### Overview
14 |
15 | A binary heap is a binary tree with two constraints:
16 |
17 | **Shape property**
18 |
19 | * A heap is a complete binary tree
20 | * A complete binary tree is defined as having all levels of the tree fully filled except possibly the last one
21 | * If the last level of the complete binary tree is not filled. The nodes are filled from left to right
22 |
23 | **Heap property**
24 |
25 | * All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap
26 | * Common comparison predicates include max-heaps and min-heaps
27 | * Max-heaps use the comparison predicate ">=" and min-heaps use "<=" when constructing the heap
28 |
29 | **Max-heap**
30 |
31 | ```ruby
32 | top of heap - > 100
33 | / \
34 | 20 40
35 | / \ / \
36 | 10 15 32 8
37 | ```
38 |
39 | **Min-heap**
40 |
41 | ```ruby
42 | top of heap - > 10
43 | / \
44 | 20 40
45 | / \ / \
46 | 30 25 45 80
47 | ```
48 |
49 | Due to the unordered nature of heaps rebalancing will occur when inserting or deleting nodes.
50 |
51 | For example if 1000 was inserted into the previous max-heap:
52 |
53 | ```ruby
54 | top of heap - > 100
55 | / \
56 | 20 40
57 | / \ / \
58 | 10 15 32 8
59 |
60 |
61 | 100
62 | / \
63 | 20 40
64 | / \ / \
65 | 10 15 32 8
66 | /
67 | 1000
68 |
69 | 100
70 | / \
71 | 20 40
72 | / \ / \
73 | 1000 15 32 8
74 | /
75 | 10
76 | 100
77 | / \
78 | 1000 40
79 | / \ / \
80 | 20 15 32 8
81 | /
82 | 10
83 |
84 | 1000
85 | / \
86 | 100 40
87 | / \ / \
88 | 20 15 32 8
89 | /
90 | 10
91 | ```
92 | **Heap sort**
93 |
94 | Heap sort is an efficient algorithm to sort an array. It is typically implemented on a max-heap by removing the node at the top of the heap and rebalancing.
95 |
96 | ### Implementation Tips
97 |
98 | * Binary heaps are typically implemented with an array
99 | * Ex: [1000, 100, 40, 20, 15, 32, 8, 10]
100 | * They are adjusted by shifting the contents of the array around
101 | * The heap property does not lend itself to creation by insertion (like a binary search tree)
102 | * Creation by insertion is suboptimal versus rearranging an already 'complete' binary tree
103 | * A well implemented heap should sort as it implements the heap and shape property
104 |
--------------------------------------------------------------------------------
/huffman_coding/javascript/compression.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////
2 | //// ♪┏(°.°)┛ LEAF ┗(°.°)┓♪ ////
3 | ///////////////////////////////////////
4 | function Leaf(character, count) {
5 | this.character = character;
6 | this.count = count;
7 | }
8 |
9 | Leaf.prototype.encoderObject = function(parentBits) {
10 | return {[this.character]: parentBits}
11 | };
12 |
13 | Leaf.prototype.unsetParents = function() {
14 | return this;
15 | };
16 |
17 | /////////////////////////////
18 | //// (>’.’)> NODE <(‘.'<) ///
19 | /////////////////////////////
20 | function Node(left, right) {
21 | this.left = left;
22 | this.right = right;
23 |
24 | Object.defineProperties(this, {
25 | count: {"get": function() { return this.left.count + this.right.count; }}
26 | });
27 | }
28 |
29 | Node.prototype.encoderObject = function(parentBits = "") {
30 | var leftEncoderObject = this.left.encoderObject(parentBits + "0");
31 | var rightEncoderObject = this.right.encoderObject(parentBits + "1");
32 | return _.extend(leftEncoderObject, rightEncoderObject);
33 | };
34 |
35 | Node.prototype.unsetParents = function() {
36 | delete this.left.unsetParents().parent;
37 | delete this.right.unsetParents().parent;
38 | return this;
39 | };
40 |
41 | ///////////////////////////////////
42 | //// (⌐■_■) ENCODER (⌐■_■) ////
43 | //////////////////////////////////
44 | function Encoder(message) {
45 |
46 | buildTree(this, message);
47 |
48 | var encoder = this;
49 | this.compressedBitstring = message.split('').reduce(function(bitstring, character){
50 | return bitstring + encoder.characterToCode(character);
51 | }, "");
52 |
53 | function buildTree(encoder, message) {
54 | var characterCounts = _.countBy(message.split(''));
55 |
56 | var nodeQueue = _.map(characterCounts, function(count, character) {
57 | return new Leaf(character, count);
58 | });
59 |
60 | encoder.leaves = nodeQueue.slice(0);
61 |
62 | while(nodeQueue.length > 1) {
63 | nodeQueue = _.sortBy(nodeQueue, 'count');
64 | newNode = new Node(nodeQueue.shift(), nodeQueue.shift());
65 | newNode.left.parent = newNode.right.parent = newNode;
66 | nodeQueue.push(newNode);
67 | }
68 |
69 | encoder.root = nodeQueue[0];
70 | }
71 |
72 | }
73 |
74 | Encoder.prototype.characterToCode = function(character) {
75 | return this.root.encoderObject()[character];
76 | };
77 |
78 | Encoder.prototype.decode = function(compressedBitstring) {
79 |
80 | // TODO: All the awesome
81 |
82 | };
83 |
84 | ///////////////////////////////////
85 | //// ><((((‘> DECODER <`))))>< ////
86 | ///////////////////////////////////
87 | function Decoder(compressedBitstring, rootNode) {
88 | this.bitstring = compressedBitstring;
89 | this.root = rootNode;
90 | }
91 |
92 | Decoder.prototype.message = function(){
93 | // TODO: It
94 | // YOU CAN DO IT!!
95 | };
96 |
--------------------------------------------------------------------------------
/huffman_coding/javascript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Win One for the Zipper Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/huffman_coding/javascript/test.js:
--------------------------------------------------------------------------------
1 | var message = "That's no moon, it's a space station!";
2 |
3 | var encoder = new Encoder(message);
4 |
5 | describe('compression', function() {
6 |
7 | context('leaf', function() {
8 | it('has a character and a count', function() {
9 | var leaf = new Leaf("J", 4);
10 | assert.ok(leaf.character, 'has a character');
11 | assert.ok(leaf.count, 'has a count');
12 | });
13 |
14 | it('returns itself as an object', function() {
15 | var leaf = new Leaf("J", 4);
16 | assert.deepEqual(leaf.encoderObject("010"), {J: "010"}, 'has correct object returned');
17 | });
18 |
19 | });
20 |
21 | context('node', function() {
22 |
23 | it('has a left node and a right node', function() {
24 | var node = new Node(new Leaf(), new Leaf());
25 | assert.ok(node.left, 'has a left node');
26 | assert.ok(node.right, 'has a right node');
27 | });
28 |
29 | it('has a count equal to the sum of the counts of its leaves', function() {
30 | var node = new Node(new Leaf("!", 1), new Leaf("@", 2));
31 | assert.equal(node.count, 3);
32 | });
33 |
34 | it('returns itself as an object', function() {
35 | var leftLeaf = new Leaf("J", 1);
36 | var rightLeaf = new Leaf("K", 1);
37 | var node = new Node(leftLeaf, rightLeaf);
38 | assert.deepEqual(node.encoderObject("0"), {J: "00", K: "01"}, 'has correct object returned');
39 | });
40 |
41 | });
42 |
43 | context('rootNode', function() {
44 | it('has a count equal to the message length', function() {
45 | assert.equal(encoder.root.count, message.length);
46 | });
47 |
48 | it('has children that know about their parents', function() {
49 | assert.equal(encoder.root, encoder.root.left.parent);
50 | assert.equal(encoder.root, encoder.root.right.parent);
51 | });
52 |
53 | it('can unset parents', function() {
54 | var tempEncoder = new Encoder('Cowabunga');
55 | tempEncoder.root.unsetParents();
56 | assert.isUndefined(tempEncoder.root.left.parent);
57 | assert.isUndefined(tempEncoder.root.right.parent);
58 | });
59 |
60 | });
61 |
62 | context('encoding', function() {
63 | it('has an array of leaves', function() {
64 | var numCharacters = _.uniq(message.split("")).length;
65 | assert.equal(numCharacters, encoder.leaves.length);
66 | encoder.leaves.forEach(function(leaf) {
67 | assert.instanceOf(leaf, Leaf);
68 | });
69 |
70 | });
71 |
72 | it('can convert characters to binary codes', function() {
73 | assert.match(encoder.characterToCode("T"), /^[01]+$/);
74 | });
75 |
76 | it('has shorter codes for characters with more frequency', function() {
77 | var codeLengths = ["t", "!", "n", " "].map(function(character) {
78 | return encoder.characterToCode(character);
79 | });
80 | assert.deepEqual(codeLengths, codeLengths.sort());
81 | });
82 |
83 | it('can tell me the compressed bitstring', function() {
84 | var compressed = "100001000111110000110001110111001011010010010010111010011110011100001100011101111110001101001111101011011011000100011110000111010111010111";
85 | assert.equal(encoder.compressedBitstring, compressed);
86 | });
87 |
88 | });
89 |
90 | context("decoding", function() {
91 | context("challenge 1", function() {
92 | it.skip('can decode a compressed message', function() {
93 | var decodedMessage = encoder.decode(encoder.compressedBitstring);
94 | assert.equal(decodedMessage, message);
95 | });
96 | });
97 |
98 | context("challenge 2", function() {
99 | it.skip('can decode from only a compressed bitstring and a tree', function() {
100 | var decoder = new Decoder(encoder.compressedBitstring, encoder.root);
101 | assert.equal(decoder.message(), message);
102 | });
103 | });
104 |
105 | context("batman challenge", function() {
106 | it('can decode from only a compressed bitstring and a tree where the nodes have lost their parents', function() {
107 | encoder.root.unsetParents();
108 | var decoder = new Decoder(encoder.compressedBitstring, encoder.root);
109 | assert.equal(decoder.message(), message);
110 | });
111 | });
112 |
113 | });
114 | });
115 |
--------------------------------------------------------------------------------
/huffman_coding/readme.md:
--------------------------------------------------------------------------------
1 | Computers use one byte to store each character in a file. A byte is made up of 8 bits. There are 2^8 = 256 possible states of one byte. There are only 26 letters in the alphabet! Even when you include capital letters, numbers and special characters, you can only type 95 characters on a standard keyboard. We're wasting the rest of the space in those bytes. Maybe we should only use 7 bytes per character.
2 |
3 | The most common character in english is the letter 'E'. It appears over 100x more often than a 'Z'. And spaces occur twice as often as 'E's. Should all of these characters take up the same number of bits? Why are we wasting all this space!?
4 |
5 | # Huffman Coding
6 |
7 | Huffman coding is one of the oldest compression algorithms, and forms of it are still used in MP3 and JPEG files today. It uses frequency of different characters in a text file to recode the bits used for each character.
8 |
9 | ## The Tree
10 |
11 | 
12 |
13 | ### Encoding
14 |
15 | A Huffman coding tree determines how you will code each character. To determine the code for a character, work your way from the top (root) to the "leaf" that contains your character. Each time you go left, add a `0`. Each time you go right, add a `1`. Once you get to the leaf, you have your code.
16 |
17 | In the above image, each `c` in your text gets replaced by `1011`, and each `a` is simply `0`. In ASCII, the 'bitstring' for `'abcd'` would be `01100001011000100110001101100100`. 4 characters = 4 bytes = 32 bits. After we encode it with our Huffman tree, our bitstring is `01111011100`. 11 bits = 1 3/8ths bytes. Only 34% of the original length.
18 |
19 | ### Building the tree
20 |
21 | All the code to build the tree from a given message is done for you and tested. If you're curious how it works, the basics are in this [6 minute youtube video](https://www.youtube.com/watch?v=ZdooBTdW5bM).
22 |
23 | ### Decoding
24 |
25 | So how do we get from `01111011100` to `'abcd'`?
26 |
27 | It's your job to write a decoder function, or rather functions.
28 |
29 | First, decode as part of the `Encoder` class itself. You'll have access to a list of `leaves`, the `encoderObject` function, and other things that may be helpful.
30 |
31 | Then create a `Decoder` class. It will be initialized by a compressed bitstring, and a huffman coding tree in the form of the root node. You no longer have access to the `encoderObject` or the `leaves` array. Try to solve this one without recreating those things.
32 |
33 | The last challenge is the Batman challenge. You're still working with the Decoder class, but now the nodes of your tree have lost their parents. Each node only has a `left` and a `right`
34 |
--------------------------------------------------------------------------------
/linked_lists/README.markdown:
--------------------------------------------------------------------------------
1 | ## Linked Lists
2 |
3 | Linked Lists are one of the most fundamental Computer Science data structures.
4 |
5 | ### Singly-Linked List
6 |
7 | In a singly-linked list you have a *head*, the start of the list, and *nodes* which hold the data. Each *node* holds a single element of data and a link to the *next* node in the list.
8 |
9 | Using sweet ASCII art, it might look like this:
10 |
11 | ```
12 | HEAD ---> ["hello" | -]--> ["world" | -]--> ["!" | ]
13 | ```
14 |
15 | The three nodes here hold the data `"hello"`, `"world"`, and `"!"`. The first two node have links which point to other nodes. The last node, holding the data `"!"`, has no reference in the link spot. This signifies that it is the end of the list.
16 |
17 | #### Functionality
18 |
19 | A fully functional singly linked list can:
20 |
21 | * Insert elements
22 | * Pop an element from the end
23 | * Push an element onto the beginning
24 | * Remove the (first occurance | all occurances) of an element by data content
25 | * Remove an element by position
26 | * Add an element at an arbitrary position
27 | * Add an element after a known node
28 | * Find whether a data element is or is not in the list
29 | * Find the distance between two nodes
30 |
31 | #### Implementation
32 |
33 | Implement a singly-linked list using:
34 |
35 | * A) Iteration/looping
36 | * B) Recursion
37 |
38 | ### Doubly-Linked List
39 |
40 | In a doubly-linked list, each node has a link to both the previous and next nodes in the list.
41 |
42 | #### Functionality
43 |
44 | A doubly-linked list implements all the functionality of a singly-linked list and also:
45 |
46 | * Insert a node immediately before a known node
47 | * Find the shortest distance between two nodes
48 |
49 | ### Ring List
50 |
51 | In a circular or ring list, the "last" node links back to the first. How does this structure affect searching?
--------------------------------------------------------------------------------
/linked_lists/javascript/ListNode.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turingschool/data_structures_and_algorithms/f9e9b47900e84e55d93be51600e51bb9297868aa/linked_lists/javascript/ListNode.js
--------------------------------------------------------------------------------
/linked_lists/javascript/ListNode_test.js:
--------------------------------------------------------------------------------
1 | describe('ListNode', function() {
2 | it('should have a data property', function(){
3 | var node = new ListNode();
4 | expect(node).to.have.property('data');
5 | });
6 |
7 | // it('should have data', function() {
8 | // var node = new ListNode('info');
9 | // expect(node.data).to.eq('info');
10 | // var pizzaNode = new ListNode('pizza');
11 | // expect(pizzaNode.data).to.eq('pizza');
12 | // });
13 |
14 | // it('should have a default empty nextNode', function() {
15 | // var node = new ListNode('pizza');
16 | // expect(node.nextNode).to.eq(null);
17 | // });
18 |
19 | // it('should allow setting a nextNode', function() {
20 | // var n1 = new ListNode('pizza');
21 | // var n2 = new ListNode('cats');
22 | // n1.nextNode = n2;
23 | // expect(n1.nextNode.data).to.eq('cats');
24 | // expect(n1.nextNode instanceof ListNode).to.be.true;
25 | // });
26 |
27 | // it('should allow a next node argument on creation', function(){
28 | // var node = new ListNode('pizza', new ListNode('cats'));
29 | // expect(node.nextNode.data).to.eq('cats');
30 | // expect(node.nextNode instanceof ListNode).to.be.true;
31 | // });
32 | });
33 |
--------------------------------------------------------------------------------
/linked_lists/javascript/README.md:
--------------------------------------------------------------------------------
1 | # Linked List Problem
2 |
3 | Open the `test.html` page to see your tests run in the brower.
4 |
5 | There are two sets of tests to get passing!
6 |
7 | Start with the tests in `ListNode_test.js`
8 |
9 | Once those are passing, more on to the tests in `LinkedList_test.js`
--------------------------------------------------------------------------------
/linked_lists/javascript/linkedList.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turingschool/data_structures_and_algorithms/f9e9b47900e84e55d93be51600e51bb9297868aa/linked_lists/javascript/linkedList.js
--------------------------------------------------------------------------------
/linked_lists/javascript/linkedList_test.js:
--------------------------------------------------------------------------------
1 | describe('LinkedList', function() {
2 | var list;
3 |
4 | beforeEach(function(){
5 | list = new List();
6 | });
7 |
8 | it.skip('should start with zero elements', function() {
9 | expect(list._length).to.eq(0);
10 | });
11 |
12 | it.skip('should set its default head to null', function(){
13 | expect(list.head).to.eq(null);
14 | });
15 |
16 | describe('.push', function(){
17 | context('with a single element', function(){
18 | it.skip('should allow push of a single element to a list', function(){
19 | list.push('pizza');
20 | expect(list.head.data).to.eq('pizza');
21 | });
22 |
23 | it.skip('should increment the _length of the list', function(){
24 | list.push('pizza');
25 | expect(list._length).to.eq(1);
26 | });
27 | });
28 |
29 | context('with multiple elements', function(){
30 | it.skip('should increment the length count', function(){
31 | list.push('pizza');
32 | list.push('stromboli');
33 | list.push('mushroom');
34 | expect(list._length).to.eq(3);
35 | });
36 |
37 | it.skip('should assign the head to the first element pushed', function(){
38 | expect(list.head).to.eq(null);
39 | list.push('pizza');
40 | expect(list.head.data).to.eq('pizza');
41 | list.push('stromboli');
42 | expect(list.head.data).to.eq('pizza');
43 | });
44 |
45 | it.skip('should attach the second element to the first element', function(){
46 | list.push('pizza');
47 | list.push('stromboli');
48 | expect(list.head.nextNode.data).to.eq('stromboli');
49 | });
50 |
51 | it.skip('should attach nextNodes in sequential order', function(){
52 | list.push('pizza');
53 | list.push('stromboli');
54 | list.push('mushroom');
55 | list.push('peanutbutter');
56 | expect(list.head.data).to.eq('pizza');
57 | expect(list.head.nextNode.data).to.eq('stromboli');
58 | expect(list.head.nextNode.nextNode.data).to.eq('mushroom');
59 | expect(list.head.nextNode.nextNode.nextNode.data).to.eq('peanutbutter');
60 | });
61 | });
62 | });
63 |
64 | describe('.pop', function(){
65 | context('with no elements', function(){
66 | it.skip('should return null', function(){
67 | expect(list.pop()).to.eq(null);
68 | });
69 |
70 | it.skip('should not decrement the _length', function(){
71 | expect(list._length).to.eq(0);
72 | });
73 | });
74 |
75 | context('with one element', function(){
76 | it.skip('should change the _length', function(){
77 | list.push('hello');
78 | var result = list.pop();
79 | expect(list._length).to.eq(0);
80 | });
81 |
82 | it.skip('should set the list head to null', function(){
83 | list.push('hello');
84 | var result = list.pop();
85 | expect(list.head).to.eq(null);
86 | });
87 |
88 | it.skip('should return the last element', function(){
89 | list.push('hello');
90 | var result = list.pop();
91 | expect(result.data).to.eq('hello');
92 | });
93 | });
94 |
95 | context('with multiple elements', function(){
96 | it.skip('should return the last element from the list', function(){
97 | list.push("hello");
98 | list.push("new");
99 | list.push("world");
100 | list.push("today");
101 |
102 | var output = list.pop();
103 | expect(output.data).to.eq('today');
104 | });
105 |
106 | it.skip('should remove the last element from the list', function(){
107 | list.push("hello");
108 | list.push("world");
109 | list.push("today");
110 |
111 | var output = list.pop();
112 | expect(output.data).to.eq('today');
113 | expect(list._length).to.eq(2);
114 |
115 | var output2 = list.pop();
116 | expect(output2.data).to.eq('world');
117 | expect(output2.nextNode).to.eq(null);
118 | expect(list._length).to.eq(1);
119 |
120 | var output3 = list.pop();
121 | expect(output3.data).to.eq('hello');
122 | expect(output3.nextNode).to.eq(null);
123 | expect(list._length).to.eq(0);
124 | });
125 | });
126 | });
127 |
128 | describe('.delete', function(){
129 | context('with one node', function(){
130 | it.skip('deletes a solo node', function(){
131 | list.push('hello');
132 | list.delete('hello');
133 | expect(list._length).to.eq(0);
134 | expect(list.head).to.eq(null);
135 | });
136 |
137 | it.skip('does not perform a delete when a node does not match', function(){
138 | list.push('hello');
139 | list.delete('goodbye');
140 | expect(list._length).to.eq(1);
141 | expect(list.head.data).to.eq('hello');
142 | });
143 | });
144 |
145 | context('with multiple nodes', function(){
146 | beforeEach(function(){
147 | list.push('hello');
148 | list.push('darkness');
149 | list.push('my');
150 | list.push('old');
151 | list.push('friend');
152 | });
153 |
154 | it.skip('changes the list _.length', function(){
155 | expect(list.head.nextNode.data).to.eq('darkness');
156 | expect(list._length).to.eq(5);
157 | list.delete('friend');
158 | expect(list._length).to.eq(4);
159 | list.delete('my');
160 | expect(list._length).to.eq(3);
161 | list.delete('happy');
162 | expect(list._length).to.eq(3);
163 | });
164 |
165 | it.skip('resets the nextNode property on the node before the deleted node', function(){
166 | expect(list.head.nextNode.data).to.eq('darkness');
167 | list.delete('darkness');
168 | expect(list.head.nextNode.data).to.eq('my');
169 | });
170 |
171 | it.skip('resets the list.head if deleting the first node', function(){
172 | expect(list.head.data).to.eq('hello');
173 | list.delete('hello');
174 | expect(list.head.data).to.eq('darkness');
175 | });
176 | });
177 | });
178 |
179 | describe('.toArray', function(){
180 | context('when there are no elements', function(){
181 | it.skip('converts to an array', function(){
182 | expect(list.toArray()).to.deep.equal([]);
183 | });
184 | });
185 |
186 | context('when there are several elements', function(){
187 | beforeEach(function(){
188 | list.push('The');
189 | list.push('rain');
190 | list.push('in');
191 | list.push('Spain');
192 | });
193 |
194 | it.skip('can convert to an array', function(){
195 | expect(list.toArray()).to.deep.equal(['The', 'rain', 'in', 'Spain']);
196 | });
197 | });
198 | });
199 |
200 | describe('.lastNode', function(){
201 | context('with several nodes', function(){
202 | beforeEach(function(){
203 | list.push('The');
204 | list.push('rain');
205 | list.push('in');
206 | list.push('Spain');
207 | });
208 |
209 | it.skip('finds the last node', function(){
210 | expect(list.lastNode().data).to.eq('Spain');
211 | });
212 | });
213 |
214 | context('with one node', function(){
215 | beforeEach(function(){
216 | list.push('Ahoy!');
217 | });
218 |
219 | it.skip('finds the only node', function(){
220 | expect(list.lastNode().data).to.eq('Ahoy!');
221 | });
222 | });
223 |
224 | context('with no nodes', function(){
225 | it.skip('returns null', function(){
226 | expect(list.lastNode()).to.eq(null);
227 | });
228 | });
229 | });
230 |
231 | describe('.include', function(){
232 | beforeEach(function(){
233 | list.push('The');
234 | list.push('rain');
235 | list.push('in');
236 | list.push('Spain');
237 | });
238 |
239 | it.skip('should return true if node is in list', function(){
240 | expect(list.include("rain")).to.eq(true);
241 | });
242 |
243 | it.skip('should return false if node is not in list', function(){
244 | expect(list.include("nope")).to.eq(false);
245 | });
246 | });
247 |
248 | describe('.find', function(){
249 | beforeEach(function(){
250 | list.push('oh');
251 | list.push('hello');
252 | list.push('world');
253 | });
254 |
255 | it.skip('should return true the node if node in list', function(){
256 | var result = list.find("hello");
257 | expect(result.data).to.eq('hello');
258 | expect(result.nextNode.data).to.eq('world');
259 | });
260 |
261 | it.skip('should return null if node is missing', function(){
262 | var result = list.find("nope");
263 | expect(result).to.eq(null);
264 | });
265 | });
266 |
267 | describe('.index', function(){
268 | beforeEach(function(){
269 | list.push('oh');
270 | list.push('hello');
271 | list.push('world');
272 | });
273 |
274 | it.skip('should return expected indexes', function(){
275 | expect(list.index('oh')).to.eq(0);
276 | expect(list.index('world')).to.eq(2);
277 | expect(list.index('nope')).to.eq(null);
278 | });
279 | });
280 |
281 | describe('.insert', function(){
282 | beforeEach(function(){
283 | list.push('dark');
284 | list.push('stormy');
285 | });
286 |
287 | it.skip('should insert nodes', function(){
288 | expect(list._length).to.eq(2);
289 | list.insert(1, 'and');
290 | list.insert(3, 'night');
291 | expect(list._length).to.eq(4);
292 | expect(list.toArray()).to.deep.equal(['dark', 'and', 'stormy', 'night']);
293 | });
294 | });
295 |
296 | describe('.insertAfter', function(){
297 | beforeEach(function(){
298 | list.push('dark');
299 | list.push('stormy');
300 | });
301 |
302 | it.skip('should insert nodes after other nodes', function(){
303 | expect(list._length).to.eq(2);
304 | list.insertAgfter('dark', 'and');
305 | list.insertAfter('stormy', 'night');
306 | expect(list._length).to.eq(4);
307 | expect(list.toArray()).to.deep.equal(['dark', 'and', 'stormy', 'night']);
308 | });
309 | });
310 |
311 | describe('.distance', function(){
312 | beforeEach(function(){
313 | list.push("hello")
314 | list.push("pizza")
315 | list.push("world")
316 | list.push("today")
317 | list.push("tomorrow")
318 | });
319 |
320 | it.skip('should calculate distance between nodes', function(){
321 | expect(list.distance("hello", "today")).to.eq(3);
322 | expect(list.distance("pizza", "today")).to.eq(2);
323 | expect(list.distance("hello", "world")).to.eq(2);
324 | expect(list.distance("hello", "tomorrow")).to.eq(4);
325 | expect(list.distance("world", "today")).to.eq(1);
326 | });
327 | });
328 | });
329 |
--------------------------------------------------------------------------------
/linked_lists/javascript/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Linked List Test Suite
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/linked_lists/ruby/linked_list_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require 'minitest/pride'
4 |
5 | class LinkedListTest < Minitest::Test
6 | attr_reader :list
7 |
8 | def setup
9 | @list = LinkedList.new
10 | end
11 |
12 | def test_nodes_have_data
13 | skip
14 | node = Node.new("pizza")
15 | assert_equal "pizza", node.data
16 | end
17 |
18 | def test_nodes_have_next_node
19 | skip
20 | n1 = Node.new("pizza")
21 | n2 = Node.new("cats")
22 | n1.next_node = n2
23 | assert_equal "cats", n1.next_node.data
24 | assert_equal Node, n1.next_node.class
25 | end
26 |
27 | def test_it_accepts_next_node_on_init
28 | skip
29 | n1 = Node.new("pizza", Node.new("cats"))
30 | assert_equal "cats", n1.next_node.data
31 | assert_equal Node, n1.next_node.class
32 | end
33 |
34 | def test_it_starts_with_zero_elements
35 | skip
36 | assert_equal 0, list.count
37 | end
38 |
39 | def test_a_new_list_starts_with_nil_head
40 | skip
41 | assert_equal nil, LinkedList.new.head
42 | end
43 |
44 | def test_it_pushes_a_single_element_onto_a_list
45 | skip
46 | list.push("pizza")
47 | assert_equal "pizza", list.head.data
48 | assert_equal 1, list.count
49 | end
50 |
51 | def test_it_pushes_two_elements
52 | skip
53 | list.push("pizza")
54 | assert_equal "pizza", list.head.data
55 | list.push("stromboli")
56 | assert_equal "stromboli", list.head.next_node.data
57 | end
58 |
59 | def test_it_pushes_three_elements_onto_a_list
60 | skip
61 | list.push("hello")
62 | assert_equal "hello", list.head.data
63 | list.push("world")
64 | assert_equal "world", list.head.next_node.data
65 | list.push("today")
66 | assert_equal "world", list.head.next_node.data
67 | assert_equal "today", list.head.next_node.next_node.data
68 | assert_equal 3, list.count
69 | end
70 |
71 | def test_it_adds_four_elements
72 | skip
73 | list.push("hello")
74 | list.push("world")
75 | list.push("today")
76 | list.push("pizza")
77 | assert_equal "today", list.head.next_node.next_node.data
78 | assert_equal "pizza", list.head.next_node.next_node.next_node.data
79 | assert_equal 4, list.count
80 | end
81 |
82 | def test_it_pops_the_last_element_from_the_list
83 | skip
84 | list.push("hello")
85 | list.push("world")
86 | list.push("today")
87 | output = list.pop
88 | assert_equal "today", output
89 | assert_equal 2, list.count
90 | end
91 |
92 | def test_a_popped_element_is_removed
93 | skip
94 | list.push("hello")
95 | output = list.pop
96 | assert_equal "hello", output
97 | assert_equal 0, list.count
98 | end
99 |
100 | def test_it_pops_nil_when_there_are_no_elements
101 | skip
102 | assert_nil list.pop
103 | end
104 |
105 | def test_it_deletes_a_solo_node
106 | skip
107 | list.push("hello")
108 | list.delete("hello")
109 | assert_equal 0, list.count
110 | end
111 |
112 | def test_it_does_not_delete_when_the_data_does_not_match
113 | skip
114 | list.push("hello")
115 | list.push("world")
116 | list.delete("today")
117 | assert_equal 2, list.count
118 | end
119 |
120 | def test_it_deletes_a_last_node
121 | skip
122 | list.push("hello")
123 | list.push("world")
124 | list.push("today")
125 | list.delete("today")
126 | assert_equal 2, list.count
127 | end
128 |
129 | def test_it_deletes_a_middle_node
130 | skip
131 | list.push("hello")
132 | list.push("world")
133 | list.push("today")
134 | list.delete("world")
135 | assert_equal 2, list.count
136 | assert_equal "today", list.pop
137 | assert_equal "hello", list.pop
138 | end
139 |
140 | def test_it_deletes_the_head_when_there_are_more_nodes
141 | skip
142 | list.push("hello")
143 | list.push("world")
144 | list.push("today")
145 | list.delete("hello")
146 | assert_equal 2, list.count
147 | assert_equal "today", list.pop
148 | assert_equal "world", list.pop
149 | end
150 |
151 | def test_it_converts_to_an_array_when_there_are_no_elements
152 | skip
153 | assert_equal [], list.to_a
154 | end
155 |
156 | def test_it_converts_to_an_array_with_several_elements
157 | skip
158 | list.push("hello")
159 | list.push("world")
160 | list.push("today")
161 | assert_equal ["hello", "world", "today"], list.to_a
162 | end
163 |
164 | def test_it_finds_the_last_node
165 | skip
166 | list.push("hello")
167 | list.push("world")
168 | node = list.last_node
169 | assert_equal "world", node.data
170 | end
171 |
172 | def test_a_node_links_to_its_next_element
173 | skip
174 | list.push("hello")
175 | list.push("world")
176 | assert_equal "world", list.last_node.data
177 | assert_equal "world", list.head_node.next_node.data
178 | end
179 |
180 | def test_next_node_for_the_last_node_is_nil
181 | skip
182 | list.push("world")
183 | assert_nil list.last_node.next_node
184 | end
185 |
186 | def test_find_if_an_element_is_included_in_the_list
187 | skip
188 | list.push("hello")
189 | list.push("world")
190 | assert_equal true, list.include?("hello")
191 | assert_equal false, list.include?("bogus")
192 | end
193 |
194 | def test_find_a_given_node
195 | skip
196 | list.push("hello")
197 | list.push("world")
198 | list.push("today")
199 |
200 | assert_equal "world", list.find("world").data
201 | assert_equal "today", list.find("world").next_node.data
202 | end
203 |
204 | def test_inserts_node_at_arbitrary_position
205 | skip
206 | list.push("hello")
207 | list.push("world")
208 | list.push("today")
209 |
210 | list.insert(1, "pizza")
211 |
212 | assert_equal 1, list.index("pizza")
213 | assert_equal ["hello", "pizza", "world", "today"], list.to_a
214 | end
215 |
216 | def test_inserted_node_is_next_node_for_previous_node
217 | skip
218 | list.push("hello")
219 | list.push("world")
220 | list.push("today")
221 |
222 | list.insert(1, "pizza")
223 |
224 | assert_equal "world", list.find("pizza").next_node.data
225 | assert_equal "pizza", list.find("hello").next_node.data
226 | end
227 |
228 | def test_insert_after_adds_a_node_after_a_given_node
229 | skip
230 | list.push("hello")
231 | list.push("world")
232 | list.push("today")
233 |
234 | list.insert_after("hello", "pizza")
235 |
236 | assert_equal "world", list.find("pizza").next_node.data
237 | assert_equal "pizza", list.find("hello").next_node.data
238 | end
239 |
240 | def test_distance_returns_distance_between_two_nodes
241 | skip
242 | list.push("hello")
243 | list.push("pizza")
244 | list.push("world")
245 | list.push("today")
246 | list.push("tomorrow")
247 | assert_equal 3, list.distance("hello", "today")
248 | assert_equal 2, list.distance("pizza", "today")
249 | assert_equal 2, list.distance("hello", "world")
250 | assert_equal 4, list.distance("hello", "tomorrow")
251 | assert_equal 1, list.distance("world", "today")
252 | end
253 | end
254 |
--------------------------------------------------------------------------------
/luhn_algorithm/README.markdown:
--------------------------------------------------------------------------------
1 | ## Luhn Algorithm
2 |
3 | The Luhn algorithm is a check-summing algorithm best known for checking the validity of credit card numbers.
4 |
5 | You can checkout the full description on Wikipedia: http://en.wikipedia.org/wiki/Luhn_algorithm
6 |
7 | ### Description
8 |
9 | (adapted from Wikipedia)
10 |
11 | The formula verifies a number against its included check digit, which is usually appended to a partial account number to generate the full account number. This full account number must pass the following test:
12 |
13 | * from the rightmost digit, which is the check digit, moving left, double the value of every second digit
14 | * if product of this doubling operation is greater than 9 (e.g., 7 * 2 = 14), then sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5).
15 | * take the sum of all the digits
16 | * if and only if the total modulo 10 is equal to 0 then the number is valid
17 |
18 | ### Example
19 |
20 | #### Calculating the Check Digit
21 |
22 | Take an account identifier `7992739871`. To make it an account number, we need to calculate and append a check digit. Calling the digit `x`, the full account number will look like `7992739871x`.
23 |
24 | We use the algorithm to calculate the correct checksum digit:
25 |
26 | * `Account identifier: 7 9 9 2 7 3 9 8 7 1 x`
27 | * `2x every other digit: 7 18 9 4 7 6 9 16 7 2 x`
28 | * `Summed digits over 10: 7 9 9 4 7 6 9 7 7 2 x`
29 | * `Results summed: 7 9 9 4 7 6 9 7 7 2` = 67
30 |
31 | With the result of `67`, we take the ones digit (`7`) and subtract it from `10`: `10 - 7 = 3`. Thus `3` is the check digit.
32 |
33 | The full account number with check digit is `79927398713`.
34 |
35 | #### Validating an Account Number
36 |
37 | We can use the same process to validate an account number. Using `79927398713` as our sample input:
38 |
39 | * `Account identifier: 7 9 9 2 7 3 9 8 7 1 3`
40 | * `2x every other digit: 7 18 9 4 7 6 9 16 7 2 3`
41 | * `Summed digits over 10: 7 9 9 4 7 6 9 7 7 2 3`
42 | * `Results summed: 7 9 9 4 7 6 9 7 7 2 3` = 70
43 |
44 | Since the summed results modulo 10 is zero, the account number is valid according to the algorithm.
45 |
46 |
47 |
--------------------------------------------------------------------------------
/luhn_algorithm/luhn_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require_relative 'luhn_validator'
4 |
5 | class LuhnTest < Minitest::Test
6 | # This test suite is not meant to be exhaustive,
7 | # just a start. Write your own tests!
8 |
9 | attr_reader :validator
10 |
11 | def setup
12 | @validator = LuhnValidator.new
13 | end
14 |
15 | def test_it_validates_the_example_account_number
16 | assert validator.validate('79927398713')
17 | end
18 |
19 | def test_it_finds_the_check_digit_for_an_identifier
20 | assert_equal '3', validator.check_digit_for('7992739871')
21 | end
22 | end
--------------------------------------------------------------------------------
/md5/README.markdown:
--------------------------------------------------------------------------------
1 | ## MD5 Hashing
2 |
3 | One-way hash functions like MD5 have many uses from security to data validity.
4 |
5 | MD5 is often used to hash passwords, though it is a poor choice for that application since the algorithm is designed to be fast. Therefore, if the hashed password is exposed, an attacker can iterate through many possible solutions quickly.
6 |
7 | Instead, MD5 is best suited to verifying the integrity of data. For instance, if you're transferring a large file between two machines, you could run MD5 on the source machine and on the receiving machine. If the two hashes match exactly, then you know the file transferred without corruption.
8 |
9 | ### The Algorithm
10 |
11 | Pseudocode:
12 |
13 | ```plain
14 | //Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
15 | var int[64] s, K
16 |
17 | //s specifies the per-round shift amounts
18 | s[ 0..15] := { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22}
19 | s[16..31] := { 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20}
20 | s[32..47] := { 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23}
21 | s[48..63] := { 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}
22 |
23 | //Use binary integer part of the sines of integers (Radians) as constants:
24 | for i from 0 to 63
25 | K[i] := floor(abs(sin(i + 1)) × (2 pow 32))
26 | end for
27 | //(Or just use the following table):
28 | K[ 0.. 3] := { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee }
29 | K[ 4.. 7] := { 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 }
30 | K[ 8..11] := { 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be }
31 | K[12..15] := { 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 }
32 | K[16..19] := { 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa }
33 | K[20..23] := { 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 }
34 | K[24..27] := { 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed }
35 | K[28..31] := { 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a }
36 | K[32..35] := { 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c }
37 | K[36..39] := { 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 }
38 | K[40..43] := { 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 }
39 | K[44..47] := { 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 }
40 | K[48..51] := { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 }
41 | K[52..55] := { 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 }
42 | K[56..59] := { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 }
43 | K[60..63] := { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }
44 |
45 | //Initialize variables:
46 | var int a0 := 0x67452301 //A
47 | var int b0 := 0xefcdab89 //B
48 | var int c0 := 0x98badcfe //C
49 | var int d0 := 0x10325476 //D
50 |
51 | //Pre-processing: adding a single 1 bit
52 | append "1" bit to message
53 | /* Notice: the input bytes are considered as bits strings,
54 | where the first bit is the most significant bit of the byte.[41]
55 |
56 |
57 | //Pre-processing: padding with zeros
58 | append "0" bit until message length in bit ≡ 448 (mod 512)
59 | append length mod (2 pow 64) to message
60 |
61 |
62 | //Process the message in successive 512-bit chunks:
63 | for each 512-bit chunk of message
64 | break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
65 | //Initialize hash value for this chunk:
66 | var int A := a0
67 | var int B := b0
68 | var int C := c0
69 | var int D := d0
70 | //Main loop:
71 | for i from 0 to 63
72 | if 0 ≤ i ≤ 15 then
73 | F := (B and C) or ((not B) and D)
74 | g := i
75 | else if 16 ≤ i ≤ 31
76 | F := (D and B) or ((not D) and C)
77 | g := (5×i + 1) mod 16
78 | else if 32 ≤ i ≤ 47
79 | F := B xor C xor D
80 | g := (3×i + 5) mod 16
81 | else if 48 ≤ i ≤ 63
82 | F := C xor (B or (not D))
83 | g := (7×i) mod 16
84 | dTemp := D
85 | D := C
86 | C := B
87 | B := B + leftrotate((A + F + K[i] + M[g]), s[i])
88 | A := dTemp
89 | end for
90 | //Add this chunk's hash to result so far:
91 | a0 := a0 + A
92 | b0 := b0 + B
93 | c0 := c0 + C
94 | d0 := d0 + D
95 | end for
96 |
97 | var char digest[16] := a0 append b0 append c0 append d0 //(Output is in little-endian)
98 |
99 | //leftrotate function definition
100 | leftrotate (x, c)
101 | return (x << c) binary or (x >> (32-c));
102 | ```
103 |
104 | ### References
105 |
106 | * [IETF RFC 1321](http://tools.ietf.org/html/rfc1321)
107 | * [Wikipedia](http://en.wikipedia.org/wiki/MD5#Algorithm)
108 |
--------------------------------------------------------------------------------
/md5/md5.rb:
--------------------------------------------------------------------------------
1 | class MD5
2 | def self.hexdigest(input)
3 |
4 | end
5 | end
--------------------------------------------------------------------------------
/md5/md5_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require_relative 'md5'
4 | require 'digest/md5'
5 |
6 | class MD5Test < Minitest::Test
7 | def test_it_hashes_a_string
8 | expected = Digest::MD5.hexdigest("Hello World\n")
9 | result = MD5.hexdigest("Hello World\n")
10 | assert_equal expected, result
11 | end
12 | end
--------------------------------------------------------------------------------
/pathfinding/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | guard :minitest do
5 | watch(%r{^test/(.*)\/?(.*)\.rb$})
6 | watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
7 | end
8 |
--------------------------------------------------------------------------------
/pathfinding/lib/landscape.rb:
--------------------------------------------------------------------------------
1 | class Landscape
2 | attr_reader :matrix
3 |
4 | def initialize(matrix)
5 | @matrix = matrix
6 | end
7 |
8 | def self.load(file_path)
9 | matrix = File.open(file_path) do |file|
10 | file.each_line.map do |line|
11 | line.chomp!.split(//)
12 | end
13 | end
14 | self.new(matrix)
15 | end
16 |
17 | def to_s
18 | matrix.map { |l| l.join("") }.join("\n")
19 | end
20 |
21 | def start
22 | element_coords("S")
23 | end
24 |
25 | def finish
26 | element_coords("F")
27 | end
28 |
29 | def element_coords(element)
30 | row = matrix.find { |f| f.include?(element) }
31 | y = matrix.index(row)
32 | x = row.index(element)
33 | [x,y]
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/pathfinding/lib/pathfinder.rb:
--------------------------------------------------------------------------------
1 | class Pathfinder
2 | def solve(landscape)
3 | []
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/pathfinding/test/fixtures/landscape1.txt:
--------------------------------------------------------------------------------
1 | ###########
2 | # S #
3 | # ##### # #
4 | # # # #
5 | ### # ### #
6 | # # #
7 | # # ### ###
8 | # # # #
9 | # ### # # #
10 | # # F #
11 | ###########
12 |
--------------------------------------------------------------------------------
/pathfinding/test/fixtures/landscape2.txt:
--------------------------------------------------------------------------------
1 | ######################
2 | # GGGGGGGGGGGG #
3 | # GGGGGGGGGGGG #
4 | # SGGGGGGGGGGGGF #
5 | # GGGGGGGGGGGG #
6 | # #
7 | ######################
8 |
--------------------------------------------------------------------------------
/pathfinding/test/landscape_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require 'minitest/pride'
4 | require 'minitest/spec'
5 | require_relative '../lib/landscape'
6 | require_relative '../lib/pathfinder'
7 |
8 | describe Landscape do
9 | it "generates a landscape from a fixture file" do
10 | matrix = [["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"],
11 | ["#", " ", "S", " ", " ", " ", " ", " ", " ", " ", "#"],
12 | ["#", " ", "#", "#", "#", "#", "#", " ", "#", " ", "#"],
13 | ["#", " ", " ", " ", "#", " ", " ", " ", "#", " ", "#"],
14 | ["#", "#", "#", " ", "#", " ", "#", "#", "#", " ", "#"],
15 | ["#", " ", " ", " ", " ", " ", "#", " ", " ", " ", "#"],
16 | ["#", " ", "#", " ", "#", "#", "#", " ", "#", "#", "#"],
17 | ["#", " ", "#", " ", " ", " ", "#", " ", " ", " ", "#"],
18 | ["#", " ", "#", "#", "#", " ", "#", " ", "#", " ", "#"],
19 | ["#", " ", " ", " ", " ", " ", "#", " ", "F", " ", "#"],
20 | ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]]
21 | loaded = Landscape.load(File.join(__dir__, "fixtures", "landscape1.txt")).matrix
22 | matrix.each_with_index do |line, index|
23 | assert_equal line, loaded[index], "line #{index} did not match"
24 | end
25 | end
26 |
27 | it "prints itself" do
28 | landscape = Landscape.load(File.join(__dir__, "fixtures", "landscape1.txt"))
29 | assert_equal File.read(File.join(__dir__, "fixtures", "landscape1.txt")).chomp, landscape.to_s
30 | end
31 |
32 | it "finds start and finish" do
33 | landscape = Landscape.load(File.join(__dir__, "fixtures", "landscape1.txt"))
34 | assert_equal [2,1], landscape.start
35 | assert_equal [8,9], landscape.finish
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/pathfinding/test/pathfinder_test.rb:
--------------------------------------------------------------------------------
1 | gem 'minitest'
2 | require 'minitest/autorun'
3 | require 'minitest/pride'
4 | require 'minitest/spec'
5 | require_relative '../lib/landscape'
6 | require_relative '../lib/pathfinder'
7 |
8 | describe Pathfinder do
9 | before do
10 | @landscape = Landscape.load(File.join(__dir__, "fixtures", "landscape1.txt"))
11 | @landscape2 = Landscape.load(File.join(__dir__, "fixtures", "landscape2.txt"))
12 | @pathfinder = Pathfinder.new
13 | end
14 |
15 | describe "#solve" do
16 | it "returns a path as an array of coordinates" do
17 | solution = [[3,1],[4,1],[5,1],[6,1],[7,1],[8,1],[9,1],
18 | [9,2],[9,3],[9,4],[9,5],[8,5],[7,5],[7,6],
19 | [7,7],[7,8],[7,9]]
20 | assert_equal solution, @pathfinder.solve(@landscape)
21 | end
22 |
23 | it "Solves with grass" do
24 | solution = [[3,4],[3,5],[4,5],[5,5],[6,5],[7,5],[8,5],
25 | [9,5],[10,5],[11,5],[12,5],[13,5],[14,5],
26 | [15,5],[16,5],[16,4]]
27 | assert_equal solution, @pathfinder.solve(@landscape2)
28 | end
29 | end
30 | end
31 |
32 |
--------------------------------------------------------------------------------
/red_black_trees/README.markdown:
--------------------------------------------------------------------------------
1 | ### Red/Black Binary Trees
2 |
3 | * Subtype of Binary Tree
4 | * Trying to solve the problem of worst-case / guaranteed performance
5 |
6 | #### Worst-case Binary Trees
7 |
8 | * Inserting ordered data:
9 |
10 | ```
11 | 1
12 | \
13 | 2
14 | \
15 | 3
16 | \
17 | 4
18 | ```
19 |
20 | * Inserting reverse-ordered Data:
21 |
22 | ```
23 | 4
24 | /
25 | 3
26 | /
27 | 2
28 | /
29 | 1
30 | ```
31 |
32 | * Inserting ordered data alternating between first / last
33 |
34 | ```
35 | 1
36 | \
37 | 6
38 | /
39 | 2
40 | \
41 | 5
42 | /
43 | 3
44 | \
45 | 4
46 | ```
47 |
48 | In each of these cases, we can see that the order of the data
49 | causes us to lose the crucial branching factor which makes
50 | binary trees efficient.
51 |
52 | In fact, we end up with a "directed graph of order 1"... i.e. a
53 | Linked List.
54 |
55 | #### Solving the problem
56 |
57 | One solution to the problem is to periodically stop and re-balance
58 | the tree. This is partly why balancing is such an interesting
59 | and important operation for trees.
60 |
61 | However doing a lengthy re-balance can sometimes be very costly.
62 | It would be ideal if we could ensure our tree remained balanced
63 | in the first place by doing small, incremental re-balancing
64 | as we go.
65 |
66 | This is exactly the problem a [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) solves.
67 |
68 | #### RB Tree Coloring Conventions
69 |
70 | So why is a Red-Black tree named as such?
71 |
72 | In order for the tree to self balance it needs a general understanding of its nodes. Color coding each as red or black (pink/green if you want to fight the power!) serves this purpose.
73 |
74 | #### RB Tree Fundamentals
75 |
76 | **Properties**
77 |
78 | 1. A node is either red or black.
79 | 2. The root is black. This rule is sometimes omitted. Since the root can always be changed from red to black, but not necessarily vice versa, this rule has little effect on analysis.
80 | 3. All leaves (NIL) are black.
81 | 4. If a node is red, then both its children are black.
82 | 5. Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes. The uniform number of black nodes in the paths from root to leaves is called the black-height of the red–black tree.
83 |
84 | Source: https://en.wikipedia.org/wiki/Red–black_tree
85 |
86 | **Property overview**
87 |
88 | 1. This is simplistic and can be represented by a bit (0 / 1) with in each node
89 | 2. Simpler to implement if you just assume "Root must be black!!"
90 | 3. In a normal Binary Search Tree leaves are typically nodes with values associated with them. RB trees also have leaves but they have a NIL value associated with them.
91 | 4. This property combined with property 5 will determine the shape of the tree
92 | 5. Unfortunately the definition above is pretty good (even though it is confusing). An example will hopefully give some context:
93 |
94 | ```
95 | x = NIL(B)
96 |
97 | 5(B)
98 | / \
99 | 4(R) 6(R)
100 | / \ / \
101 | x x x x
102 | ```
103 | In the valid tree above the root would have a black height of 1. The black height is the number of black nodes between the given node (root) and a descendant leaf. So if the left most path is taken the root would encounter 1 black node (which would be the leaf itself). Property 5 asserts on that all of the paths from the said node (our case the root) must have the same number of black node encounters. So for all four paths the root can take to the leaves the black height must be one in order for it to be a valid RB tree
104 |
105 | The combination of properties 4 and 5 force the tree to be about balanced on both sides.
106 |
107 | #### RB Tree Insertion
108 |
109 | Insertion is one of the crucial operations for an RBT, as this is
110 | when we need to make the appropriate adjustments to keep the tree
111 | balanced.
112 |
113 | A rough algorithm for the insertion process is as follows
114 |
115 | In fact, we can partly divide the insertion process into 2
116 | steps -- standard insertion, followed by possible rotation
117 | / rebalancing.
118 |
119 | __Node Creation / Insertion__
120 |
121 | 1. Create a new node `N` to hold the inserted piece of data
122 | 2. If the tree is empty, `N` will become the new root node, so
123 | make it black
124 | 3. Otherwise, insert `N` into the tree as with a normal BST and make it red
125 |
126 | __Tree Rotation / Rebalancing__
127 |
128 | Now, we need to check if the tree has remained balanced.
129 | Possibly we will need to do some re-balancing, and there are,
130 | unfortunately, quite a few possible cases that need to be
131 | handled.
132 |
133 | For this step, we'll often start out looking at a given
134 | Node's "aunt"/"uncle". As in human geneology, the aunt node
135 | of a given node is the sibling of its parent.
136 |
137 | So in this example, we would say 6 is an uncle node of 3:
138 |
139 | ```
140 | 5
141 | / \
142 | 4 6
143 | /
144 | 3
145 | ```
146 |
147 | __Aunt/Uncle Cases__
148 |
149 | Now, we need to look at how to adjust the tree based on the various
150 | arrangements of our tree when we have inserted a new node.
151 | Again, we have to subdivide these into 2 sub-groups of cases,
152 | depending on the color of the aunt nodes.
153 |
154 | 1. Aunt/Uncle node is Red
155 | 2. Aunt/Uncle node is Black
156 |
157 | #### Aunt/Uncle Node is Red Subcase
158 |
159 | In this case just recoloring can be implemented (no rotations needed!):
160 |
161 | ```
162 | 5(B)
163 | / \
164 | 4(R) 6(R)
165 | /
166 | 3(R)
167 | ```
168 | Property 4 will be violated sometimes a new node is inserted on the tree.
169 | If the Aunt (Uncle) is red we can implement recoloring. Parent, Aunt and
170 | Grandparent should each inverse their colors.
171 |
172 | ```
173 | 5(R)
174 | / \
175 | 4(B) 6(B)
176 | /
177 | 3(R)
178 | ```
179 | Depending on whether this is a subtree or the root it could violate property 2!
180 | When it is the root feel free to recolor it to black. This will not violate
181 | property 5.
182 |
183 |
184 | #### Aunt/Uncle Node is Black Subcases
185 |
186 | In these cases, we need to
187 | consider the tree from a perspective of 3 "generations" at a time:
188 | the newly inserted node, `N`, the Parent / Uncle generation, and the
189 | Grandparent generation.
190 |
191 | For this generation configuration, we will see that we actually have
192 | 2 possible positions for our new node (also duplicated on the opposite side):
193 |
194 | **Case One (aka Left-Left - `N` is left child of left child)**
195 |
196 | ```
197 | G(B)
198 | / \
199 | P(R) NIL(B)
200 | /
201 | N(R)
202 | ```
203 | NIL leaf and a node colored black are the same logic
204 |
205 | **Case Two (aka Left-Right - `N` is right child of left child)**
206 |
207 | ```
208 | G(B)
209 | / \
210 | P(R) NIL(B)
211 | \
212 | N(R)
213 | ```
214 | NIL leaf and a node colored black are the same logic
215 |
216 |
217 | ####Solutions
218 |
219 | **Solution One (aka Left-Left - `N` is left child of left child)**
220 |
221 | ```
222 | Initial insertion
223 |
224 | G(B)
225 | / \
226 | P(R) NIL(B)
227 | /
228 | N(R)
229 |
230 | Rotate G(B) right
231 |
232 | P(R)
233 | / \
234 | N(R) G(B)
235 | \
236 | NIL(B)
237 |
238 | Recolor
239 |
240 | P(B)
241 | / \
242 | N(R) G(R)
243 | \
244 | NIL(B)
245 |
246 | ```
247 |
248 | **Solution Two (aka Left-Right - `N` is right child of left child)**
249 |
250 | ```
251 | Initial insertion
252 |
253 | G(B)
254 | / \
255 | P(R) NIL(B)
256 | \
257 | N(R)
258 |
259 | Rotate P(R) left
260 |
261 | G(B)
262 | / \
263 | N(R) NIL(B)
264 | /
265 | P(R)
266 |
267 |
268 | Rotate G(B) right
269 |
270 | N(R)
271 | / \
272 | P(R) G(B)
273 | \
274 | NIL(B)
275 |
276 | Recolor
277 |
278 | N(B)
279 | / \
280 | P(R) G(R)
281 | \
282 | NIL(B)
283 |
284 | ```
285 |
286 | __Implementation Tips and Tricks__
287 |
288 | 1. After case one or case two no properties should be violated
289 | 2. Recolor can recurse its way up the tree (to a rotate if needed)
290 | 3. BST functionality is useful to build before building RBT functionality
291 |
292 |
293 | Insertion cases writeup: http://www.geeksforgeeks.org/red-black-tree-set-2-insert/
294 |
295 | Insertion cases video: https://www.youtube.com/watch?v=g9SaX0yeneU
296 |
297 | Better visual representation of rotations: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-046j-introduction-to-algorithms-sma-5503-fall-2005/video-lectures/lecture-10-red-black-trees-rotations-insertions-deletions/lec10.pdf
298 |
--------------------------------------------------------------------------------
/resources/number_generator.rb:
--------------------------------------------------------------------------------
1 | filename = "sample_numbers.txt"
2 | file = File.open("./resources/" + filename, "w")
3 | quantity = 1000000
4 | quantity.times do |i|
5 | if i % 100 == 0
6 | puts "#{quantity - i} left"
7 | end
8 | file.write(rand(quantity/2).to_s + "\n")
9 | end
--------------------------------------------------------------------------------
/sha_1/README.markdown:
--------------------------------------------------------------------------------
1 | # SHA-1
2 |
3 | ## Hash Function Intro
4 |
5 | ## SHA-1 Resources
6 |
7 | A great writeup of the SHA-1 process with fairly detailed
8 | examples can be found [here](http://m.metamorphosite.com/one-way-hash-encryption-sha1-data-software).
9 |
10 | ## SHA-1 Process
11 |
12 | ### 1. Prep the message
13 |
14 | Before we start on the core of the algorithm, we need
15 | to run through a few preparatory steps. The main body of the
16 | function will be operating on the underlying bits that make up
17 | our (originally textual) message.
18 |
19 | In order to smooth things out, we need to pre-process the message
20 | a bit in order to get it into a compatible format. A rough
21 | outline of the steps looks like this:
22 |
23 | 1. Convert the message into its bit-array (or byte-array) representation
24 | 2. "Pad" the message bits to be congruent with 448 modulo 512
25 | 3. Separate the message from the appended padding by a "1" bit
26 | 4. Append 64 bits representing the original length of the message
27 | in characters (or bytes)
28 |
29 | __Converting the message to bytes__
30 |
31 | For the remainder of the algorithm, we'll be working with the
32 | underlying bits (or bytes) that make up the text of the message.
33 | To get started, we need to first convert the message into
34 | a sequence of bits.
35 |
36 | There are various ways to handle this, and they will likely vary
37 | depending on how "low level" your language is, and what facilities
38 | it exposes to you for doing low-level bit manipulation.
39 |
40 | For example in C, we might simply allocate a large block of memory
41 | equivalent to the bit-length we'll ultimately need to work with
42 | and start going to town.
43 |
44 | In Java or other JVM languages, we might work with a byte array --
45 | a sequential data structure for working with a series of bytes,
46 | or 8-bit units.
47 |
48 | Yet another option which, while probably not the fastest, might
49 | make things easier to inspect and reason about, would be to
50 | use your language's built-in String facilities to model the problem
51 | around a series of literal "0" and "1" characters.
52 |
53 | In any case, you'll want to start out by converting your message
54 | character by character into a sequence of bytes. This is pretty
55 | easy for simple Latin text, since the ASCII character encoding is
56 | built around a byte-per-character model.
57 |
58 | Each character in ASCII maps to a predefined byte value, which
59 | we can ultimately encode in our string as a sequence of 8 bits.
60 | See [this table](http://www.asciitable.com/) for a list of the various
61 | encodings.
62 |
63 | In Ruby, for example, we can convert a character to its ASCII value
64 | like so:
65 |
66 | ```ruby
67 | >"pizza".each_byte.to_a
68 | => [112, 105, 122, 122, 97]
69 | ```
70 |
71 | The `String#ord` method is useful for this as well:
72 |
73 | ```ruby
74 | >"p".ord
75 | => 112
76 | > "pizza".chars.map(&:ord)
77 | => [112, 105, 122, 122, 97]
78 | ```
79 |
80 | Next we would want to convert these each to an 8-bit binary
81 | number, and combine them all together:
82 |
83 | ```ruby
84 | > "pizza".chars.map(&:ord).map { |i| i.to_s(2) }
85 | ["1110000", "1101001", "1111010", "1111010", "1100001"]
86 | ```
87 |
88 | And then join them together:
89 |
90 | ```ruby
91 | > "pizza".chars.map(&:ord).map { |i| i.to_s(2) }.join
92 | "pizza".chars.map(&:ord).map { |i| i.to_s(2) }.join
93 | "11100001101001111101011110101100001"
94 | ```
95 |
96 | Getting close, but if we look closely, we'll see that we
97 | ended up with a 35-bit binary string, as opposed to the expected
98 | 40 bits.
99 |
100 | One tricky issue when working with binary numbers is to make sure
101 | we aren't losing or unintentionally colliding our numbers.
102 | In this case, Ruby omits leading `0`'s when converting a number
103 | to a binary string.
104 |
105 | This is one area where working with something like a byte
106 | array would help us (since a literal byte will preserve the appropriate
107 | 8 bits), but if you want to go down the string route you'll need
108 | to "pad" your bits to preserve leading 0's.
109 |
110 | For now, we can imagine doing something like this:
111 |
112 | ```ruby
113 | >"pizza".chars.map(&:ord).map do |i|
114 | i.to_s(2)
115 | end.map do |i|
116 | "0" + i
117 | end.join.length
118 | => "0111000001101001011110100111101001100001"
119 | ```
120 |
121 | __Padding the Message__
122 |
123 | Now that we have some binary representation of our incoming message,
124 | we need to "pad" it. The reason for padding the message is that the
125 | SHA-1 algorithm is designed to work on blocks of 512 bits at a time.
126 |
127 | To facilitate this, we need to massage the message to give it a bit-length
128 | that fits neatly into our block size.
129 |
130 | * Modulo Congruence
131 | * Target 448 congruence
132 | * Leaving room for 64-bit message length
133 |
134 | __Appending Binary Message-Length__
135 |
136 | Now that we've padded out the message, we're going to finish
137 | out the last block by adding a series of bits representing
138 | the length of the original message.
139 |
140 | The length we're interested in is the original length of the
141 | message in bytes (or characters, in ASCII), and we'll be
142 | expressing it as a 64-bit integer. Hence why it was so important
143 | to pad the message out to congruence with 448 mod 512 -- to leave
144 | room for these 64 message-length bits at the end.
145 |
146 | For this step, take the length of the message, turn it to binary, and
147 | left-pad it to make sure the overall length works out to 64 bits.
148 |
149 | (Alternatively, you can simply make sure your value is cast to a
150 | 64-bit int, for example Java's `long` type)
151 |
152 | #### random notes
153 |
154 | "Add appropriate number of 0 bytes to bring message into congruence with 448
155 | mod 512 (56 mod 64 bytes). Additionally, the first bit of this padding sequence
156 | should be set 1 to separate original message from padding."
157 |
158 | "takes incoming string message through various steps needed to
159 | convert it to a mod-512 byte array with appropriate padding and
160 | meessage length appended"
161 |
162 | ```clojure
163 | ;; extending block
164 | ;; iterate i = 16 - 79
165 | ;; each iteration, take diffs:
166 | ;; i - 3
167 | ;; i - 8
168 | ;; i - 14
169 | ;; i - 16
170 | ;; as we go, we will be adding new words to the end of our
171 | ;; sequence, so e.g. i=17 doesn't exist at the start, but it
172 | ;; will get added adter the first iteration
173 |
174 |
175 | ;; within each loop, take the 4 selected words,
176 | ;; and reduce them via XOR
177 | ;; so first, (XOR (i-3) (i-8)) (i.e. word 13 and word 8)
178 | ;; then (XOR _result (i-14))
179 | ;; then (XOR _result (i-16))
180 | ;; something like this:
181 | #(-> (aget block (- i 3))
182 | (bit-xor (aget block (- i 8)))
183 | (bit-xor (aget block (- i 14)))
184 | (bit-xor (aget block (- i 16))))
185 |
186 | ;; next, "carry through left bit rotation by a factor of 1" ?!?!?
187 | ;; i.e. remove first digit of left-most word and append it to the end
188 | ;; of the word -- probably some right-shifts and left shifts?
189 |
190 | ;; Finally, after this rotation
191 | ;; this word gets appended to the end of our existing 16 words,
192 | ;; becoming word 17
193 | ;; this sequence repeats until 80 words are generated
194 | ;; from the original 17
195 | ```
196 |
197 | ;; string "ab" should give
198 | ;; 97,98 binary
199 | ;; + "1"
200 | ;; + diff to make congruent mod 512
201 | ;; + message length in characters padded to 64 bits
202 | ;; or:
203 | ;; "11000011" + "100010" + "1" + ("0" * 443) + (64-bit padded 2)
204 |
205 |
206 | "pads short message to 56 total bytes, leaving 8 bytes in
207 | same 512-bit block for message length. Additionally, leading
208 | padding bit should be 1 to distinguish padding from message"
209 |
210 |
211 | "pads message longer than 512 bits to be congruent with 448
212 | mod 512, leaving 8 bytes for message length in next block"
213 |
214 | "message longer that is greater than 448 mod 512 bits still has to
215 | pad to 448 congruence in next block since there aren't enough bits
216 | left in current block for 64-bit message-length encoding"
217 |
218 | "generates byte-array for encoding message length as 64-bit long"
219 |
220 | "preps message by converting to bytes, adding padding separator bit,
221 | adding congruence padding, and adding message length bits"
222 |
223 | "take a 64-byte chunk consisting of 16 4-byte words
224 | and 'extend' it to generate 80 words from the original
225 | 16"
226 |
--------------------------------------------------------------------------------
/topics_wishlist.markdown:
--------------------------------------------------------------------------------
1 | Unsorted list of various technical interview questions/topics culled from the internet.
2 |
3 | ### General
4 |
5 | * Find the most frequent integer in an array
6 | * Find pairs in an integer array whose sum is equal to 10 (bonus: do it in linear time)
7 | * Given 2 integer arrays, determine of the 2nd array is a rotated version of the 1st array. Ex. Original Array A={1,2,3,5,6,7,8} Rotated Array B={5,6,7,8,1,2,3}
8 | * Write fibbonaci iteratively and recursively (bonus: use dynamic programming)
9 | * Find the only element in an array that only occurs once.
10 | * Find the common elements of 2 int arrays
11 | * Implement binary search of a sorted array of integers
12 | * Implement binary search in a rotated array (ex. {5,6,7,8,1,2,3})
13 | * Use dynamic programming to find the first X prime numbers
14 | * Write a function that prints out the binary form of an int
15 | * Implement parseInt
16 | * Implement squareroot function
17 | * Implement an exponent function (bonus: now try in log(n) time)
18 | * Write a multiply function that multiples 2 integers without using *
19 | * HARD: Given a function rand5() that returns a random int between 0 and 5, implement rand7()
20 | * HARD: Given a 2D array of 1s and 0s, count the number of "islands of 1s" (e.g. groups of connecting 1s)
21 | * Count the number of set bits in a byte/int32 (7 different solutions)
22 | * Implement a function to return a ratio from a double (ie 0.25 -> 1/4). The function will also take a tolerance so if toleran ce is .01 then FindRatio(.24, .01) -> 1/4
23 |
24 | ### Strings
25 |
26 | * Find the first non-repeated character in a String
27 | * Reverse a String iteratively and recursively
28 | * Determine if 2 Strings are anagrams
29 | * Check if String is a palindrome
30 | * Check if a String is composed of all unique characters
31 | * Determine if a String is an int or a double
32 | * HARD: Find the shortest palindrome in a String
33 | * HARD: Print all permutations of a String
34 | * HARD: Given a single-line text String and a maximum width value, write the function 'String justify(String text, int maxWidth)' that formats the input text using full-justification, i.e., extra spaces on each line are equally distributed between the words; the first word on each line is flushed left and the last word on each line is flushed right
35 | * Reverse words in a string (words are separated by one or more spaces). Now do it in-place. By far the most popular string question!
36 | * Remove duplicate chars from a string ("AAA BBB" -> "A B")
37 | * Find the first non-repeating character in a string:("ABCA" -> B )
38 |
39 | ### Trees
40 |
41 | * Implement a BST with insert and delete functions
42 | * Print a tree using BFS and DFS
43 | * Write a function that determines if a tree is a BST
44 | * Find the smallest element in a BST
45 | * Find the 2nd largest number in a BST
46 | * Given a binary tree which is a sum tree (child nodes add to parent), write an algorithm to determine whether the tree is a valid sum tree
47 | * Find the distance between 2 nodes in a BST and a normal binary tree
48 | * Print the coordinates of every node in a binary tree, where root is 0,0
49 | * Print a tree by levels
50 | * Given a binary tree which is a sum tree, write an algorithm to determine whether the tree is a valid sum tree
51 | * Given a tree, verify that it contains a subtree.
52 | * HARD: Find the max distance between 2 nodes in a BST.
53 | * HARD: Construct a BST given the pre-order and in-order traversal Strings
54 | * Insert
55 | * PrintInOrder
56 | * PrintPreOrder
57 | * PrintPostOrder
58 | * Implement a non-recursive PrintInOrder
59 |
60 | ### Linked Lists
61 |
62 | This is an extremely popular topic. I've had linked lists on every interview.
63 | You must be able to produce simple clean linked list implementations quickly.
64 |
65 | * Implement a linked list (with insert and delete functions)
66 | * singly-linked linked list
67 | * sorted linked list
68 | * circular linked list
69 | * Find the Nth element in a linked list
70 | * Remove the Nth element of a linked list
71 | * Check if a linked list has cycles
72 | * Given a circular linked list, find the node at the beginning of the loop. Example: A-->B-->C --> D-->E -->C, C is the node that begins the loop
73 | * Check whether a link list is a palindrome
74 | * Reverse a linked list iteratively and recursively
75 | * Split a linked list given a pivot value
76 | * Find the middle of a linked list. Now do it while only going through the list once. (same solution as finding cycles)
77 |
78 | ### Sorting
79 |
80 | * Implement bubble sort
81 | * Implement selection sort
82 | * Implement insertion sort
83 | * Implement merge sort
84 | * Implement quick sort
85 |
86 | ### Arrays
87 |
88 | * You are given an array with integers between 1 and 1,000,000. One integer is in the array twice. How can you determine which one? Can you think of a way to do it using little extra memory.
89 | * You are given an array with integers between 1 and 1,000,000. One integer is missing. How can you determine which one? Can you think of a way to do it while iterating through the array only once. Is overflow a problem in the solution? Why not?
90 | * Returns the largest sum of contiguous integers in the array -- Example: if the input is (-10, 2, 3, -2, 0, 5, -15), the largest sum is 8
91 | * Implement Shuffle given an array containing a deck of cards and the number of cards. Now make it O(n).
92 | * Return the sum two largest integers in an array
93 | * Sum n largest integers in an array of integers where every integer is between 0 and 9
94 |
95 | ### Heaps / Stacks / Queues
96 |
97 | * Difference between heap and stack? Write a function to figure out if stack grows up or down.
98 | * Implement a stack with push and pop functions
99 | * Implement a queue with queue and dequeue functions
100 | * Find the minimum element in a stack in O(1) time
101 | * Write a function that sorts a stack (bonus: sort the stack in place without extra memory)
102 | * Implement a binary min heap. Turn it into a binary max heap
103 | * HARD: Implement a queue using 2 stacks
104 |
105 | ### SQL
106 |
107 | TK
108 |
--------------------------------------------------------------------------------
/tries/README.md:
--------------------------------------------------------------------------------
1 | ## Tries
2 |
3 | A Trie is a type of branching data structure often used for storing
4 | and querying words within a body of text. The name comes from the idea
5 | of "Re__trie__val" -- a Trie is well suited for rapid retrieval of
6 | a provided search string. Additionally, its organization as a tree
7 | structure allows it to efficiently find all "children" of a given substring,
8 | making it ideally suited for predictive text applications.
9 |
10 | ### Visualizing a Trie
11 |
12 | A Trie can be implemented as an N-ary tree, where the root node
13 | is empty and all of its children represent the first characters
14 | of the various strings contained in the trie. Consider this
15 | very simple example storing the strings "cat", "dog", and "do":
16 |
17 | ```
18 | Root
19 | c/ \d
20 | node-() node-()
21 | |a |o
22 | node() node-(do)
23 | |t |g
24 | node-(cat) node-(dog)
25 | ```
26 |
27 | To search this Trie for cat or dog, we start from the root and
28 | check each character in turn to see if it appears along a path
29 | between the root and the leaves. If we tried to search for "catty"
30 | we would run out of nodes along the "cat" path before we found all
31 | of our characters, and thus could determine that "catty" does not
32 | appear.
33 |
34 | Additionally, we can see that some interior "nodes" in the trie serve only as branching or connection
35 | points to valid nodes that exist further down in the structure (such as the "ca")
36 | node.
37 |
38 | Alternatively, some interior nodes also represent valid words in and of
39 | themselves (e.g. the "do" node). Your trie implementation will likely
40 | need some way to distinguish these types of interior nodes.
41 |
42 | ### Branching
43 |
44 | A great thing about Tries is the ability to represent branching of
45 | strings that share common prefixes. Let's add "car" and "dot" to our
46 | Trie above:
47 |
48 | ```
49 | Root
50 | c/ \d
51 | node node
52 | a| |o
53 | node node—————
54 | t/ \ \ \t
55 | node-cat \r \g node-dot
56 | node-car \
57 | node-dog
58 | ```
59 |
60 | Now, when searching, we would encounter branches at the "c-a" or "d-o"
61 | points. Depending which string we are looking for, we could go left or
62 | right.
63 |
64 | ### Node/Word Storage
65 |
66 | In these diagrams we've been representing nodes as containing the word
67 | that they represent, but in a proper Trie structure, nodes don't
68 | actually contain data. Rather, the data a node represents can be
69 | inferred from the path that was used to reach it (so if we reach a node
70 | by walking d-o-g, we know already that the node represents "dog" without
71 | having to label it as such).
72 |
73 | For a node to be a terminating (leaf) node, it must represent the result
74 | of a valid path through the Trie (i.e. a valid word). For intermediate
75 | (interior) nodes that represent valid words (e.g. "d-o" on the way to
76 | "d-o-g"), they will need to be labeled or marked in some way.
77 |
78 |
79 | ### Challenge -- Tries for Text Prediction
80 |
81 | A common real-word use-case for tries is doing word prediction,
82 | such as the auto-completion on your smartphone.
83 |
84 | See if you can complete a trie data structure that will
85 | allow us to fulfill a basic version of this feature.
86 | We'd like to provide an interface along the lines of:
87 |
88 | ```
89 | t = Trie.new
90 | input_words.each do |w|
91 | t.insert(w)
92 | end
93 |
94 | t.suggest("piz")
95 | => ["pizza", "pizzeria", "pizzicato"]
96 | ```
97 |
--------------------------------------------------------------------------------