diff --git a/.gitignore b/.gitignore index 6fee6d3a..2458e8b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea/* -*.log \ No newline at end of file +*.log +node_modules +coverage diff --git a/README.md b/README.md index 9712708a..64771d99 100644 --- a/README.md +++ b/README.md @@ -3,26 +3,41 @@ Learning JavaScript Data Structures and Algorithms Source code of **Learning JavaScript Data Structures and Algorithms** book. -Book link: +| 1st edition | 2nd edition | +| ------------- |:-------------:| +| ![1st edition](https://d1ldz4te4covpm.cloudfront.net/sites/default/files/imagecache/ppv4_main_book_cover/4874OS_Learning%20JavaScript%20Data%20Structures%20and%20Algorithms.jpg) | ![2nd edition](https://d255esdrn735hr.cloudfront.net/sites/default/files/imagecache/ppv4_main_book_cover/5493OS_5348_Learning%20JavaScript%20Data%20Structures%20and%20Algorithms,%20Second%20Edition.jpg) | +| [Book link](http://amzn.to/1Y1OWPx)| [Book link](http://amzn.to/1TSkcA1)| + +Book link - first edition: - [Packt](https://www.packtpub.com/application-development/learning-javascript-data-structures-and-algorithms) - - [Amazon](http://www.amazon.com/gp/product/1783554878/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1783554878&linkCode=as2&tag=loiagron-20&linkId=7VBQ7OMJ47XY7MUV) + - [Amazon](http://amzn.to/1Y1OWPx) + - [Chinese version](http://www.ituring.com.cn/book/1613) + - [Korean version](http://www.acornpub.co.kr/book/javascript-data-structure) +Book link - second edition: + - [Packt](https://www.packtpub.com/web-development/learning-javascript-data-structures-and-algorithms-second-edition) + - [Amazon](http://amzn.to/1TSkcA1) + - [Brazilian Portuguese version](https://novatec.com.br/livros/estruturas-de-dados-algoritmos-em-javascript/) -###List of Chapters: +### List of Chapters: -* 1: JAVASCRIPT – A QUICK OVERVIEW -* 2: ARRAYS -* 3: STACKS -* 4: QUEUES -* 5: LINKED LISTS -* 6: SETS -* 7: DICTIONARIES AND HASHES -* 8: TREES -* 9: GRAPHS -* 10: SORTING AND SEARCHING ALGORITHMS -* 11: More about Algorithms (Recursion, Dynamic Programing, Greedy Algorithms and Big-O Notation) - Extra chapter that can be donwloaded from [Packt](https://www.packtpub.com/application-development/learning-javascript-data-structures-and-algorithms) website -* Apendix A: Big-O Cheat Sheet - Extra chapter that can be donwloaded from [Packt](https://www.packtpub.com/application-development/learning-javascript-data-structures-and-algorithms) website - -###Found an issue or have a question? +* 01: [JavaScript: a quick overview](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter01) +* 02: [Arrays](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter02) +* 03: [Stacks](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter03) +* 04: [Queues](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter04) +* 05: [Linked Lists](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter05) +* 06: [Sets](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter06) +* 07: [Dictionaries and Hashes](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter07) +* 08: [Trees](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter08) +* 09: [Graphs](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter09) +* 10: [Sorting and searching algorithms](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter10) +* 11: [Pattern of algorithms](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter11) +* 12: [Algorithm Complexity](https://github.com/loiane/javascript-datastructures-algorithms/tree/second-edition/chapter12) + +### First Edition source code: + +Please refer to [this link](https://github.com/loiane/javascript-datastructures-algorithms/tree/master) + +### Found an issue or have a question? Please create an [Issue](https://github.com/loiane/javascript-datastructures-algorithms/issues) or [Pull Request](https://github.com/loiane/javascript-datastructures-algorithms/pulls) diff --git a/chapter01/14-ES6ParameterHandling.js b/chapter01/14-ES6ParameterHandling.js index 706c2059..af23585c 100644 --- a/chapter01/14-ES6ParameterHandling.js +++ b/chapter01/14-ES6ParameterHandling.js @@ -14,7 +14,7 @@ function sum2 (x, y, z) { z = 3; return x + y + z; }; -console.log(sum2(4,2)); //outpus 10 +console.log(sum2(4,2)); //outpus 9 //******* EcmaScript 6: spread operator ('...') var params = [3, 4, 5]; @@ -30,8 +30,8 @@ function restParamaterFunction (x, y, ...a) { console.log(restParamaterFunction(1, 2, "hello", true, 7)); // outputs 9; //code above is the same as ES5: -function restParamaterFunction (x, y) { +function restParamaterFunction2 (x, y) { var a = Array.prototype.slice.call(arguments, 2); return (x + y) * a.length; }; -console.log(restParamaterFunction2(1, 2, "hello", true, 7)); \ No newline at end of file +console.log(restParamaterFunction2(1, 2, "hello", true, 7)); diff --git a/chapter02/06-ES6Methods.js b/chapter02/06-ES6Methods.js index 60468aa4..bf4eb36a 100644 --- a/chapter02/06-ES6Methods.js +++ b/chapter02/06-ES6Methods.js @@ -40,7 +40,7 @@ console.log(aKeys.next()); // {value: 1, done: false } console.log(aKeys.next()); // {value: 2, done: false } console.log('Array.values'); -//let aValues = numbers.values(); +let aValues = numbers.values(); console.log(aValues.next()); // {value: 1, done: false } done false means iterator has more values console.log(aValues.next()); // {value: 2, done: false } console.log(aValues.next()); // {value: 3, done: false } diff --git a/chapter03/01-Stack3.js b/chapter03/01-Stack3.js index fd490ffa..d13a87dd 100644 --- a/chapter03/01-Stack3.js +++ b/chapter03/01-Stack3.js @@ -11,13 +11,11 @@ let Stack3 = (function () { push(element){ let s = items.get(this); s.push(element); - items.set(this, s); } pop(){ let s = items.get(this); let r = s.pop(); - items.set(this, s); return r; } diff --git a/chapter03/02-UsingStacks.js b/chapter03/02-UsingStacks.js index a84703a3..9876e892 100644 --- a/chapter03/02-UsingStacks.js +++ b/chapter03/02-UsingStacks.js @@ -1,4 +1,4 @@ -let stack = new Stack2(); +let stack = new Stack3(); console.log(stack.isEmpty()); //outputs true stack.push(5); stack.push(8); @@ -15,10 +15,10 @@ let stack = new Stack2(); //how to ensure true privacy //in case using Stack 2 uncomment code below -let objectSymbols = Object.getOwnPropertySymbols(stack); +/*let objectSymbols = Object.getOwnPropertySymbols(stack); console.log(objectSymbols.length); // 1 console.log(objectSymbols); // [Symbol()] console.log(objectSymbols[0]); // Symbol() stack[objectSymbols[0]].push(1); - stack.print(); //5, 8, 1 \ No newline at end of file + stack.print(); //5, 8, 1*/ \ No newline at end of file diff --git a/chapter04/01-Queue2.js b/chapter04/01-Queue2.js index c35ea102..d4bc9891 100644 --- a/chapter04/01-Queue2.js +++ b/chapter04/01-Queue2.js @@ -11,13 +11,11 @@ let Queue2 = (function () { enqueue(element) { let q = items.get(this); q.push(element); - items.set(this, q) } dequeue() { let q = items.get(this); let r = q.shift(); - items.set(this, q); return r; } diff --git a/chapter04/02-UsingQueues.js b/chapter04/02-UsingQueues.js index 1b3f58ae..5411bad6 100644 --- a/chapter04/02-UsingQueues.js +++ b/chapter04/02-UsingQueues.js @@ -1,4 +1,4 @@ -let queue = new Queue(); +let queue = new Queue2(); console.log(queue.isEmpty()); //outputs true queue.enqueue("John"); queue.enqueue("Jack"); diff --git a/chapter04/03-PriorityQueue.js b/chapter04/03-PriorityQueue.js index f9071ddc..3b029e4d 100644 --- a/chapter04/03-PriorityQueue.js +++ b/chapter04/03-PriorityQueue.js @@ -50,7 +50,5 @@ let priorityQueue = new PriorityQueue(); priorityQueue.enqueue("John", 2); priorityQueue.enqueue("Jack", 1); priorityQueue.enqueue("Camila", 1); -priorityQueue.enqueue("Maxwell", 2); -priorityQueue.enqueue("Ana", 3); priorityQueue.print(); diff --git a/chapter05/01-Linked-List.js b/chapter05/01-LinkedList.js similarity index 88% rename from chapter05/01-Linked-List.js rename to chapter05/01-LinkedList.js index d4f4637f..3e52bc80 100644 --- a/chapter05/01-Linked-List.js +++ b/chapter05/01-LinkedList.js @@ -1,17 +1,17 @@ function LinkedList() { - var Node = function(element){ + let Node = function(element){ this.element = element; this.next = null; }; - var length = 0; - var head = null; + let length = 0; + let head = null; this.append = function(element){ - var node = new Node(element), + let node = new Node(element), current; if (head === null){ //first node on list @@ -37,7 +37,7 @@ function LinkedList() { //check for out-of-bounds values if (position >= 0 && position <= length){ - var node = new Node(element), + let node = new Node(element), current = head, previous, index = 0; @@ -70,7 +70,7 @@ function LinkedList() { //check for out-of-bounds values if (position > -1 && position < length){ - var current = head, + let current = head, previous, index = 0; @@ -100,13 +100,13 @@ function LinkedList() { this.remove = function(element){ - var index = this.indexOf(element); + let index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ - var current = head, + let current = head, index = 0; while (current) { @@ -134,11 +134,11 @@ function LinkedList() { this.toString = function(){ - var current = head, + let current = head, string = ''; while (current) { - string += current.element + (current.next ? '\n' : ''); + string += current.element + (current.next ? ', ' : ''); current = current.next; } return string; diff --git a/chapter05/01-LinkedList2.js b/chapter05/01-LinkedList2.js new file mode 100644 index 00000000..98452857 --- /dev/null +++ b/chapter05/01-LinkedList2.js @@ -0,0 +1,170 @@ +let LinkedList2 = (function () { + + class Node { + constructor(element){ + this.element = element; + this.next = null; + } + } + + const length = new WeakMap(); + const head = new WeakMap(); + + class LinkedList2 { + + constructor () { + length.set(this, 0); + head.set(this, null); + } + + append(element) { + + let node = new Node(element), + current; + + if (this.getHead() === null) { //first node on list + head.set(this, node); + } else { + + current = this.getHead(); + + //loop the list until find last item + while (current.next) { + current = current.next; + } + + //get last item and assign next to added item to make the link + current.next = node; + } + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + } + + insert(position, element) { + + //check for out-of-bounds values + if (position >= 0 && position <= this.size()) { + + let node = new Node(element), + current = this.getHead(), + previous, + index = 0; + + if (position === 0) { //add on first position + + node.next = current; + head.set(this, node); + + } else { + while (index++ < position) { + previous = current; + current = current.next; + } + node.next = current; + previous.next = node; + } + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + + return true; + + } else { + return false; + } + } + + removeAt(position) { + + //check for out-of-bounds values + if (position > -1 && position < this.size()) { + + let current = this.getHead(), + previous, + index = 0; + + //removing first item + if (position === 0) { + head.set(this, current.next); + } else { + + while (index++ < position) { + + previous = current; + current = current.next; + } + + //link previous with current's next - skip it to remove + previous.next = current.next; + } + + let l = this.size(); + l--; + length.set(this, l); + + return current.element; + + } else { + return null; + } + } + + remove(element) { + + let index = this.indexOf(element); + return this.removeAt(index); + } + + indexOf(element) { + + let current = this.getHead(), + index = 0; + + while (current) { + if (element === current.element) { + return index; + } + index++; + current = current.next; + } + + return -1; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return length.get(this); + } + + getHead() { + return head.get(this); + } + + toString() { + + let current = this.getHead(), + string = ''; + + while (current) { + string += current.element + (current.next ? ', ' : ''); + current = current.next; + } + return string; + + } + + print() { + console.log(this.toString()); + } + } + + return LinkedList2; +})(); diff --git a/chapter05/02-UsingLinkedLists.html b/chapter05/02-UsingLinkedLists.html index da977b75..97210e70 100644 --- a/chapter05/02-UsingLinkedLists.html +++ b/chapter05/02-UsingLinkedLists.html @@ -5,7 +5,8 @@ - - + + + \ No newline at end of file diff --git a/chapter05/02-UsingLinkedLists.js b/chapter05/02-UsingLinkedLists.js index 9c92c483..bef9d86e 100644 --- a/chapter05/02-UsingLinkedLists.js +++ b/chapter05/02-UsingLinkedLists.js @@ -1,4 +1,4 @@ -var list = new LinkedList(); +let list = new LinkedList2(); list.append(15); list.print(); console.log(list.indexOf(15)); diff --git a/chapter05/03-Doubly-Linked-List.js b/chapter05/03-DoublyLinkedList.js similarity index 92% rename from chapter05/03-Doubly-Linked-List.js rename to chapter05/03-DoublyLinkedList.js index 1ca53298..6d4de9c5 100644 --- a/chapter05/03-Doubly-Linked-List.js +++ b/chapter05/03-DoublyLinkedList.js @@ -1,19 +1,19 @@ function DoublyLinkedList() { - var Node = function(element){ + let Node = function(element){ this.element = element; this.next = null; this.prev = null; //NEW }; - var length = 0; - var head = null; - var tail = null; //NEW + let length = 0; + let head = null; + let tail = null; //NEW this.append = function(element){ - var node = new Node(element), + let node = new Node(element), current; if (head === null){ //first node on list @@ -35,7 +35,7 @@ function DoublyLinkedList() { //check for out-of-bounds values if (position >= 0 && position <= length){ - var node = new Node(element), + let node = new Node(element), current = head, previous, index = 0; @@ -84,7 +84,7 @@ function DoublyLinkedList() { //check for out-of-bounds values if (position > -1 && position < length){ - var current = head, + let current = head, previous, index = 0; @@ -130,13 +130,13 @@ function DoublyLinkedList() { this.remove = function(element){ - var index = this.indexOf(element); + let index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ - var current = head, + let current = head, index = -1; //check first item @@ -175,7 +175,7 @@ function DoublyLinkedList() { this.toString = function(){ - var current = head, + let current = head, s = current ? current.element : ''; while(current && current.next){ @@ -188,7 +188,7 @@ function DoublyLinkedList() { this.inverseToString = function() { - var current = tail, + let current = tail, s = current ? current.element : ''; while(current && current.prev){ diff --git a/chapter05/03-DoublyLinkedList2.js b/chapter05/03-DoublyLinkedList2.js new file mode 100644 index 00000000..9fe7d87b --- /dev/null +++ b/chapter05/03-DoublyLinkedList2.js @@ -0,0 +1,242 @@ +let DoublyLinkedList2 = (function () { + + class Node { + constructor(element) { + this.element = element; + this.next = null; + this.prev = null; //NEW + } + } + + const length = new WeakMap(); + const head = new WeakMap(); + const tail = new WeakMap(); //NEW + + class DoublyLinkedList2 { + + constructor () { + length.set(this, 0); + head.set(this, null); + tail.set(this, null); + } + + append(element) { + + let node = new Node(element), + current, _tail; + + if (this.getHead() === null) { //first node on list + head.set(this, node); + tail.set(this, node); //NEW + } else { + //attach to the tail node //NEW + _tail = this.getTail(); + _tail.next = node; + node.prev = _tail; + tail.set(this, node); + } + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + } + + insert(position, element) { + + //check for out-of-bounds values + if (position >= 0 && position <= this.size()) { + + let node = new Node(element), + current = this.getHead(), + previous, + index = 0; + + if (position === 0) { //add on first position + + if (!this.getHead()) { //NEW + head.set(this, node); + tail.set(this, node); + } else { + node.next = current; + current.prev = node; //NEW {1} + head.set(this, node); + } + + } else if (position === this.size()) { //last item //NEW + + current = tail; // {2} + current.next = node; + node.prev = current; + tail.set(this, node); + + } else { + while (index++ < position) { //{3} + previous = current; + current = current.next; + } + node.next = current; + previous.next = node; + + current.prev = node; //NEW + node.prev = previous; //NEW + } + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + + return true; + + } else { + return false; + } + } + + removeAt(position) { + + //check for out-of-bounds values + if (position > -1 && position < this.size()) { + + let _head = this.getHead(), + _tail = this.getTail(), + current = _head, + previous, + index = 0; + + //removing first item + if (position === 0) { + + _head = current.next; // {1} + + //if there is only one item, then we update tail as well //NEW + if (this.size() === 1) { // {2} + _tail = null; + } else { + _head.prev = null; // {3} + } + + } else if (position === this.size() - 1) { //last item //NEW + + current = _tail; // {4} + _tail = current.prev; + _tail.next = null; + + } else { + + while (index++ < position) { // {5} + + previous = current; + current = current.next; + } + + //link previous with current's next - skip it to remove + previous.next = current.next; // {6} + current.next.prev = previous; //NEW + } + + head.set(this,_head); + tail.set(this,_tail); + + //update size of list + let l = this.size(); + l--; + length.set(this, l); + + return current.element; + + } else { + return null; + } + } + + remove(element) { + + let index = this.indexOf(element); + return this.removeAt(index); + } + + indexOf(element) { + + let current = this.getHead(), + index = -1; + + //check first item + if (element == current.element) { + return 0; + } + + index++; + + //check in the middle of the list + while (current.next) { + + if (element == current.element) { + return index; + } + + current = current.next; + index++; + } + + //check last item + if (element == current.element) { + return index; + } + + return -1; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return length.get(this); + } + + toString() { + + let current = this.getHead(), + s = current ? current.element : ''; + + while (current && current.next) { + current = current.next; + s += ', ' + current.element; + } + + return s; + } + + inverseToString() { + + let current = this.getTail(), + s = current ? current.element : ''; + + while (current && current.prev) { + current = current.prev; + s += ', ' + current.element; + } + + return s; + } + + print() { + console.log(this.toString()); + } + + printInverse() { + console.log(this.inverseToString()); + } + + getHead() { + return head.get(this); + } + + getTail() { + return tail.get(this); + } + } + return DoublyLinkedList2; +})(); \ No newline at end of file diff --git a/chapter05/04-UsingDoublyLinkedLists.html b/chapter05/04-UsingDoublyLinkedLists.html index d4b60521..58f959d5 100644 --- a/chapter05/04-UsingDoublyLinkedLists.html +++ b/chapter05/04-UsingDoublyLinkedLists.html @@ -5,7 +5,8 @@ - - + + + \ No newline at end of file diff --git a/chapter05/04-UsingDoublyLinkedLists.js b/chapter05/04-UsingDoublyLinkedLists.js index 00534d49..9ad4a17c 100644 --- a/chapter05/04-UsingDoublyLinkedLists.js +++ b/chapter05/04-UsingDoublyLinkedLists.js @@ -1,4 +1,4 @@ -var list = new DoublyLinkedList(); +let list = new DoublyLinkedList2(); list.append(15); list.print(); diff --git a/chapter05/05-CircularLinkedList.js b/chapter05/05-CircularLinkedList.js index 590c08f4..c3151148 100644 --- a/chapter05/05-CircularLinkedList.js +++ b/chapter05/05-CircularLinkedList.js @@ -1,17 +1,17 @@ function CircularLinkedList() { - var Node = function(element){ + let Node = function(element){ this.element = element; this.next = null; }; - var length = 0; - var head = null; + let length = 0; + let head = null; this.append = function(element){ - var node = new Node(element), + let node = new Node(element), current; if (head === null){ //first node on list @@ -40,22 +40,28 @@ function CircularLinkedList() { //check for out-of-bounds values if (position >= 0 && position <= length){ - var node = new Node(element), + let node = new Node(element), current = head, previous, index = 0; if (position === 0){ //add on first position + + if(!head){ // if no node in list + head = node; + node.next = head; + }else{ + node.next = current; - node.next = current; + //update last element + while(current.next !== head){ //last element will be head instead of NULL + current = current.next; + } - //update last element - while(current.next !== head){ //last element will be head instead of NULL - current = current.next; + head = node; + current.next = head; } - - head = node; - current.next = head; + } else { while (index++ < position){ @@ -64,10 +70,6 @@ function CircularLinkedList() { } node.next = current; previous.next = node; - - if (node.next === null){ //update in case last element - node.next = head; - } } length++; //update size of list @@ -84,7 +86,7 @@ function CircularLinkedList() { //check for out-of-bounds values if (position > -1 && position < length){ - var current = head, + let current = head, previous, index = 0; @@ -121,13 +123,13 @@ function CircularLinkedList() { this.remove = function(element){ - var index = this.indexOf(element); + let index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ - var current = head, + let current = head, index = -1; //check first item @@ -170,7 +172,7 @@ function CircularLinkedList() { this.toString = function(){ - var current = head, + let current = head, s = current.element; while(current.next !== head){ @@ -184,4 +186,5 @@ function CircularLinkedList() { this.print = function(){ console.log(this.toString()); }; -} \ No newline at end of file +} + diff --git a/chapter05/05-CircularLinkedList2.js b/chapter05/05-CircularLinkedList2.js new file mode 100644 index 00000000..6f7574ef --- /dev/null +++ b/chapter05/05-CircularLinkedList2.js @@ -0,0 +1,204 @@ +let CircularLinkedList2 = (function () { + + class Node { + constructor(element) { + this.element = element; + this.next = null; + } + } + + const length = new WeakMap(); + const head = new WeakMap(); + + class CircularLinkedList2 { + + constructor () { + length.set(this, 0); + head.set(this, null); + } + + append(element) { + + let node = new Node(element), + current; + + if (this.getHead() === null) { //first node on list + head.set(this, node); + } else { + + current = this.getHead(); + + //loop the list until find last item + while (current.next !== this.getHead()) { //last element will be head instead of NULL + current = current.next; + } + + //get last item and assign next to added item to make the link + current.next = node; + } + + //set node.next to head - to have circular list + node.next = this.getHead(); + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + } + + insert(position, element) { + + //check for out-of-bounds values + if (position >= 0 && position <= this.size()) { + + let node = new Node(element), + current = this.getHead(), + previous, + index = 0; + + if (position === 0) { //add on first position + + if(!this.getHead()) { // if no node in list + head.set(this, node); + node.next = this.getHead(); + } else { + node.next = current; + //update last element + while(current.next !== this.getHead()) { //last element will be head instead of NULL + current = current.next; + } + head.set(this, node); + current.next = this.getHead(); + } + + } else { + while (index++ < position) { + previous = current; + current = current.next; + } + node.next = current; + previous.next = node; + } + + //update size of list + let l = this.size(); + l++; + length.set(this, l); + + return true; + + } else { + return false; + } + } + + removeAt(position) { + + //check for out-of-bounds values + if (position > -1 && position < this.size()) { + + let current = this.getHead(), + previous, + index = 0; + + //removing first item + if (position === 0) { + + while (current.next !== this.getHead()) { //needs to update last element first + current = current.next; + } + + head.set(this, this.getHead().next); + current.next = this.getHead(); + + } else { //no need to update last element for circular list + + while (index++ < position) { + + previous = current; + current = current.next; + } + + //link previous with current's next - skip it to remove + previous.next = current.next; + } + + let l = this.size(); + l--; + length.set(this, l); + + return current.element; + + } else { + return null; + } + } + + remove(element) { + + let index = this.indexOf(element); + return this.removeAt(index); + } + + indexOf(element) { + + let current = this.getHead(), + index = -1; + + //check first item + if (element == current.element) { + return 0; + } + + index++; + + //check in the middle of the list + while (current.next !== this.getHead()) { + + if (element == current.element) { + return index; + } + + current = current.next; + index++; + } + + //check last item + if (element == current.element) { + return index; + } + + return -1; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return length.get(this); + } + + getHead() { + return head.get(this); + } + + toString() { + + let current = this.getHead(), + s = current.element; + + while (current.next !== this.getHead()) { + current = current.next; + s += ', ' + current.element; + } + + return s.toString(); + } + + print() { + console.log(this.toString()); + } + } + return CircularLinkedList2; +})(); diff --git a/chapter05/06-UsingCircularLinkedList.html b/chapter05/06-UsingCircularLinkedList.html index 5a2fbb5d..ab39ba27 100644 --- a/chapter05/06-UsingCircularLinkedList.html +++ b/chapter05/06-UsingCircularLinkedList.html @@ -5,7 +5,8 @@ - - + + + \ No newline at end of file diff --git a/chapter05/06-UsingCircularLinkedList.js b/chapter05/06-UsingCircularLinkedList.js index 33d9f8c9..a1feebbb 100644 --- a/chapter05/06-UsingCircularLinkedList.js +++ b/chapter05/06-UsingCircularLinkedList.js @@ -1,4 +1,4 @@ -var circularLinkedList = new CircularLinkedList(); +let circularLinkedList = new CircularLinkedList2(); circularLinkedList.append(15); circularLinkedList.print(); diff --git a/chapter06/01-Set.js b/chapter06/01-Set.js index fa2148b7..3fa90281 100644 --- a/chapter06/01-Set.js +++ b/chapter06/01-Set.js @@ -6,7 +6,7 @@ */ function Set() { - var items = {}; + let items = {}; this.add = function(value){ if (!this.has(value)){ @@ -16,7 +16,7 @@ function Set() { return false; }; - this.remove = function(value){ + this.delete = function(value){ if (this.has(value)){ delete items[value]; return true; @@ -48,8 +48,8 @@ function Set() { * @returns {number} */ this.sizeLegacy = function(){ - var count = 0; - for(var key in items) { + let count = 0; + for(let key in items) { if(items.hasOwnProperty(key)) ++count; } @@ -62,16 +62,16 @@ function Set() { * @returns {Array} */ this.values = function(){ - var values = []; - for (var i=0, keys=Object.keys(items); i otherSet.size()){ //{1} return false; } else { - var values = this.values(); - for (var i=0; i otherSet.size()){ + return false; + } else { + let values = this.values(); + for (let i=0; i - - + + + \ No newline at end of file diff --git a/chapter06/02-UsingSets.js b/chapter06/02-UsingSets.js index 62221b23..e74269ac 100644 --- a/chapter06/02-UsingSets.js +++ b/chapter06/02-UsingSets.js @@ -1,4 +1,4 @@ -var set = new Set(); +let set = new Set(); set.add(1); console.log(set.values()); //outputs [1] @@ -11,8 +11,8 @@ console.log(set.has(2)); //true console.log(set.size()); //2 console.log(set.sizeLegacy()); //3 -set.remove(1); +set.delete(1); console.log(set.values()); //outputs [2] -set.remove(2); +set.delete(2); console.log(set.values()); //outputs [] \ No newline at end of file diff --git a/chapter06/03-Operations.js b/chapter06/03-Operations.js index fc866c0c..dc7ece35 100644 --- a/chapter06/03-Operations.js +++ b/chapter06/03-Operations.js @@ -1,62 +1,62 @@ //--------- Union ---------- -var setA = new Set(); +let setA = new Set(); setA.add(1); setA.add(2); setA.add(3); -var setB = new Set(); +let setB = new Set(); setB.add(3); setB.add(4); setB.add(5); setB.add(6); -var unionAB = setA.union(setB); +let unionAB = setA.union(setB); console.log(unionAB.values()); //--------- Intersection ---------- -var setA = new Set(); +let setA = new Set(); setA.add(1); setA.add(2); setA.add(3); -var setB = new Set(); +let setB = new Set(); setB.add(2); setB.add(3); setB.add(4); -var intersectionAB = setA.intersection(setB); +let intersectionAB = setA.intersection(setB); console.log(intersectionAB.values()); //--------- Difference ---------- -var setA = new Set(); +let setA = new Set(); setA.add(1); setA.add(2); setA.add(3); -var setB = new Set(); +let setB = new Set(); setB.add(2); setB.add(3); setB.add(4); -var differenceAB = setA.difference(setB); +let differenceAB = setA.difference(setB); console.log(differenceAB.values()); //--------- Subset ---------- -var setA = new Set(); +let setA = new Set(); setA.add(1); setA.add(2); -var setB = new Set(); +let setB = new Set(); setB.add(1); setB.add(2); setB.add(3); -var setC = new Set(); +let setC = new Set(); setC.add(2); setC.add(3); setC.add(4); diff --git a/chapter06/04-UsingES6Set.html b/chapter06/04-UsingES6Set.html new file mode 100644 index 00000000..a08e635c --- /dev/null +++ b/chapter06/04-UsingES6Set.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter06/04-UsingES6Set.js b/chapter06/04-UsingES6Set.js new file mode 100644 index 00000000..a39e4100 --- /dev/null +++ b/chapter06/04-UsingES6Set.js @@ -0,0 +1,71 @@ +let set = new Set(); + +set.add(1); +console.log(set.values()); //outputs @Iterator +console.log(set.has(1)); //outputs true +console.log(set.size); //outputs 1 + +set.add(2); +console.log(set.values()); //outputs [1, 2] +console.log(set.has(2)); //true +console.log(set.size); //2 + +set.delete(1); +console.log(set.values()); //outputs [2] + +set.delete(2); +console.log(set.values()); //outputs [] + +let setA = new Set(); +setA.add(1); +setA.add(2); +setA.add(3); + +let setB = new Set(); +setB.add(2); +setB.add(3); +setB.add(4); + +//--------- Union ---------- +let unionAb = new Set(); +for (let x of setA) unionAb.add(x); +for (let x of setB) unionAb.add(x); +console.log(unionAb); + +//--------- Intersection ---------- +let intersection = function(setA, setB){ + let intersectionSet = new Set(); + + for (let x of setA){ + if (setB.has(x)){ + intersectionSet.add(x); + } + } + + return intersectionSet; +}; +let intersectionAB = intersection(setA, setB); +console.log(intersectionAB); + +//alternative - works on FF only +//intersectionAb = new Set([x for (x of setA) if (setB.has(x))]); +//console.log(intersectionAB); + +//--------- Difference ---------- +let difference = function(setA, setB){ + let differenceSet = new Set(); + + for (let x of setA){ + if (!setB.has(x)){ + differenceSet.add(x); + } + } + + return differenceSet; +}; +let differenceAB = difference(setA, setB); +console.log(differenceAB); + +//alternative - works on FF only +//differenceAB = new Set([x for (x of setA) if (!setB.has(x))]); +//console.log(differenceAB); diff --git a/chapter07/01-Dictionaries.js b/chapter07/01-Dictionaries.js index ea26cd05..a22ec419 100644 --- a/chapter07/01-Dictionaries.js +++ b/chapter07/01-Dictionaries.js @@ -6,7 +6,7 @@ function Dictionary(){ items[key] = value; //{1} }; - this.remove = function(key){ + this.delete = function(key){ if (this.has(key)){ delete items[key]; return true; diff --git a/chapter07/02-UsingDictionaries.js b/chapter07/02-UsingDictionaries.js index 3fc4db6f..dc0bf258 100644 --- a/chapter07/02-UsingDictionaries.js +++ b/chapter07/02-UsingDictionaries.js @@ -11,9 +11,9 @@ console.log(dictionary.keys()); //outputs ["Gandalf", "John", "Tyrion"] console.log(dictionary.values()); //outputs ["gandalf@email.com", "johnsnow@email.com", "tyrion@email.com"] console.log(dictionary.get('Tyrion')); //outputs tyrion@email.com -dictionary.remove('John'); +dictionary.delete('John'); console.log(dictionary.keys()); //outputs ["Gandalf", "Tyrion"] console.log(dictionary.values()); //outputs ["gandalf@email.com", "tyrion@email.com"] -console.log(dictionary.getItems()); //Object {Gandalf: "gandalf@email.com", Tyrion: "tyrion@email.com"} \ No newline at end of file +console.log(dictionary.getItems()); //Object {Gandalf: "gandalf@email.com", Tyrion: "tyrion@email.com"} diff --git a/chapter07/06-UsingHashCollisionSeparateChaining.html b/chapter07/06-UsingHashCollisionSeparateChaining.html index e1741527..d671e133 100644 --- a/chapter07/06-UsingHashCollisionSeparateChaining.html +++ b/chapter07/06-UsingHashCollisionSeparateChaining.html @@ -5,7 +5,7 @@ - + diff --git a/chapter07/07-HashCollisionLinearProbing.js b/chapter07/07-HashCollisionLinearProbing.js index 74fdbac5..4b1172be 100644 --- a/chapter07/07-HashCollisionLinearProbing.js +++ b/chapter07/07-HashCollisionLinearProbing.js @@ -46,13 +46,22 @@ function HashLinearProbing(){ return table[position].value; } else { var index = ++position; - while (table[index] === undefined || table[index].key !== key){ + while (table[index] !== undefined && (table[index] && table[index].key !== key)){ index++; } - if (table[index].key === key) { + if (table[index] && table[index].key === key) { return table[index].value; } } + } else { //search for possible deleted value + var index = ++position; + while (table[index] == undefined || index == table.length || + (table[index] !== undefined && table[index] && table[index].key !== key)){ + index++; + } + if (table[index] && table[index].key === key) { + return table[index].value; + } } return undefined; }; @@ -82,4 +91,4 @@ function HashLinearProbing(){ } } }; -} \ No newline at end of file +} diff --git a/chapter07/08-UsingHashCollisionLinearProbing.js b/chapter07/08-UsingHashCollisionLinearProbing.js index 902384ee..36a33e61 100644 --- a/chapter07/08-UsingHashCollisionLinearProbing.js +++ b/chapter07/08-UsingHashCollisionLinearProbing.js @@ -26,4 +26,12 @@ console.log('**** Remove **** '); hashLinearProbing.remove('Gandalf'); console.log(hashLinearProbing.get('Gandalf')); +hashLinearProbing.print(); + +console.log('**** Remove Test 2 **** '); +console.log('Removing Jonathan', hashLinearProbing.remove('Jonathan')); +console.log('**** Print **** '); +hashLinearProbing.print(); +console.log('Get Jamie', hashLinearProbing.get('Jamie')); +console.log('**** Print **** '); hashLinearProbing.print(); \ No newline at end of file diff --git a/chapter07/09-ES6Map.html b/chapter07/09-ES6Map.html new file mode 100644 index 00000000..e755aac7 --- /dev/null +++ b/chapter07/09-ES6Map.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter07/09-ES6Map.js b/chapter07/09-ES6Map.js new file mode 100644 index 00000000..5e0c9dae --- /dev/null +++ b/chapter07/09-ES6Map.js @@ -0,0 +1,17 @@ +var map = new Map(); + +map.set('Gandalf', 'gandalf@email.com'); +map.set('John', 'johnsnow@email.com'); +map.set('Tyrion', 'tyrion@email.com'); + +console.log(map.has('Gandalf')); //outputs true +console.log(map.size); //outputs 3 + +console.log(map.keys()); //outputs ["Gandalf", "John", "Tyrion"] +console.log(map.values()); //outputs ["gandalf@email.com", "johnsnow@email.com", "tyrion@email.com"] +console.log(map.get('Tyrion')); //outputs tyrion@email.com + +map.delete('John'); + +console.log(map.keys()); //outputs ["Gandalf", "Tyrion"] +console.log(map.values()); //outputs ["gandalf@email.com", "tyrion@email.com"] \ No newline at end of file diff --git a/chapter07/10-ES6WeakMap.html b/chapter07/10-ES6WeakMap.html new file mode 100644 index 00000000..25b28e2d --- /dev/null +++ b/chapter07/10-ES6WeakMap.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter07/10-ES6WeakMap.js b/chapter07/10-ES6WeakMap.js new file mode 100644 index 00000000..8efa16b8 --- /dev/null +++ b/chapter07/10-ES6WeakMap.js @@ -0,0 +1,18 @@ +var map = new WeakMap(); + +var ob1 = {name:'Gandalf'}, + ob2 = {name:'John'}, + ob3 = {name:'Tyrion'}; + +map.set(ob1, 'gandalf@email.com'); +map.set(ob2, 'johnsnow@email.com'); +map.set(ob3, 'tyrion@email.com'); + +console.log(map.has(ob1)); //outputs true +console.log(map.has(ob2)); //outputs true +console.log(map.has(ob3)); //outputs true + +console.log(map.get(ob3)); //outputs tyrion@email.com + +map.delete(ob2); +console.log(map.has(ob2)); //outputs false diff --git a/chapter07/11-ES6WeakSet.html b/chapter07/11-ES6WeakSet.html new file mode 100644 index 00000000..68710e76 --- /dev/null +++ b/chapter07/11-ES6WeakSet.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter07/11-ES6WeakSet.js b/chapter07/11-ES6WeakSet.js new file mode 100644 index 00000000..e54a40de --- /dev/null +++ b/chapter07/11-ES6WeakSet.js @@ -0,0 +1,16 @@ +var set = new WeakSet(); + +var ob1 = {name:'Gandalf'}, + ob2 = {name:'John'}, + ob3 = {name:'Tyrion'}; + +set.add(ob1); +set.add(ob2); +set.add(ob3); + +console.log(set.has(ob1)); //outputs true +console.log(set.has(ob2)); //outputs true +console.log(set.has(ob3)); //outputs true + +set.delete(ob2); +console.log(set.has(ob2)); //outputs false diff --git a/chapter08/02-UsingBinarySearchTree.html b/chapter08/02-UsingBinarySearchTree.html index ed25a2c4..dd40cf48 100644 --- a/chapter08/02-UsingBinarySearchTree.html +++ b/chapter08/02-UsingBinarySearchTree.html @@ -5,7 +5,7 @@ - - + + \ No newline at end of file diff --git a/chapter08/02-UsingBinarySearchTree.js b/chapter08/02-UsingBinarySearchTree.js index 3caef17c..eb139837 100644 --- a/chapter08/02-UsingBinarySearchTree.js +++ b/chapter08/02-UsingBinarySearchTree.js @@ -49,4 +49,4 @@ tree.remove(15); tree.inOrderTraverse(printNode); console.log('********* raw data structure ***********'); -console.log(tree.getRoot()); \ No newline at end of file +console.log(tree.getRoot()); diff --git a/chapter08/03-AVLTree.js b/chapter08/03-AVLTree.js index e69de29b..2eed4f3e 100644 --- a/chapter08/03-AVLTree.js +++ b/chapter08/03-AVLTree.js @@ -0,0 +1,149 @@ +function AVLTree() { + + var Node = function(key){ + this.key = key; + this.left = null; + this.right = null; + }; + + var root = null; + + this.getRoot = function(){ + return root; + }; + + var heightNode = function(node) { + if (node === null) { + return -1; + } else { + return Math.max(heightNode(node.left), heightNode(node.right)) + 1; + } + }; + + var rotationLL = function(node) { + var tmp = node.left; + node.left = tmp.right; + tmp.right = node; + + return tmp; + }; + + var rotationRR = function(node) { + var tmp = node.right; + node.right = tmp.left; + tmp.left = node; + + return tmp; + }; + + var rotationLR = function(node) { + node.left = rotationRR(node.left); + return rotationLL(node); + }; + + var rotationRL = function(node) { + node.right = rotationLL(node.right); + return rotationRR(node); + }; + + var insertNode = function(node, element) { + + if (node === null) { + node = new Node(element); + + } else if (element < node.key) { + + node.left = insertNode(node.left, element); + + if (node.left !== null) { + + if ((heightNode(node.left) - heightNode(node.right)) > 1){ + if (element < node.left.key){ + node = rotationLL(node); + } else { + node = rotationLR(node); + } + } + } + } else if (element > node.key) { + + node.right = insertNode(node.right, element); + + if (node.right !== null) { + + if ((heightNode(node.right) - heightNode(node.left)) > 1){ + + if (element > node.right.key){ + node = rotationRR(node); + } else { + node = rotationRL(node); + } + } + } + } + + return node; + }; + + this.insert = function(element) { + root = insertNode(root, element); + }; + + var parentNode; + var nodeToBeDeleted; + + var removeNode = function(node, element) { + if (node === null) { + return null; + } + parentNode = node; + + if (element < node.key) { + node.left = removeNode(node.left, element); + } else { + nodeToBeDeleted = node; + node.right = removeNode(node.right, element); + } + + if (node === parentNode) { //remove node + if (nodeToBeDeleted !== null && element === nodeToBeDeleted.key) { + if (nodeToBeDeleted === parentNode) { + node = node.left; + } else { + var tmp = nodeToBeDeleted.key; + nodeToBeDeleted.key = parentNode.key; + parentNode.key = tmp; + node = node.right; + } + } + } else { //do balancing + + if (node.left === undefined) node.left = null; + if (node.right === undefined) node.right = null; + + if ((heightNode(node.left) - heightNode(node.right)) === 2) { + if (element < node.left.key) { + node = rotationLR(node); + } else { + node = rotationLL(node); + } + } + + if ((heightNode(node.right) - heightNode(node.left)) === 2) { + if (element > node.right.key) { + node = rotationRL(node); + } else { + node = rotationRR(node); + } + } + } + + return node; + }; + + this.remove = function(element) { + parentNode = null; + nodeToBeDeleted = null; + root = removeNode(root, element); + }; +} \ No newline at end of file diff --git a/chapter08/04-UsingAVLTree.html b/chapter08/04-UsingAVLTree.html index f7ce18b0..fda15f71 100644 --- a/chapter08/04-UsingAVLTree.html +++ b/chapter08/04-UsingAVLTree.html @@ -5,7 +5,7 @@ - - + + \ No newline at end of file diff --git a/chapter08/04-UsingAVLTree.js b/chapter08/04-UsingAVLTree.js index e69de29b..fd77d395 100644 --- a/chapter08/04-UsingAVLTree.js +++ b/chapter08/04-UsingAVLTree.js @@ -0,0 +1,62 @@ +var avlTree = new AVLTree(); + +avlTree.insert(1); +avlTree.insert(2); +avlTree.insert(3); +avlTree.insert(4); +avlTree.insert(5); +avlTree.insert(6); +avlTree.insert(7); +avlTree.insert(14); +avlTree.insert(15); +avlTree.insert(13); +avlTree.insert(12); +avlTree.insert(11); + +//RR rotation +/*avlTree.insert(50); +avlTree.insert(30); +avlTree.insert(70); +avlTree.insert(60); +avlTree.insert(80); +avlTree.insert(90);*/ + +//LL rotation +/*avlTree.insert(50); +avlTree.insert(30); +avlTree.insert(70); +avlTree.insert(10); +avlTree.insert(40); +avlTree.insert(5);*/ + +//LR rotation +/*avlTree.insert(50); +avlTree.insert(30); +avlTree.insert(70); +avlTree.insert(40); +avlTree.insert(10); +avlTree.insert(35);*/ + +//RL rotation +/*avlTree.insert(70); +avlTree.insert(50); +avlTree.insert(80); +avlTree.insert(72); +avlTree.insert(90); +avlTree.insert(75);*/ + +console.log('********* raw data structure ***********'); +console.log(avlTree.getRoot()); + +/*avlTree.remove(12); +avlTree.remove(15); +avlTree.remove(11); +avlTree.remove(14); +avlTree.remove(13); +avlTree.remove(7); +avlTree.remove(6); +avlTree.remove(2); +avlTree.remove(4); + +console.log(avlTree.getRoot());*/ + diff --git a/chapter08/05-RedBlackTree.js b/chapter08/05-RedBlackTree.js new file mode 100644 index 00000000..7a985d2e --- /dev/null +++ b/chapter08/05-RedBlackTree.js @@ -0,0 +1,101 @@ +function RedBlackTree() { + + var Colors = { + RED: 0, + BLACK: 1 + }; + + var Node = function (key, color) { + this.key = key; + this.left = null; + this.right = null; + this.color = color; + + this.flipColor = function(){ + if (this.color === Colors.RED) { + this.color = Colors.BLACK; + } else { + this.color = Colors.RED; + } + }; + }; + + var root = null; + + this.getRoot = function () { + return root; + }; + + var isRed = function(node){ + if (!node){ + return false; + } + return node.color === Colors.RED; + }; + + var flipColors = function(node){ + node.left.flipColor(); + node.right.flipColor(); + }; + + var rotateLeft = function(node){ + var temp = node.right; + if (temp !== null) { + node.right = temp.left; + temp.left = node; + temp.color = node.color; + node.color = Colors.RED; + } + return temp; + }; + + var rotateRight = function (node) { + var temp = node.left; + if (temp !== null) { + node.left = temp.right; + temp.right = node; + temp.color = node.color; + node.color = Colors.RED; + } + return temp; + }; + + var insertNode = function(node, element) { + + if (node === null) { + return new Node(element, Colors.RED); + } + + var newRoot = node; + + if (element < node.key) { + + node.left = insertNode(node.left, element); + + } else if (element > node.key) { + + node.right = insertNode(node.right, element); + + } else { + node.key = element; + } + + if (isRed(node.right) && !isRed(node.left)) { + newRoot = rotateLeft(node); + } + + if (isRed(node.left) && isRed(node.left.left)) { + newRoot = rotateRight(node); + } + if (isRed(node.left) && isRed(node.right)) { + flipColors(node); + } + + return newRoot; + }; + + this.insert = function(element) { + root = insertNode(root, element); + root.color = Colors.BLACK; + }; +} diff --git a/chapter08/06-UsingRedBlackTree.html b/chapter08/06-UsingRedBlackTree.html new file mode 100644 index 00000000..f0fdfcc9 --- /dev/null +++ b/chapter08/06-UsingRedBlackTree.html @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/chapter08/06-UsingRedBlackTree.js b/chapter08/06-UsingRedBlackTree.js new file mode 100644 index 00000000..31136f99 --- /dev/null +++ b/chapter08/06-UsingRedBlackTree.js @@ -0,0 +1,17 @@ +var rbTree = new RedBlackTree(); + +rbTree.insert(1); +rbTree.insert(2); +rbTree.insert(3); +rbTree.insert(4); +rbTree.insert(5); +rbTree.insert(6); +rbTree.insert(7); +rbTree.insert(14); +rbTree.insert(15); +rbTree.insert(13); +rbTree.insert(12); +rbTree.insert(11); + +console.log('********* raw data structure ***********'); +console.log(rbTree.getRoot()); \ No newline at end of file diff --git a/chapter09/03-ShortestPath.js b/chapter09/03-ShortestPath.js new file mode 100644 index 00000000..cdef7fbb --- /dev/null +++ b/chapter09/03-ShortestPath.js @@ -0,0 +1,76 @@ +function ShortestPath(graph) { + + this.graph = graph; + + var INF = Number.MAX_SAFE_INTEGER; + + var minDistance = function(dist, visited){ + + var min = INF, + minIndex = -1; + + for (var v = 0; v < dist.length; v++){ + if (visited[v] == false && dist[v] <= min){ + min = dist[v]; + minIndex = v; + } + } + + return minIndex; + }; + + this.dijkstra = function(src){ + + var dist = [], + visited = [], + length = this.graph.length; + + for (var i = 0; i < length; i++) { + dist[i] = INF; + visited[i] = false; + } + + dist[src] = 0; + + for (var i = 0; i < length-1; i++){ + + var u = minDistance(dist, visited); + + visited[u] = true; + + for (var v = 0; v < length; v++){ + if (!visited[v] && this.graph[u][v]!=0 && dist[u] != INF && dist[u]+this.graph[u][v] < dist[v]){ + dist[v] = dist[u] + this.graph[u][v]; + } + } + } + + return dist; + }; + + this.floydWarshall = function(){ + + var dist = [], + length = this.graph.length, + i, j, k; + + for (i = 0; i < length; i++){ + dist[i] = []; + for (j = 0; j < length; j++){ + dist[i][j] = this.graph[i][j]; + } + } + + for (k = 0; k < length; k++){ + for (i = 0; i < length; i++){ + for (j = 0; j < length; j++){ + if (dist[i][k] + dist[k][j] < dist[i][j]){ + dist[i][j] = dist[i][k] + dist[k][j]; + } + } + } + } + + return dist; + } +} \ No newline at end of file diff --git a/chapter09/04-UsingShortestPathAlgorithms.html b/chapter09/04-UsingShortestPathAlgorithms.html new file mode 100644 index 00000000..422b9fc4 --- /dev/null +++ b/chapter09/04-UsingShortestPathAlgorithms.html @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/chapter09/04-UsingShortestPathAlgorithms.js b/chapter09/04-UsingShortestPathAlgorithms.js new file mode 100644 index 00000000..5bc5ac79 --- /dev/null +++ b/chapter09/04-UsingShortestPathAlgorithms.js @@ -0,0 +1,45 @@ +//adjacent matrix +var i; + +var graph = [[0, 2, 4, 0, 0, 0], + [0, 0, 2, 4, 2, 0], + [0, 0, 0, 0, 3, 0], + [0, 0, 0, 0, 0, 2], + [0, 0, 0, 3, 0, 2], + [0, 0, 0, 0, 0, 0]]; + +var shortestPath = new ShortestPath(graph); + +console.log("********* Dijkstra's Algorithm - Shortest Path ***********"); + +var dist = shortestPath.dijkstra(0); + +for (i = 0; i < dist.length; i++){ + console.log(i + '\t\t' + dist[i]); +} + +console.log("********* Floyd-Warshall Algorithm - All-Pairs Shortest Path ***********"); + +var INF = Number.MAX_SAFE_INTEGER; +graph = [[0, 2, 4, INF, INF, INF], + [INF, 0, 2, 4, 2, INF], + [INF, INF, 0, INF, 3, INF], + [INF, INF, INF, 0, INF, 2], + [INF, INF, INF, 3, 0, 2], + [INF, INF, INF, INF, INF, 0]]; + +shortestPath = new ShortestPath(graph); + +dist = shortestPath.floydWarshall(); + +var s = ''; +for (i=0; i + + + + + + + + + + \ No newline at end of file diff --git a/chapter09/06-UsingMinimumSpanningTree.js b/chapter09/06-UsingMinimumSpanningTree.js new file mode 100644 index 00000000..286f1dff --- /dev/null +++ b/chapter09/06-UsingMinimumSpanningTree.js @@ -0,0 +1,29 @@ +var i; + +var graph = [[0, 2, 4, 0, 0, 0], + [2, 0, 2, 4, 2, 0], + [4, 2, 0, 0, 3, 0], + [0, 4, 0, 0, 3, 2], + [0, 2, 3, 3, 0, 2], + [0, 0, 0, 2, 2, 0]]; + +var mst = new MinimumSpanningTree(graph); + + +console.log("********* Prim's Algorithm - Minimum Spanning Tree ***********"); + +var parent = mst.prim(); + +console.log('Edge Weight'); +for (i = 1; i < graph.length; i++){ + console.log(parent[i] + ' - ' + i + ' ' + graph[i][parent[i]]); +} + +console.log("********* Kruskal Algorithm - Minimum Spanning Tree ***********"); + +parent = mst.kruskal(); + +console.log('Edge Weight'); +for (i = 1; i < graph.length; i++){ + console.log(parent[i] + ' - ' + i + ' ' + graph[i][parent[i]]); +} \ No newline at end of file diff --git a/chapter10/01-SortingSearchingAlgorithms.js b/chapter10/01-SortingSearchingAlgorithms.js index b4081024..916e7403 100755 --- a/chapter10/01-SortingSearchingAlgorithms.js +++ b/chapter10/01-SortingSearchingAlgorithms.js @@ -6,16 +6,22 @@ function ArrayList(){ array.push(item); }; - var swap = function(index1, index2){ + var swap = function(array, index1, index2){ var aux = array[index1]; array[index1] = array[index2]; array[index2] = aux; + //ES2015 swap - Firefox only, for other browser, uncomment code above and coment line below + //[array[index1], array[index2]] = [array[index2], array[index1]]; }; this.toString= function(){ return array.join(); }; + this.array= function(){ + return array; + }; + this.bubbleSort = function(){ var length = array.length; @@ -25,7 +31,7 @@ function ArrayList(){ console.log('compare ' + array[j] + ' with ' + array[j+1]); if (array[j] > array[j+1]){ console.log('swap ' + array[j] + ' with ' + array[j+1]); - swap(j, j+1); + swap(array, j, j+1); } } } @@ -84,6 +90,20 @@ function ArrayList(){ } }; + var insertionSort_ = function(array){ + var length = array.length, + j, temp; + for (var i=1; i0 && array[j-1] > temp){ + array[j] = array[j-1]; + j--; + } + array[j] = temp; + } + }; + this.mergeSort = function(){ array = mergeSortRec(array); }; @@ -156,7 +176,7 @@ function ArrayList(){ if (i <= j) { console.log('swap ' + array[i] + ' with ' + array[j]); - swapQuickStort(array, i, j); + swap(array, i, j); i++; j--; } @@ -165,12 +185,6 @@ function ArrayList(){ return i; }; - var swapQuickStort = function(array, index1, index2){ - var aux = array[index1]; - array[index1] = array[index2]; - array[index2] = aux; - }; - var quick = function(array, left, right){ var index; @@ -190,6 +204,158 @@ function ArrayList(){ return array; }; + this.heapSort = function(){ + var heapSize = array.length; + + buildHeap(array); + + while (heapSize > 1) { + heapSize--; + console.log('swap (' + + array[0] + ',' + array[heapSize] + ')'); + swap(array, 0, heapSize); + console.log('heapify ' + array.join()); + heapify(array, heapSize, 0); + } + }; + + var buildHeap = function(array){ + console.log('building heap'); + var heapSize = array.length; + for (var i = Math.floor(array.length / 2); i >= 0; i--) { + heapify(array, heapSize, i); + } + console.log('heap created: ' + array.join()); + }; + + var heapify = function(array, heapSize, i){ + var left = i * 2 + 1, + right = i * 2 + 2, + largest = i; + + if (left < heapSize && array[left] > array[largest]) { + largest = left; + } + + if (right < heapSize && array[right] > array[largest]) { + largest = right; + } + + console.log('Heapify Index = '+ i + ' and Heap Size = ' + heapSize); + + if (largest !== i) { + console.log('swap index ' + i + ' with ' + largest + ' (' + + array[i] + ',' + array[largest] + ')'); + swap(array, i, largest); + console.log('heapify ' + array.join()); + heapify(array, heapSize, largest); + } + }; + + this.countingSort = function(){ + + var i, + maxValue = this.findMaxValue(), + sortedIndex = 0, + counts = new Array(maxValue + 1); + + for (i = 0; i < array.length; i++) { + if (!counts[array[i]]) { + counts[array[i]] = 0; + } + counts[array[i]]++; + } + + console.log('Frequencies: ' + counts.join()); + + for (i = 0; i < counts.length; i++) { + while (counts[i] > 0) { + array[sortedIndex++] = i; + counts[i]--; + } + } + }; + + this.bucketSort = function(bucketSize){ + + var i, + minValue = this.findMinValue(), + maxValue = this.findMaxValue(), + BUCKET_SIZE = 5; + + console.log('minValue ' + minValue); + console.log('maxValue ' + maxValue); + + bucketSize = bucketSize || BUCKET_SIZE; + var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; + var buckets = new Array(bucketCount); + console.log('bucketSize = ' + bucketCount); + for (i = 0; i < buckets.length; i++) { + buckets[i] = []; + } + + for (i = 0; i < array.length; i++) { + buckets[Math.floor((array[i] - minValue) / bucketSize)].push(array[i]); + console.log('pushing item ' + array[i] + ' to bucket index ' + Math.floor((array[i] - minValue) / bucketSize)); + } + + array = []; + for (i = 0; i < buckets.length; i++) { + insertionSort_(buckets[i]); + + console.log('bucket sorted ' + i + ': ' + buckets[i].join()); + + for (var j = 0; j < buckets[i].length; j++) { + array.push(buckets[i][j]); + } + } + }; + + this.radixSort = function(radixBase){ + + var i, + minValue = this.findMinValue(), + maxValue = this.findMaxValue(), + radixBase = radixBase || 10; + + // Perform counting sort for each significant digit), starting at 1 + var significantDigit = 1; + while (((maxValue - minValue) / significantDigit) >= 1) { + console.log('radix sort for digit ' + significantDigit); + array = countingSortForRadix(array, radixBase, significantDigit, minValue); + console.log(array.join()); + significantDigit *= radixBase; + } + }; + + var countingSortForRadix = function(array, radixBase, significantDigit, minValue){ + var i, countsIndex, + counts = new Array(radixBase), + aux = new Array(radixBase); + + for (i = 0; i < radixBase; i++) { + counts[i] = 0; + } + + for (i = 0; i < array.length; i++) { + countsIndex = Math.floor(((array[i] - minValue) / significantDigit) % radixBase); + counts[countsIndex]++; + } + + for (i = 1; i < radixBase; i++) { + counts[i] += counts[i - 1]; + } + + for (i = array.length - 1; i >= 0; i--) { + countsIndex = Math.floor(((array[i] - minValue) / significantDigit) % radixBase); + aux[--counts[countsIndex]] = array[i]; + } + + for (i = 0; i < array.length; i++) { + array[i] = aux[i]; + } + + return array; + }; + this.sequentialSearch = function(item){ for (var i=0; i + + + + + + + + + \ No newline at end of file diff --git a/chapter11/05-KnapsackProblemDP.js b/chapter11/05-KnapsackProblemDP.js new file mode 100644 index 00000000..fb6adbe7 --- /dev/null +++ b/chapter11/05-KnapsackProblemDP.js @@ -0,0 +1,53 @@ +function knapSack(capacity, weights, values, n) { + + var i, w, a, b, kS = []; + + for (i = 0; i <= n; i++) { + kS[i] = []; + } + + for (i = 0; i <= n; i++){ + for (w = 0; w <= capacity; w++){ + if (i == 0 || w == 0){ + kS[i][w] = 0; + + } else if (weights[i-1] <= w){ + a = values[i-1] + kS[i-1][w-weights[i-1]]; + b = kS[i-1][w]; + kS[i][w] = (a > b) ? a : b; //max(a,b) + console.log(a + ' can be part of the solution'); + } else{ + kS[i][w] = kS[i-1][w]; + } + } + console.log(kS[i].join()); + } + + //extra algorithm to find the items that are part of the solution + findValues(n, capacity, kS, values, weights); + + return kS[n][capacity]; +} + +function findValues(n, capacity, kS, weights, values){ + var i=n, k=capacity; + + console.log('Items that are part of the solution:'); + + while (i>0 && k>0){ + if (kS[i][k] !== kS[i-1][k]){ + console.log('item '+i+' can be part of solution w,v: ' + weights[i-1] + ',' + values[i-1]); + i--; + k = k - kS[i][k]; + } else { + i--; + } + } +} + +var values = [3,4,5], + weights = [2,3,4], + capacity = 5, + n = values.length; + +console.log('Total value that can be carried: ' + knapSack(capacity, weights, values, n)); \ No newline at end of file diff --git a/chapter11/06-KnapSackProblemRecursive.html b/chapter11/06-KnapSackProblemRecursive.html new file mode 100644 index 00000000..cc000756 --- /dev/null +++ b/chapter11/06-KnapSackProblemRecursive.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter11/06-KnapSackProblemRecursive.js b/chapter11/06-KnapSackProblemRecursive.js new file mode 100644 index 00000000..583092e1 --- /dev/null +++ b/chapter11/06-KnapSackProblemRecursive.js @@ -0,0 +1,22 @@ +function knapSack(capacity, weights, values, n) { + + if (n == 0 || capacity == 0){ + return 0; + } + + if (weights[n-1] > capacity){ + return knapSack(capacity, weights, values, n-1); + + } else { + var a = values[n-1] + knapSack(capacity-weights[n-1], weights, values, n-1), + b = knapSack(capacity, weights, values, n-1); + return (a > b) ? a : b; + } +} + +var values = [3,4,5], + weights = [2,3,4], + capacity = 5, + n = values.length; + +console.log(knapSack(capacity, weights, values, n)); \ No newline at end of file diff --git a/chapter11/07-KnapSackProblemGreedy.html b/chapter11/07-KnapSackProblemGreedy.html new file mode 100644 index 00000000..227d7b4b --- /dev/null +++ b/chapter11/07-KnapSackProblemGreedy.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter11/07-KnapSackProblemGreedy.js b/chapter11/07-KnapSackProblemGreedy.js new file mode 100644 index 00000000..4c12e1a6 --- /dev/null +++ b/chapter11/07-KnapSackProblemGreedy.js @@ -0,0 +1,28 @@ +function knapSack(capacity, values, weights) { + var n = values.length, + load = 0, + i = 0, + val = 0; + + for (i=0; i + + + + + + + + + \ No newline at end of file diff --git a/chapter11/08-LongestCommonSubsequenceDP.js b/chapter11/08-LongestCommonSubsequenceDP.js new file mode 100644 index 00000000..b5eaf3f1 --- /dev/null +++ b/chapter11/08-LongestCommonSubsequenceDP.js @@ -0,0 +1,105 @@ +function lcs(wordX, wordY) { + + var m = wordX.length, + n = wordY.length, + l = [], + i, j, a, b; + + for (i = 0; i <= m; ++i) { + l[i] = []; + for (j = 0; j <= n; ++j) { + l[i][j] = 0; + } + } + + for (i=0; i<=m; i++) { + for (j=0; j<=n; j++) { + if (i == 0 || j == 0){ + l[i][j] = 0; + + } else if (wordX[i-1] == wordY[j-1]) { + l[i][j] = l[i-1][j-1] + 1; + + } else { + a = l[i-1][j]; + b = l[i][j-1]; + l[i][j] = (a > b) ? a : b; //max(a,b) + } + } + console.log(l[i].join()); + } + + return l[m][n]; +} + +//complete algorithm that prints the LCS as well + +function lcs2(wordX, wordY) { + + var m = wordX.length, + n = wordY.length, + l = [], + solution = [], + i, j, a, b; + + for (i = 0; i <= m; ++i) { + l[i] = []; + solution[i] = []; + for (j = 0; j <= n; ++j) { + l[i][j] = 0; + solution[i][j] = '0'; + } + } + + for (i=0; i<=m; i++) { + for (j=0; j<=n; j++) { + if (i == 0 || j == 0){ + l[i][j] = 0; + + } else if (wordX[i-1] == wordY[j-1]) { + l[i][j] = l[i-1][j-1] + 1; + solution[i][j] = 'diagonal'; + + } else { + a = l[i-1][j]; + b = l[i][j-1]; + l[i][j] = (a > b) ? a : b; //max(a,b) + + solution[i][j] = (l[i][j] == l[i - 1][j]) ? 'top' : 'left'; + } + } + console.log(l[i].join()); + console.log(solution[i].join()); + } + + printSolution(solution, l, wordX, wordY, m, n); + + return l[m][n]; +} + +function printSolution(solution, l, wordX, wordY, m, n){ + + var a = m, b = n, i, j, + x = solution[a][b], + answer = ''; + + while (x !== '0') { + if (solution[a][b] === 'diagonal') { + answer = wordX[a - 1] + answer; + a--; + b--; + } else if (solution[a][b] === 'left') { + b--; + } else if (solution[a][b] === 'top') { + a--; + } + x = solution[a][b]; + } + + console.log('lcs: '+ answer); +} + +var wordX = 'acbaed', + wordY = 'abcadf'; + +console.log(lcs2(wordX, wordY)); \ No newline at end of file diff --git a/chapter11/09-LongestCommonSubsequenceRecursive.html b/chapter11/09-LongestCommonSubsequenceRecursive.html new file mode 100644 index 00000000..59573751 --- /dev/null +++ b/chapter11/09-LongestCommonSubsequenceRecursive.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter11/09-LongestCommonSubsequenceRecursive.js b/chapter11/09-LongestCommonSubsequenceRecursive.js new file mode 100644 index 00000000..1c96fab1 --- /dev/null +++ b/chapter11/09-LongestCommonSubsequenceRecursive.js @@ -0,0 +1,19 @@ +function lcs(wordwordX, wordwordY, m, n) { + + if (m == 0 || n == 0){ + return 0; + } + + if (wordwordX[m-1] == wordY[n-1]){ + return 1 + lcs(wordX, wordY, m-1, n-1); + } else { + var a = lcs(wordX, wordY, m, n-1), + b = lcs(wordX, wordY, m-1, n); + return (a > b) ? a : b; + } +} + +var wordX = 'acbaed', + wordY = 'abcadf'; + +console.log(lcs(wordX, wordY, wordX.length, wordY.length)); \ No newline at end of file diff --git a/chapter11/10-MatrixChainMultiplicationDP.html b/chapter11/10-MatrixChainMultiplicationDP.html new file mode 100644 index 00000000..2108a100 --- /dev/null +++ b/chapter11/10-MatrixChainMultiplicationDP.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/chapter11/10-MatrixChainMultiplicationDP.js b/chapter11/10-MatrixChainMultiplicationDP.js new file mode 100644 index 00000000..e335b3cc --- /dev/null +++ b/chapter11/10-MatrixChainMultiplicationDP.js @@ -0,0 +1,56 @@ +function matrixChainOrder(p, n) { + + var i, j, k, l, q, + m = [], s=[]; + + for (i = 1; i <= n; i++){ + m[i] = []; + m[i][i] = 0; + + } + + for (i = 0; i <= n; i++){ //to help printing the optimal solution + s[i] = []; //auxiliary + for (j=0; j<=n; j++){ + s[i][j] = 0; + } + } + + for (l=2; l + + + + + + + + + \ No newline at end of file diff --git a/chapter11/11-MatrixChainMultiplicationRecursive.js b/chapter11/11-MatrixChainMultiplicationRecursive.js new file mode 100644 index 00000000..0b327524 --- /dev/null +++ b/chapter11/11-MatrixChainMultiplicationRecursive.js @@ -0,0 +1,26 @@ +function matrixChainOrder(p, i, j){ + + if(i == j) { + return 0; + } + + var k, count, + min = Number.MAX_SAFE_INTEGER; + + for (k = i; k + + + + + + + + + \ No newline at end of file diff --git a/chapter11/12-IntroFunctionalProgramming.js b/chapter11/12-IntroFunctionalProgramming.js new file mode 100644 index 00000000..47787255 --- /dev/null +++ b/chapter11/12-IntroFunctionalProgramming.js @@ -0,0 +1,147 @@ +console.log('Using imperative JS'); + +var printArray = function(array){ + for (var i=0; i array[i]){ + minValue = array[i]; + } + } + + return minValue; +}; + +console.log(findMinArray([8,6,4,5,9])); + +console.log('Finding the min value in an array - functional ES2015'); +const min_ = function(array){ + return Math.min(...array) +}; + +//simplifying using arrow functions +const min = arr => Math.min(...arr); + +console.log(min_([8,6,4,5,9])); +console.log(min([8,6,4,5,9])); + +//concat + reduce +console.log('merge arrays - imperative'); + +var mergeArrays_ = function(arrays){ + var count = arrays.length, + newArray = [], + k =0; + for (var i=0; i [].concat(...arrays); +console.log(mergeArrays([1, 2, 3], [4, 5], [6])); + +console.log('sum values of arrays - imperative'); +var sumValues = function(array){ + var total = array[0]; + for (var i=1; i arr.reduce((a, b) => a + b); + +console.log(sum([1, 2, 3, 4, 5])); + +//map +var daysOfWeek = [ + {name: 'Monday', value: 1}, + {name: 'Tuesday', value: 2}, + {name: 'Wednesday', value: 7} +]; + +var daysOfWeekValues_ = []; +for (var i = 0; i < daysOfWeek.length; i++) { + daysOfWeekValues_.push(daysOfWeek[i].value); +} + +//to +var daysOfWeekValues = daysOfWeek.map(function(day) { + return day.value; +}); +console.log(daysOfWeekValues); + + +//filter +var positiveNumbers_ = function(array){ + var positive = []; + for (var i = 0; i < array.length; i++) { + if (array[i] >= 0){ + positive.push(array[i]); + } + } + return positive; +} +console.log(positiveNumbers_([-1,1,2,-2])); + +var positiveNumbers = function(array){ + return array.filter(function(num){ + return num >= 0; + }) +}; +console.log(positiveNumbers([-1,1,2,-2])); \ No newline at end of file diff --git a/chapter11/05-BigONotation.html b/chapter12/05-BigONotation.html similarity index 100% rename from chapter11/05-BigONotation.html rename to chapter12/05-BigONotation.html diff --git a/chapter11/05-BigONotation.js b/chapter12/05-BigONotation.js similarity index 100% rename from chapter11/05-BigONotation.js rename to chapter12/05-BigONotation.js diff --git a/chapter11/bigOChart/chart.js b/chapter12/bigOChart/chart.js similarity index 100% rename from chapter11/bigOChart/chart.js rename to chapter12/bigOChart/chart.js diff --git a/chapter11/bigOChart/index.html b/chapter12/bigOChart/index.html similarity index 100% rename from chapter11/bigOChart/index.html rename to chapter12/bigOChart/index.html