diff --git a/README.md b/README.md index a6effa9..e1b9877 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,16 @@ ## Introduction to Data Structures +Welcome to the wonderful world of data structures! If this is your first exposure to the subject, check out this [gentle introduction](http://blog.benoitvallon.com/data-structures-in-javascript/data-structures-in-javascript/). + ## Implementation +The first step to understanding data structures is learning how to build them, and what the advantages of each type are. For more on this topic, check out an explanantion of [stack](http://blog.benoitvallon.com/data-structures-in-javascript/the-stack-data-structure/) and [queue](http://blog.benoitvallon.com/data-structures-in-javascript/the-queue-data-structure/). + ### Classic Questions -## Reimplementation(Using Other Data Structures) +Once you feel like you've got a solid grasp of how these data structures work, go ahead and clone and take the repo for a whirl and take a stab at two classic interview questions making use of the stack and queue data structures, respectively. + +## Reimplementation (Using Other Data Structures) + +Once you've done that level up by reimplementing these data structures using the other data structure! diff --git a/lib/spec.js b/lib/spec.js index d7d6428..aea9076 100755 --- a/lib/spec.js +++ b/lib/spec.js @@ -21,7 +21,7 @@ describe('MaxQueue', function () { it('should return max item', function() { let queue = new Queue(); queue.enqueue(1) - expect(queue.max[0]).to.equal(1); + expect(queue.getMax()).to.equal(1); }); it('should remove items', function() { diff --git a/src/balancedParens.js b/src/balancedParens.js index d687dec..029911b 100755 --- a/src/balancedParens.js +++ b/src/balancedParens.js @@ -1,8 +1,46 @@ class Stack { // Your code here + constructor() { + this.items = []; + this.count = 0; + } + + getLength() { + return this.count; + } + + push(item) { + this.items.push(item); + this.count = this.count + 1; + } + + pop() { + if(this.count > 0) { + this.count = this.count - 1; + } + + return this.items.pop(); + } + + peek() { + return this.items.slice(-1)[0]; + } }; const balancedParens = (str) => { // Your code here - + let stack = new Stack(); + let open = { '{': '}', '[': ']', '(': ')' }; + let closed = { '}': true, ']': true, ')': true }; + + for (var i = 0; i < str.length; i ++) { + let chr = str[i]; + if (open[chr]) { + stack.push(chr); + } else if (closed[chr]) { + let popped = open[stack.pop()]; + if (popped !== chr) return false; + } + } + return stack.count === 0; }; diff --git a/src/maxQueue.js b/src/maxQueue.js index 04dbfd2..92e44de 100644 --- a/src/maxQueue.js +++ b/src/maxQueue.js @@ -1,4 +1,48 @@ class Queue { // Your code here + constructor() { + this.items = []; + this.count = 0; + this.max = []; + } + + getLength() { + return this.count; + } + + enqueue(item) { + this.items.unshift(item); + this.count = this.count + 1; + if(this.max.length === 0 || this.max[0] <= item){ + this.max.unshift(item); + } + } + + dequeue() { + if(this.count > 0) { + this.count = this.count - 1; + } + var item = this.items.shift(); + if(item === this.max[0]){ + this.max.shift(); + } + if(this.max.length === 0 ){ + var tempMax; + for(var i = 0; i < this.items.length; i++){ + if(tempMax < this.items[i]){ + tempMax = this.item[i]; + } + } + this.max[0] = tempMax; + } + return item; + } + + peek() { + return this.items.slice(0,1)[0]; + } + getMax() { + return this.max[0]; + } }; diff --git a/src/minQueue.js b/src/minQueue.js new file mode 100644 index 0000000..05a7c81 --- /dev/null +++ b/src/minQueue.js @@ -0,0 +1,42 @@ +'use strict'; // this line is required because ES6 classes are written in strict mode. + +class Queue { + // Your code here + constructor() { + this.items = []; + this.count = 0; + this.min = []; + } + + getLength() { + return this.count; + } + + enqueue(item) { + this.items.unshift(item); + this.count = this.count + 1; + if(this.min.length === 0 || this.min[0] >= item){ + this.min.unshift(item); + } + } + + dequeue() { + if(this.count > 0) { + this.count = this.count - 1; + } + var item = this.items.shift(); + if(item === this.min[0]){ + this.min.shift(); + } + return item; + } + + peek() { + return this.items.slice(0,1)[0]; + } + + getMin() { + return this.min[0]; + } +}; + diff --git a/src/minQueue_privateVar.js b/src/minQueue_privateVar.js new file mode 100644 index 0000000..c79574b --- /dev/null +++ b/src/minQueue_privateVar.js @@ -0,0 +1,89 @@ +'use strict'; // this line is required because ES6 classes are written in strict mode. + +// those of you who have background in OOD languages will probably wonder if JavaScript allows for private class variables. +// JavaScript is OOD-ish. +// Private variable naming convention is to prefix private variable names with underscore character. + +// >>>>> PRIVATE VARIABLE SET UP .... ugly, right? +let _items = new WeakMap(); +let _min = new WeakMap(); +let _count = new WeakMap(); +// <<<<< +class Queue { + // Your code here + constructor() { + // >>> instantiate private variable + _items.set(this, []); + _min.set(this, []); + _count.set(this, 0); + // <<< + } + + getLength() { + // >>> private variable access + let count = _count.get(this); + // <<< + return count; + } + + enqueue(item) { + // >>> private variable access + let items = _items.get(this); + let count = _count.get(this); + let min = _min.get(this); + // <<< + + items.unshift(item); + count = count + 1; + if(min.length === 0 || min[0] >= item){ + min.unshift(item); + } + + return items[0]; + } + + dequeue() { + // >>> private variable access + let items = _items.get(this); + let count = _count.get(this); + let min = _min.get(this); + // <<< + + if(count > 0) { + count = count - 1; + } + var item = items.shift(); + if(item === min[0]){ + min.shift(); + } + return item; + } + + peek() { + // >>> private variable access + let items = _items.get(this); + // <<< + return items.slice(0,1)[0]; + } + + getMin() { + // >>> private variable access + let min = _min.get(this); + // <<< + return min[0]; + } +}; + + +let q = new Queue(); + +console.log('en: ', q.enqueue(13)); +console.log(q.enqueue(12)); +console.log(q.enqueue(10)); +console.log(q.enqueue(1)); +console.log('de: ', q.dequeue()); +console.log(q.dequeue()); +console.log(q.dequeue()); +console.log(q.dequeue()); + + diff --git a/src/queue_LL.js b/src/queue_LL.js new file mode 100644 index 0000000..43ae32c --- /dev/null +++ b/src/queue_LL.js @@ -0,0 +1,65 @@ +// IMPLEMENTATION USING LINKED LIST +var Queue = function() { + // private variables + var queueInstance = {}; + var head = null; + var tail = null; + + // private class + var Node = function(val) { + var nodeInstance = {}; + nodeInstance.value = val; + nodeInstance.next = null; + + return nodeInstance; + } + + queueInstance.enqueue = function(v) { + var newNode = Node(v); + + if(!head) { + // head = tail = newNode; <<<< shortcut + head = newNode; + tail = newNode; + } else { + tail.next = newNode; + tail = newNode; + } + ++this.length; + + return tail.value; + } + + queueInstance.dequeue = function() { + if (!head) { + console.error('Cannot dequeue empty queue'); + } else { + var n = head.value; + head = head.next; + --this.length; + return n; + } + + return undefined; + } + + queueInstance.length = 0; + + return queueInstance; +} + +var q = Queue(); +console.log('length at start: ', q.length); // 0 +console.log('enqueue: '); +for (var i = 0; i < 3; i++) { + console.log(q.enqueue(i)); // H[]T --> Head[0]Tail --> H[0, 1]T --> H[0, 1, 2]T +} + +console.log('length after adding 3 items: ', q.length); // 3 +console.log('dequeue: '); +for (var i = 0; i < 3; i++) { + console.log(q.dequeue()); // Head[0, 1, 2]Tail --> H[1, 2]T --> H[2]T --> H[]T +} + +console.log('length after removing everything: ', q.length); // 0 +q.dequeue(); // should log error message diff --git a/src/stack_LL.js b/src/stack_LL.js new file mode 100644 index 0000000..8a9dffb --- /dev/null +++ b/src/stack_LL.js @@ -0,0 +1,37 @@ +// IMPLEMENTATION OF STACK using LINKED LIST +var Stack = function() { + var instance = {}; + + var Node = function(val) { + var node = {}; + node.value = val; + node.next = null; + return node; + } + var head = null; + + instance.length = 0; + + instance.pop = function() { + if (!head) { + console.error('Cannot pop empty stack'); + } else { + var result = head.value; + head = head.next; + --this.length; + } + + return result; + } + + instance.push = function(val) { + var newNode = Node(val); + newNode.next = head; + head = newNode; + ++this.length; + + return head.value; + } + + return instance; +};