Skip to content

Commit

Permalink
Make it possible to add objects to LinkedList.
Browse files Browse the repository at this point in the history
  • Loading branch information
trekhleb committed Apr 9, 2018
1 parent cdf7220 commit 8c46dbf
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 189 deletions.
22 changes: 19 additions & 3 deletions src/data-structures/hash-table/HashTable.js
Expand Up @@ -21,16 +21,32 @@ export default class HashTable {

insert(key, value) {
const bucketLinkedList = this.buckets[this.hash(key)];
bucketLinkedList.appendUnique({ key, value });
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });

if (!node) {
// Insert new node.
bucketLinkedList.append({ key, value });
} else {
// Update value of existing node.
node.value.value = value;
}
}

delete(key) {
const bucketLinkedList = this.buckets[this.hash(key)];
return bucketLinkedList.deleteByKey(key);
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });

if (node) {
return bucketLinkedList.delete(node.value);
}

return null;
}

get(key) {
const bucketLinkedList = this.buckets[this.hash(key)];
return bucketLinkedList.findByKey(key);
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key });

return node ? node.value.value : null;
}
}
29 changes: 22 additions & 7 deletions src/data-structures/hash-table/__test__/HashTable.test.js
Expand Up @@ -31,19 +31,34 @@ describe('HashTable', () => {
hashTable.insert('c', 'earth');
hashTable.insert('d', 'ocean');

expect(hashTable.buckets[0].toString()).toBe('c:earth');
expect(hashTable.buckets[1].toString()).toBe('a:sky,d:ocean');
expect(hashTable.buckets[2].toString()).toBe('b:sea');
const stringifier = value => `${value.key}:${value.value}`;

expect(hashTable.get('a').value).toBe('sky');
expect(hashTable.get('d').value).toBe('ocean');
expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth');
expect(hashTable.buckets[1].toString(stringifier)).toBe('a:sky,d:ocean');
expect(hashTable.buckets[2].toString(stringifier)).toBe('b:sea');

expect(hashTable.get('a')).toBe('sky');
expect(hashTable.get('d')).toBe('ocean');

hashTable.delete('a');

expect(hashTable.delete('not-existing')).toBeNull();

expect(hashTable.get('a')).toBeNull();
expect(hashTable.get('d').value).toBe('ocean');
expect(hashTable.get('d')).toBe('ocean');

hashTable.insert('d', 'ocean-new');
expect(hashTable.get('d').value).toBe('ocean-new');
expect(hashTable.get('d')).toBe('ocean-new');
});

it('should be possible to add objects to hash table', () => {
const hashTable = new HashTable();

hashTable.insert('objectKey', { prop1: 'a', prop2: 'b' });

const object = hashTable.get('objectKey');
expect(object).toBeDefined();
expect(object.prop1).toBe('a');
expect(object.prop2).toBe('b');
});
});
115 changes: 27 additions & 88 deletions src/data-structures/linked-list/LinkedList.js
Expand Up @@ -2,74 +2,39 @@ import LinkedListNode from './LinkedListNode';

export default class LinkedList {
constructor() {
/** @var LinkedListNode */
this.head = null;

/** @var LinkedListNode */
this.tail = null;
}

prepend({ value, key = null }) {
const newNode = new LinkedListNode({ value, key, next: this.head });

prepend(value) {
// Make new node to be a head.
this.head = newNode;
this.head = new LinkedListNode(value, this.head);

return newNode;
return this;
}

append({ value, key = null }) {
const newNode = new LinkedListNode({ value, key });
append(value) {
const newNode = new LinkedListNode(value);

// If there is no head yet let's make new node a head.
if (!this.head) {
this.head = newNode;
this.tail = newNode;

return newNode;
return this;
}

// Attach new node to the end of linked list.
this.tail.next = newNode;
this.tail = newNode;

return newNode;
return this;
}

appendUnique({ value, key = null }) {
const newNode = new LinkedListNode({ value, key });

// If there is no head yet let's make new node a head.
if (!this.head) {
this.head = newNode;
this.tail = newNode;

return newNode;
}

// Rewind to last node.
let currentNode = this.head;
while (currentNode.next !== null) {
// If there is a node with specified key exists then update it instead of adding new one.
if (key && currentNode.key === key) {
currentNode.value = value;
return currentNode;
}

currentNode = currentNode.next;
}

// If there is a node with specified key exists then update it instead of adding new one.
if (key && currentNode.key === key) {
currentNode.value = value;
return currentNode;
}

// Attach new node to the end of linked list.
currentNode.next = newNode;
this.tail = newNode;

return newNode;
}

deleteByValue(value) {
delete(value) {
if (!this.head) {
return null;
}
Expand Down Expand Up @@ -102,37 +67,28 @@ export default class LinkedList {
return deletedNode;
}

deleteByKey(key) {
find({ value = undefined, callback = undefined }) {
if (!this.head) {
return null;
}

let deletedNode = null;

// If the head must be deleted then make 2nd node to be a head.
if (this.head.key === key) {
deletedNode = this.head;
this.head = this.head.next;
}

let currentNode = this.head;

// If next node must be deleted then make next node to be a next next one.
while (currentNode.next) {
if (currentNode.next.key === key) {
deletedNode = currentNode.next;
currentNode.next = currentNode.next.next;
} else {
currentNode = currentNode.next;
while (currentNode) {
// If callback is specified then try to find node by callback.
if (callback && callback(currentNode.value)) {
return currentNode;
}
}

// Check if tail must be deleted.
if (this.tail.key === key) {
this.tail = currentNode;
// If value is specified then try to compare by value..
if (value !== undefined && currentNode.value === value) {
return currentNode;
}

currentNode = currentNode.next;
}

return deletedNode;
return null;
}

deleteTail() {
Expand Down Expand Up @@ -177,32 +133,15 @@ export default class LinkedList {
return deletedHead;
}

findByKey(key) {
let currentNode = this.head;
toString(callback) {
const nodeStrings = [];

while (currentNode) {
if (currentNode.key === key) {
return currentNode;
}
currentNode = currentNode.next;
}

return null;
}

toArray() {
const listArray = [];
let currentNode = this.head;

while (currentNode) {
listArray.push(currentNode.toString());
nodeStrings.push(currentNode.toString(callback));
currentNode = currentNode.next;
}

return listArray;
}

toString() {
return this.toArray().toString();
return nodeStrings.toString();
}
}
13 changes: 3 additions & 10 deletions src/data-structures/linked-list/LinkedListNode.js
@@ -1,17 +1,10 @@
export default class LinkedListNode {
constructor({ value, next = null, key = null }) {
constructor(value, next = null) {
this.value = value;
this.next = next;

// Key is added to make this linked list nodes to be reusable in hash tables.
this.key = key;
}

toString() {
if (this.key) {
return `${this.key}:${this.value}`;
}

return `${this.value}`;
toString(callback) {
return callback ? callback(this.value) : `${this.value}`;
}
}

0 comments on commit 8c46dbf

Please sign in to comment.