diff --git a/src/doubly-linked-list.js b/src/doubly-linked-list.js index 6373ce3..40abb40 100644 --- a/src/doubly-linked-list.js +++ b/src/doubly-linked-list.js @@ -3,4 +3,91 @@ class DoublyLinkedList { this.head = null; this.tail = null; } + addToTail(value) { + const newTail = { + value, + next: null, + prev: null, + }; + if (this.tail === null) { + this.head = newTail; + this.tail = newTail; + return; + } + const oldTail = this.tail; + oldTail.next = newTail; + this.tail = newTail; + newTail.prev = oldTail; + } + addToHead(value) { + const newNode = { + value, + next: null, + prev: null, + }; + if (this.head === null) { + this.head = newNode; + this.tail = newNode; + return; + } + const oldHead = this.head; + oldHead.prev = newNode; + this.head = newNode; + this.head.next = oldHead; + } + removeFromHead() { + const oldHead = this.head; + if (oldHead === null) return null; + if (oldHead.next !== null) { + this.head = oldHead.next; + this.head.prev = null; + } else { + this.head = null; + this.tail = null; + } + return oldHead; + } + + removeFromTail() { + const oldTail = this.tail; + if (oldTail === null) return null; + if (oldTail.prev !== null) { + this.tail = oldTail.prev; + this.tail.next = null; + } else { + this.head = null; + this.tail = null; + } + return oldTail; + } + delete(node) { + if (node.value === this.head.value) { + this.removeFromHead(); + } + if (node.value === this.tail.value) { + this.removeFromTail(); + } + let current = this.head; + while (current !== null) { + if (current.value === node.value) { + current.prev.next = current.next; + current.next.prev = current.prev; + break; + } + current = current.next; + } + return; + } + moveToFront(node) { + if (this.head.value === node.value) return; + this.delete(node); + this.addToHead(node.value); + } + moveToBack(node) { + if (this.tail.value === node.value) return; + this.delete(node); + this.addToTail(node.value); + } } + +module.exports = DoublyLinkedList; diff --git a/src/hash-table.js b/src/hash-table.js index 7edba9e..5a7d3bb 100644 --- a/src/hash-table.js +++ b/src/hash-table.js @@ -14,20 +14,50 @@ class HashTable { // If no bucket has been created for that index, instantiate a new bucket and add the key, value pair to that new bucket // If the key already exists in the bucket, the newer value should overwrite the older value associated with that key insert(key, value) { - + this.resize(); + const index = getIndexBelowMax(key.toString(), this.limit); + let bucket = this.storage.get(index) || []; + bucket = bucket.filter(item => item[0] !== key); + bucket.push([key, value]); + this.storage.set(index, bucket); } // Removes the key, value pair from the hash table // Fetch the bucket associated with the given key using the getIndexBelowMax function // Remove the key, value pair from the bucket remove(key) { - + const index = getIndexBelowMax(key.toString(), this.limit); + let bucket = this.storage.get(index); + if (bucket) { + bucket = bucket.filter(item => item[0] !== key); + this.storage.set(index, bucket); + } } - + // Fetches the value associated with the given key from the hash table // Fetch the bucket associated with the given key using the getIndexBelowMax function // Find the key, value pair inside the bucket and return the value retrieve(key) { - + const index = getIndexBelowMax(key.toString(), this.limit); + const bucket = this.storage.get(index); + let retrieved; + if (bucket) { + retrieved = bucket.filter(item => item[0] === key)[0]; + } + return retrieved ? retrieved[1] : undefined; + } + + resize() { + if (this.storage.length < (.75 * this.limit)) return; + let oldHT = this.storage; + this.limit *= 2; + this.storage = new LimitedArray(this.limit); + oldHT.each((bucket, index) => { + if (Array.isArray(bucket)) { + for (let i = 0; i < bucket.length; i++) { + this.insert(...bucket[i]); + } + } + }) } } diff --git a/src/linked-list.js b/src/linked-list.js index 267e295..15bd5a3 100644 --- a/src/linked-list.js +++ b/src/linked-list.js @@ -9,17 +9,43 @@ class LinkedList { // If the list is empty, the new element is considered the tail as well as the head // If there is one element in the list before the new element is added, the new element becomes the tail of the list addToTail(value) { - + const newNode = { + value, + next: null, + }; + if (this.tail === null) { + this.head = newNode; + this.tail = newNode; + return; + } + const holder = this.tail; + holder.next = newNode; + this.tail = newNode; } // Removes the current head node from the list, replacing it with the next element in the list // Returns the value of the removed node removeHead() { - + if (this.head === null) { + return null; + } + const node = this.head; + this.head = node.next; + if (this.head === null) { + this.tail = null; + } + return node.value; } // Checks the linked list for the given value // Returns true if the the value is found in the list, false otherwise contains(value) { - + let node = this.head; + while (node !== null) { + if (value === node.value) { + return true; + } + node = node.next; + } + return false; } } diff --git a/src/queue.js b/src/queue.js index dcf7ad7..6a0a4c7 100644 --- a/src/queue.js +++ b/src/queue.js @@ -5,7 +5,24 @@ 4. Add a `dequeue` method that removes the item in the queue that was added earliest */ class Queue { - + constructor(items) { + this.items = []; + this.size = this.items.length; + } + enqueue(element) { + this.items.push(element); + this.size++; + } + dequeue() { + if (this.size === 0) { + return this.size; + } + this.size--; + return this.items.shift(); + } + size() { + return this.items.length; + } } module.exports = Queue; diff --git a/src/stack.js b/src/stack.js index 4312b41..1f328ca 100644 --- a/src/stack.js +++ b/src/stack.js @@ -5,7 +5,24 @@ 4. Add a `pop` method that removes the most recently-added item to the stack */ class Stack { - + constructor() { + this.items = []; + this.size = this.items.length; + } + push(element) { + this.size++; + return this.items.push(element); + } + pop() { + if (this.size === 0) { + return this.size; + } + this.size--; + return this.items.pop(); + } + size() { + return this.items.legnth; + } } module.exports = Stack; diff --git a/tests/hash-table.test.js b/tests/hash-table.test.js index 854fe70..ff2ddc9 100644 --- a/tests/hash-table.test.js +++ b/tests/hash-table.test.js @@ -59,26 +59,26 @@ describe('HashTable', () => { }); /* Extra Credit */ - - // it('should resize the hash table when > 75% full', () => { - // hashTable.insert('a', true); - // hashTable.insert('b', true); - // hashTable.insert('c', true); - // hashTable.insert('d', true); - // hashTable.insert('e', true); - // hashTable.insert('f', true); - // hashTable.insert('g', true); - // expect(hashTable.limit).toBe(16); - // expect(hashTable.storage.length).toBe(8); - // hashTable.insert('h', true); - // hashTable.insert('i', true); - // hashTable.insert('j', true); - // hashTable.insert('k', true); - // hashTable.insert('l', true); - // hashTable.insert('m', true); - // hashTable.insert('n', true); - // hashTable.insert('o', true); - // expect(hashTable.limit).toBe(32); - // expect(hashTable.storage.length).toBe(16); - // }); + + it('should resize the hash table when > 75% full', () => { + hashTable.insert('a', true); + hashTable.insert('b', true); + hashTable.insert('c', true); + hashTable.insert('d', true); + hashTable.insert('e', true); + hashTable.insert('f', true); + hashTable.insert('g', true); + expect(hashTable.limit).toBe(16); + expect(hashTable.storage.length).toBe(8); + hashTable.insert('h', true); + hashTable.insert('i', true); + hashTable.insert('j', true); + hashTable.insert('k', true); + hashTable.insert('l', true); + hashTable.insert('m', true); + hashTable.insert('n', true); + hashTable.insert('o', true); + expect(hashTable.limit).toBe(32); + expect(hashTable.storage.length).toBe(16); + }); }); diff --git a/tests/linked-list.test.js b/tests/linked-list.test.js index ec0cae5..00ccc76 100644 --- a/tests/linked-list.test.js +++ b/tests/linked-list.test.js @@ -68,107 +68,107 @@ describe('LinkedList', () => { /* Extra Credit */ -// describe('DoublyLinkedList', () => { -// beforeEach(() => { -// list = new DoublyLinkedList(); -// }); - -// it('should have the methods "addToHead", "addToTail", "removeFromHead", "removeFromTail", "delete", "moveToFront", and "moveToBack"', () => { -// const hasAddToTail = Object.getPrototypeOf(list).hasOwnProperty('addToTail'); -// const hasAddToHead = Object.getPrototypeOf(list).hasOwnProperty('addToHead'); -// const hasRemoveFromHead = Object.getPrototypeOf(list).hasOwnProperty('removeFromHead'); -// const hasRemoveFromTail = Object.getPrototypeOf(list).hasOwnProperty('removeFromTail'); -// const hasMoveToFront = Object.getPrototypeOf(list).hasOwnProperty('moveToFront'); -// const hasMoveToBack = Object.getPrototypeOf(list).hasOwnProperty('moveToBack'); -// const hasDelete = Object.getPrototypeOf(list).hasOwnProperty('delete'); -// expect(hasAddToHead).toBe(true); -// expect(hasAddToTail).toBe(true); -// expect(hasRemoveFromHead).toBe(true); -// expect(hasRemoveFromTail).toBe(true); -// expect(hasMoveToBack).toBe(true); -// expect(hasMoveToFront).toBe(true); -// expect(hasDelete).toBe(true); -// }); - -// it('should be able to add list nodes to the head of the list', () => { -// list.addToHead(1); -// list.addToHead(2); -// list.addToHead(3); -// expect(list.head.value).toEqual(3); -// expect(list.head.next.value).toEqual(2); -// expect(list.head.next.next.value).toEqual(1); -// expect(list.tail.value).toEqual(1); -// }); - -// it('should be able to add list nodes to the tail of the list', () => { -// list.addToTail(100); -// list.addToTail(99); -// list.addToTail(98); -// expect(list.head.value).toEqual(100); -// expect(list.tail.value).toEqual(98); -// expect(list.tail.prev.value).toEqual(99); -// expect(list.tail.prev.prev.value).toEqual(100); -// }); - -// it('should be able to remove the head node of the list', () => { -// list.addToHead(3); -// list.addToHead(39); -// expect(list.removeFromHead().value).toEqual(39); -// expect(list.removeFromHead().value).toEqual(3); -// expect(list.removeFromHead()).toBeNull(); -// list.addToTail(18); -// expect(list.removeFromHead().value).toEqual(18); -// expect(list.removeFromHead()).toBeNull(); -// }); - -// it('should be able to remove the tail node of the list', () => { -// list.addToTail(18); -// list.addToTail(109); -// expect(list.removeFromTail().value).toEqual(109); -// expect(list.removeFromTail().value).toEqual(18); -// expect(list.removeFromTail()).toBeNull(); -// list.addToHead(16); -// expect(list.removeFromTail().value).toEqual(16); -// expect(list.removeFromTail()).toBeNull(); -// }); - -// it('should be able to move an arbitrary node in the list to the front of the list', () => { -// list.addToTail(1); -// list.addToTail(10); -// list.addToTail(7); -// list.addToTail(3); -// expect(list.head.value).toEqual(1); -// expect(list.tail.value).toEqual(3); -// list.moveToFront(list.tail); -// expect(list.head.value).toEqual(3); -// expect(list.head.next.value).toEqual(1); -// expect(list.tail.value).toEqual(7); -// list.moveToFront(list.tail.prev); -// expect(list.head.value).toEqual(10); -// }); - -// it('should be able to move an arbitrary node in the list to the back of the list', () => { -// list.addToHead(1); -// list.addToHead(40); -// list.addToHead(29); -// list.addToHead(90); -// expect(list.tail.value).toEqual(1); -// expect(list.head.value).toEqual(90); -// list.moveToBack(list.head); -// expect(list.tail.value).toEqual(90); -// expect(list.tail.prev.value).toEqual(1); -// list.moveToBack(list.head.next); -// expect(list.head.value).toEqual(29); -// }); - -// it('should be able to delete an arbitrary node in the list', () => { -// list.addToHead(8); -// list.addToHead(11); -// list.addToHead(90); -// expect(list.head.next.value).toEqual(11); -// expect(list.tail.prev.value).toEqual(11); -// list.delete(list.head.next); -// expect(list.head.next.value).toEqual(8); -// expect(list.tail.prev.value).toEqual(90); -// }); -// }); +describe('DoublyLinkedList', () => { + beforeEach(() => { + list = new DoublyLinkedList(); + }); + + it('should have the methods "addToHead", "addToTail", "removeFromHead", "removeFromTail", "delete", "moveToFront", and "moveToBack"', () => { + const hasAddToTail = Object.getPrototypeOf(list).hasOwnProperty('addToTail'); + const hasAddToHead = Object.getPrototypeOf(list).hasOwnProperty('addToHead'); + const hasRemoveFromHead = Object.getPrototypeOf(list).hasOwnProperty('removeFromHead'); + const hasRemoveFromTail = Object.getPrototypeOf(list).hasOwnProperty('removeFromTail'); + const hasMoveToFront = Object.getPrototypeOf(list).hasOwnProperty('moveToFront'); + const hasMoveToBack = Object.getPrototypeOf(list).hasOwnProperty('moveToBack'); + const hasDelete = Object.getPrototypeOf(list).hasOwnProperty('delete'); + expect(hasAddToHead).toBe(true); + expect(hasAddToTail).toBe(true); + expect(hasRemoveFromHead).toBe(true); + expect(hasRemoveFromTail).toBe(true); + expect(hasMoveToBack).toBe(true); + expect(hasMoveToFront).toBe(true); + expect(hasDelete).toBe(true); + }); + + it('should be able to add list nodes to the head of the list', () => { + list.addToHead(1); + list.addToHead(2); + list.addToHead(3); + expect(list.head.value).toEqual(3); + expect(list.head.next.value).toEqual(2); + expect(list.head.next.next.value).toEqual(1); + expect(list.tail.value).toEqual(1); + }); + + it('should be able to add list nodes to the tail of the list', () => { + list.addToTail(100); + list.addToTail(99); + list.addToTail(98); + expect(list.head.value).toEqual(100); + expect(list.tail.value).toEqual(98); + expect(list.tail.prev.value).toEqual(99); + expect(list.tail.prev.prev.value).toEqual(100); + }); + + it('should be able to remove the head node of the list', () => { + list.addToHead(3); + list.addToHead(39); + expect(list.removeFromHead().value).toEqual(39); + expect(list.removeFromHead().value).toEqual(3); + expect(list.removeFromHead()).toBeNull(); + list.addToTail(18); + expect(list.removeFromHead().value).toEqual(18); + expect(list.removeFromHead()).toBeNull(); + }); + + it('should be able to remove the tail node of the list', () => { + list.addToTail(18); + list.addToTail(109); + expect(list.removeFromTail().value).toEqual(109); + expect(list.removeFromTail().value).toEqual(18); + expect(list.removeFromTail()).toBeNull(); + list.addToHead(16); + expect(list.removeFromTail().value).toEqual(16); + expect(list.removeFromTail()).toBeNull(); + }); + + it('should be able to move an arbitrary node in the list to the front of the list', () => { + list.addToTail(1); + list.addToTail(10); + list.addToTail(7); + list.addToTail(3); + expect(list.head.value).toEqual(1); + expect(list.tail.value).toEqual(3); + list.moveToFront(list.tail); + expect(list.head.value).toEqual(3); + expect(list.head.next.value).toEqual(1); + expect(list.tail.value).toEqual(7); + list.moveToFront(list.tail.prev); + expect(list.head.value).toEqual(10); + }); + + it('should be able to move an arbitrary node in the list to the back of the list', () => { + list.addToHead(1); + list.addToHead(40); + list.addToHead(29); + list.addToHead(90); + expect(list.tail.value).toEqual(1); + expect(list.head.value).toEqual(90); + list.moveToBack(list.head); + expect(list.tail.value).toEqual(90); + expect(list.tail.prev.value).toEqual(1); + list.moveToBack(list.head.next); + expect(list.head.value).toEqual(29); + }); + + it('should be able to delete an arbitrary node in the list', () => { + list.addToHead(8); + list.addToHead(11); + list.addToHead(90); + expect(list.head.next.value).toEqual(11); + expect(list.tail.prev.value).toEqual(11); + list.delete(list.head.next); + expect(list.head.next.value).toEqual(8); + expect(list.tail.prev.value).toEqual(90); + }); +});