Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"scripts": {
"test": "eslint tests/*.js && eslint src/*.js && jest --verbose",
"lint": "eslint",
"test:watch": "npm test -- --watch"
"test:watch": "npm test -- --watch",
"mytest": "jest --verbose",
"mytest:watch": "npm run mytest -- --watch"
},
"repository": {
"type": "git",
Expand Down
114 changes: 114 additions & 0 deletions src/doubly-linked-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/* eslint-disable arrow-parens */

const Node = require('./node');

class DoublyLinkedList {
constructor() {
Object.assign(this, { head: null, tail: null });
}

addToHead(value) {
const node = new Node({ value });
node.setNext(this.head);
node.setPrev(null);

if (!this.head) {
this.head = node;
this.tail = node;
return;
}
this.head.setPrev(node);
this.head = node;
}

addToTail(value) {
const node = new Node({ value });
node.setNext(null);
node.setPrev(this.tail);

if (!this.head) {
this.head = node;
this.tail = node;
return;
}
this.tail.setNext(node);
this.tail = node;
}

removeFromHead() {
if (this.head === this.tail) {
const removed = this.head;
this.head = null;
this.tail = null;
return removed;
}
const removed = this.head;
this.head = this.head.getNext();
this.head.setPrev(null);
removed.setNext(null);
return removed;
}

removeFromTail() {
if (this.tail === this.head) {
const removed = this.tail;
this.tail = null;
this.head = null;
return removed;
}
const removed = this.tail;
this.tail = this.tail.getPrev();
this.tail.setNext(null);
removed.setPrev(null);
return removed;
}

// delete :: Node -> Node | undefined
delete(node) {
let n = this.find(node);
if (!n) return undefined;

if (!n.getPrev()) {
this.removeFromHead();
} else if (!n.getNext()) {
this.removeFromTail();
} else {
n.getNext().setPrev(n.getPrev());
n.getPrev().setNext(n.getNext());
n = null;
}
return n;
}

// find :: Node -> Node | undefined
find(node) {
const recurse = n => {
if (!n) return undefined;
if (n.equals(node)) return n;
return recurse(n.getNext());
};
return recurse(this.head);
}

// each :: Function -> Side Effect
each(cb) {
const recurse = n => {
if (!n) return;
cb(n);
return recurse(n.getNext());
};
recurse(this.head);
}

moveToFront(node) {
this.delete(node);
this.addToHead(node.value);
}

moveToBack(node) {
this.delete(node);
this.addToTail(node.value);
}
}

module.exports = DoublyLinkedList;
72 changes: 66 additions & 6 deletions src/hash-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,86 @@ class HashTable {
constructor(limit = 8) {
this.limit = limit;
this.storage = new LimitedArray(this.limit);
// Do not modify anything inside of the constructor
}

// 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 hash = getIndexBelowMax(key, this.limit); // => address
const bucket = this.storage.get(hash);
let match;

try {
bucket.forEach((tuple) => {
if (tuple[0] === key) {
match = tuple[1];
}
});
} catch (e) {
return undefined;
}

return match;
}

// Adds the given key, value pair to the hash table
// Fetch the bucket associated with the given key using the getIndexBelowMax function
// 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) {
const hash = getIndexBelowMax(key, this.limit);
const bucket = this.storage.get(hash) || [];

bucket.push([key, value]);
bucket.forEach((tuple, i) => {
if (tuple[0] === key) {
bucket.splice(i, 1, tuple);
}
});

if (this.storage.length > this.limit * 0.75) {
this.resize(2 * this.limit);
}

this.storage.set(hash, bucket);
}
// Removes the key, value pair from the hash table


// 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 hash = getIndexBelowMax(key, this.limit);
const bucket = this.storage.get(hash);

try {
bucket.forEach((tuple, i) => {
if (tuple[0] === key) {
bucket.splice(i, 1);
}
});
} catch (e) {
return undefined;
}

this.storage.set(hash, 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) {

resize(newSize) {
const oldStore = this.storage;
this.limit = newSize;
this.storage = new LimitedArray(newSize);

oldStore.each((bucket) => {
if (!bucket) return;
bucket.forEach((tuple) => {
const [key, value] = tuple;
const hash = getIndexBelowMax(key);

this.insert(key, value);
});
});
}
}

Expand Down
28 changes: 26 additions & 2 deletions src/linked-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,45 @@ class LinkedList {
this.tail = null;
// Do not modify anything inside of the constructor
}

// Wraps the given value in a node object and adds the node to the tail of the list
// 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 node = {
value,
next: null,
};
if (!this.head) {
this.head = node;
this.tail = node;
return;
}

this.tail.next = node;
this.tail = node;
}

// 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() {

const removed = this.head;
this.head = this.head.next;
removed.next = null;
return removed.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 current = this.head;
while (current) {
if (current.value === value) {
return true;
}
current = current.next;
}
return false;
}
}

Expand Down
30 changes: 30 additions & 0 deletions src/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Node {
constructor({ value, next = null, prev = null }) {
Object.assign(this, { value, next, prev });
}

setNext(next) {
this.next = next;
}

setPrev(prev) {
this.prev = prev;
}

getNext() {
return this.next;
}

getPrev() {
return this.prev;
}

equals(node) {
if (Array.isArray(node.value)) {
return node.value[0] === this.value[0];
}
return node.value === this.value;
}
}

module.exports = Node;
22 changes: 22 additions & 0 deletions src/queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,30 @@
3. Add an `enqueue` method that accepts an item as input and adds it to the storage structure
4. Add a `dequeue` method that removes the item in the queue that was added earliest
*/

const DLL = require('./doubly-linked-list');

class Queue {
constructor() {
this.storage = new DLL();
this.count = 0;
}

enqueue(value) {
this.storage.addToTail(value);
return ++this.count;
}

dequeue() {
if (this.count === 0) return;
const { value } = this.storage.removeFromHead();
this.count--;
return value;
}

get size() {
return this.count;
}
}

module.exports = Queue;
43 changes: 43 additions & 0 deletions src/stack-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// This stack is implemented using an ES6 WeakMap for storage:

let Stack = (() => {
const sKey = {};
const items = new WeakMap();

class Stack {
constructor() {
items.set(sKey, []);
}

push(element) {
let stack = items.get(sKey);
stack.push(element);
}

pop() {
let stack = items.get(sKey);
return stack.pop();
}

peek() {
let stack = items.get(sKey);
return stack[stack.length - 1];
}

clear() {
items.set(sKey, []);
}

size() {
return items.get(sKey).length;
}

}

return Stack;
})();

let stack = new Stack()
stack.push('value')

module.exports = Stack
Loading