mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-07-06 01:15:56 +08:00
Make it possible to add objects to LinkedList.
This commit is contained in:
@ -21,16 +21,32 @@ export default class HashTable {
|
|||||||
|
|
||||||
insert(key, value) {
|
insert(key, value) {
|
||||||
const bucketLinkedList = this.buckets[this.hash(key)];
|
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) {
|
delete(key) {
|
||||||
const bucketLinkedList = this.buckets[this.hash(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) {
|
get(key) {
|
||||||
const bucketLinkedList = this.buckets[this.hash(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,34 @@ describe('HashTable', () => {
|
|||||||
hashTable.insert('c', 'earth');
|
hashTable.insert('c', 'earth');
|
||||||
hashTable.insert('d', 'ocean');
|
hashTable.insert('d', 'ocean');
|
||||||
|
|
||||||
expect(hashTable.buckets[0].toString()).toBe('c:earth');
|
const stringifier = value => `${value.key}:${value.value}`;
|
||||||
expect(hashTable.buckets[1].toString()).toBe('a:sky,d:ocean');
|
|
||||||
expect(hashTable.buckets[2].toString()).toBe('b:sea');
|
|
||||||
|
|
||||||
expect(hashTable.get('a').value).toBe('sky');
|
expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth');
|
||||||
expect(hashTable.get('d').value).toBe('ocean');
|
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');
|
hashTable.delete('a');
|
||||||
|
|
||||||
|
expect(hashTable.delete('not-existing')).toBeNull();
|
||||||
|
|
||||||
expect(hashTable.get('a')).toBeNull();
|
expect(hashTable.get('a')).toBeNull();
|
||||||
expect(hashTable.get('d').value).toBe('ocean');
|
expect(hashTable.get('d')).toBe('ocean');
|
||||||
|
|
||||||
hashTable.insert('d', 'ocean-new');
|
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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,74 +2,39 @@ import LinkedListNode from './LinkedListNode';
|
|||||||
|
|
||||||
export default class LinkedList {
|
export default class LinkedList {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
/** @var LinkedListNode */
|
||||||
this.head = null;
|
this.head = null;
|
||||||
|
|
||||||
|
/** @var LinkedListNode */
|
||||||
this.tail = null;
|
this.tail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepend({ value, key = null }) {
|
prepend(value) {
|
||||||
const newNode = new LinkedListNode({ value, key, next: this.head });
|
|
||||||
|
|
||||||
// Make new node to be a head.
|
// 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 }) {
|
append(value) {
|
||||||
const newNode = new LinkedListNode({ value, key });
|
const newNode = new LinkedListNode(value);
|
||||||
|
|
||||||
// If there is no head yet let's make new node a head.
|
// If there is no head yet let's make new node a head.
|
||||||
if (!this.head) {
|
if (!this.head) {
|
||||||
this.head = newNode;
|
this.head = newNode;
|
||||||
this.tail = newNode;
|
this.tail = newNode;
|
||||||
|
|
||||||
return newNode;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach new node to the end of linked list.
|
// Attach new node to the end of linked list.
|
||||||
this.tail.next = newNode;
|
this.tail.next = newNode;
|
||||||
this.tail = newNode;
|
this.tail = newNode;
|
||||||
|
|
||||||
return newNode;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
appendUnique({ value, key = null }) {
|
delete(value) {
|
||||||
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) {
|
|
||||||
if (!this.head) {
|
if (!this.head) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -102,37 +67,28 @@ export default class LinkedList {
|
|||||||
return deletedNode;
|
return deletedNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteByKey(key) {
|
find({ value = undefined, callback = undefined }) {
|
||||||
if (!this.head) {
|
if (!this.head) {
|
||||||
return null;
|
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;
|
let currentNode = this.head;
|
||||||
|
|
||||||
// If next node must be deleted then make next node to be a next next one.
|
while (currentNode) {
|
||||||
while (currentNode.next) {
|
// If callback is specified then try to find node by callback.
|
||||||
if (currentNode.next.key === key) {
|
if (callback && callback(currentNode.value)) {
|
||||||
deletedNode = currentNode.next;
|
return currentNode;
|
||||||
currentNode.next = currentNode.next.next;
|
|
||||||
} else {
|
|
||||||
currentNode = currentNode.next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If value is specified then try to compare by value..
|
||||||
|
if (value !== undefined && currentNode.value === value) {
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode = currentNode.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if tail must be deleted.
|
return null;
|
||||||
if (this.tail.key === key) {
|
|
||||||
this.tail = currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return deletedNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteTail() {
|
deleteTail() {
|
||||||
@ -177,32 +133,15 @@ export default class LinkedList {
|
|||||||
return deletedHead;
|
return deletedHead;
|
||||||
}
|
}
|
||||||
|
|
||||||
findByKey(key) {
|
toString(callback) {
|
||||||
let currentNode = this.head;
|
const nodeStrings = [];
|
||||||
|
|
||||||
|
let currentNode = this.head;
|
||||||
while (currentNode) {
|
while (currentNode) {
|
||||||
if (currentNode.key === key) {
|
nodeStrings.push(currentNode.toString(callback));
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
currentNode = currentNode.next;
|
currentNode = currentNode.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return nodeStrings.toString();
|
||||||
}
|
|
||||||
|
|
||||||
toArray() {
|
|
||||||
const listArray = [];
|
|
||||||
let currentNode = this.head;
|
|
||||||
|
|
||||||
while (currentNode) {
|
|
||||||
listArray.push(currentNode.toString());
|
|
||||||
currentNode = currentNode.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return listArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
toString() {
|
|
||||||
return this.toArray().toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
export default class LinkedListNode {
|
export default class LinkedListNode {
|
||||||
constructor({ value, next = null, key = null }) {
|
constructor(value, next = null) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.next = next;
|
this.next = next;
|
||||||
|
|
||||||
// Key is added to make this linked list nodes to be reusable in hash tables.
|
|
||||||
this.key = key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString(callback) {
|
||||||
if (this.key) {
|
return callback ? callback(this.value) : `${this.value}`;
|
||||||
return `${this.key}:${this.value}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${this.value}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,30 +12,17 @@ describe('LinkedList', () => {
|
|||||||
expect(linkedList.head).toBeNull();
|
expect(linkedList.head).toBeNull();
|
||||||
expect(linkedList.tail).toBeNull();
|
expect(linkedList.tail).toBeNull();
|
||||||
|
|
||||||
const node1 = linkedList.append({ value: 1 });
|
linkedList.append(1);
|
||||||
const node2 = linkedList.append({ value: 2, key: 'test' });
|
linkedList.append(2);
|
||||||
|
|
||||||
expect(node1.value).toBe(1);
|
expect(linkedList.toString()).toBe('1,2');
|
||||||
expect(node2.value).toBe(2);
|
|
||||||
expect(node2.key).toBe('test');
|
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('1');
|
|
||||||
expect(linkedList.tail.toString()).toBe('test:2');
|
|
||||||
|
|
||||||
expect(linkedList.toString()).toBe('1,test:2');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prepend node to linked list', () => {
|
it('should prepend node to linked list', () => {
|
||||||
const linkedList = new LinkedList();
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
const node1 = linkedList.append({ value: 1 });
|
linkedList.append(1);
|
||||||
const node2 = linkedList.prepend({ value: 2 });
|
linkedList.prepend(2);
|
||||||
|
|
||||||
expect(node1.value).toBe(1);
|
|
||||||
expect(node2.value).toBe(2);
|
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('2');
|
|
||||||
expect(linkedList.tail.toString()).toBe('1');
|
|
||||||
|
|
||||||
expect(linkedList.toString()).toBe('2,1');
|
expect(linkedList.toString()).toBe('2,1');
|
||||||
});
|
});
|
||||||
@ -43,74 +30,51 @@ describe('LinkedList', () => {
|
|||||||
it('should delete node by value from linked list', () => {
|
it('should delete node by value from linked list', () => {
|
||||||
const linkedList = new LinkedList();
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
expect(linkedList.deleteByValue(5)).toBeNull();
|
expect(linkedList.delete(5)).toBeNull();
|
||||||
|
|
||||||
linkedList.append({ value: 1 });
|
linkedList.append(1);
|
||||||
linkedList.append({ value: 2 });
|
linkedList.append(2);
|
||||||
linkedList.append({ value: 3 });
|
linkedList.append(3);
|
||||||
linkedList.append({ value: 3 });
|
linkedList.append(3);
|
||||||
linkedList.append({ value: 3 });
|
linkedList.append(3);
|
||||||
linkedList.append({ value: 4 });
|
linkedList.append(4);
|
||||||
linkedList.append({ value: 5 });
|
linkedList.append(5);
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('1');
|
expect(linkedList.head.toString()).toBe('1');
|
||||||
expect(linkedList.tail.toString()).toBe('5');
|
expect(linkedList.tail.toString()).toBe('5');
|
||||||
|
|
||||||
const deletedNode = linkedList.deleteByValue(3);
|
const deletedNode = linkedList.delete(3);
|
||||||
expect(deletedNode.value).toBe(3);
|
expect(deletedNode.value).toBe(3);
|
||||||
expect(linkedList.toString()).toBe('1,2,4,5');
|
expect(linkedList.toString()).toBe('1,2,4,5');
|
||||||
|
|
||||||
linkedList.deleteByValue(3);
|
linkedList.delete(3);
|
||||||
expect(linkedList.toString()).toBe('1,2,4,5');
|
expect(linkedList.toString()).toBe('1,2,4,5');
|
||||||
|
|
||||||
linkedList.deleteByValue(1);
|
linkedList.delete(1);
|
||||||
expect(linkedList.toString()).toBe('2,4,5');
|
expect(linkedList.toString()).toBe('2,4,5');
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('2');
|
expect(linkedList.head.toString()).toBe('2');
|
||||||
expect(linkedList.tail.toString()).toBe('5');
|
expect(linkedList.tail.toString()).toBe('5');
|
||||||
|
|
||||||
linkedList.deleteByValue(5);
|
linkedList.delete(5);
|
||||||
expect(linkedList.toString()).toBe('2,4');
|
expect(linkedList.toString()).toBe('2,4');
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('2');
|
expect(linkedList.head.toString()).toBe('2');
|
||||||
expect(linkedList.tail.toString()).toBe('4');
|
expect(linkedList.tail.toString()).toBe('4');
|
||||||
|
|
||||||
linkedList.deleteByValue(4);
|
linkedList.delete(4);
|
||||||
expect(linkedList.toString()).toBe('2');
|
expect(linkedList.toString()).toBe('2');
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('2');
|
expect(linkedList.head.toString()).toBe('2');
|
||||||
expect(linkedList.tail.toString()).toBe('2');
|
expect(linkedList.tail.toString()).toBe('2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete node by key from linked list', () => {
|
|
||||||
const linkedList = new LinkedList();
|
|
||||||
|
|
||||||
expect(linkedList.deleteByKey('key')).toBeNull();
|
|
||||||
|
|
||||||
linkedList.append({ value: 1, key: 'test1' });
|
|
||||||
linkedList.append({ value: 2, key: 'test2' });
|
|
||||||
linkedList.append({ value: 3, key: 'test3' });
|
|
||||||
linkedList.append({ value: 4, key: 'test4' });
|
|
||||||
|
|
||||||
const deletedNode1 = linkedList.deleteByKey('test2');
|
|
||||||
expect(deletedNode1.key).toBe('test2');
|
|
||||||
expect(linkedList.toString()).toBe('test1:1,test3:3,test4:4');
|
|
||||||
|
|
||||||
const deletedNode2 = linkedList.deleteByKey('test1');
|
|
||||||
expect(deletedNode2.key).toBe('test1');
|
|
||||||
expect(linkedList.toString()).toBe('test3:3,test4:4');
|
|
||||||
|
|
||||||
const deletedNode3 = linkedList.deleteByKey('test4');
|
|
||||||
expect(deletedNode3.key).toBe('test4');
|
|
||||||
expect(linkedList.toString()).toBe('test3:3');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete linked list tail', () => {
|
it('should delete linked list tail', () => {
|
||||||
const linkedList = new LinkedList();
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
linkedList.append({ value: 1 });
|
linkedList.append(1);
|
||||||
linkedList.append({ value: 2 });
|
linkedList.append(2);
|
||||||
linkedList.append({ value: 3 });
|
linkedList.append(3);
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('1');
|
expect(linkedList.head.toString()).toBe('1');
|
||||||
expect(linkedList.tail.toString()).toBe('3');
|
expect(linkedList.tail.toString()).toBe('3');
|
||||||
@ -142,8 +106,8 @@ describe('LinkedList', () => {
|
|||||||
|
|
||||||
expect(linkedList.deleteHead()).toBeNull();
|
expect(linkedList.deleteHead()).toBeNull();
|
||||||
|
|
||||||
linkedList.append({ value: 1 });
|
linkedList.append(1);
|
||||||
linkedList.append({ value: 2 });
|
linkedList.append(2);
|
||||||
|
|
||||||
expect(linkedList.head.toString()).toBe('1');
|
expect(linkedList.head.toString()).toBe('1');
|
||||||
expect(linkedList.tail.toString()).toBe('2');
|
expect(linkedList.tail.toString()).toBe('2');
|
||||||
@ -163,26 +127,52 @@ describe('LinkedList', () => {
|
|||||||
expect(linkedList.tail).toBeNull();
|
expect(linkedList.tail).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should append unique nodes', () => {
|
it('should be possible to store objects in the list and to print them out', () => {
|
||||||
const linkedList = new LinkedList();
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
linkedList.appendUnique({ value: 1, key: 'test1' });
|
const nodeValue1 = { value: 1, key: 'key1' };
|
||||||
linkedList.appendUnique({ value: 2, key: 'test2' });
|
const nodeValue2 = { value: 2, key: 'key2' };
|
||||||
linkedList.appendUnique({ value: 3, key: 'test2' });
|
|
||||||
linkedList.appendUnique({ value: 5, key: 'test1' });
|
|
||||||
|
|
||||||
expect(linkedList.toString()).toBe('test1:5,test2:3');
|
linkedList
|
||||||
|
.append(nodeValue1)
|
||||||
|
.prepend(nodeValue2);
|
||||||
|
|
||||||
|
const nodeStringifier = value => `${value.key}:${value.value}`;
|
||||||
|
|
||||||
|
expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find node by its key', () => {
|
it('should find node by value', () => {
|
||||||
const linkedList = new LinkedList();
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
expect(linkedList.findByKey('test')).toBeNull();
|
expect(linkedList.find({ value: 5 })).toBeNull();
|
||||||
|
|
||||||
linkedList.appendUnique({ value: 1, key: 'test1' });
|
linkedList.append(1);
|
||||||
linkedList.appendUnique({ value: 2, key: 'test2' });
|
expect(linkedList.find({ value: 1 })).toBeDefined();
|
||||||
linkedList.appendUnique({ value: 3, key: 'test3' });
|
|
||||||
|
|
||||||
expect(linkedList.findByKey('test3').toString()).toBe('test3:3');
|
linkedList
|
||||||
|
.append(2)
|
||||||
|
.append(3);
|
||||||
|
|
||||||
|
const node = linkedList.find({ value: 2 });
|
||||||
|
|
||||||
|
expect(node.value).toBe(2);
|
||||||
|
expect(linkedList.find({ value: 5 })).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find node by callback', () => {
|
||||||
|
const linkedList = new LinkedList();
|
||||||
|
|
||||||
|
linkedList
|
||||||
|
.append({ value: 1, key: 'test1' })
|
||||||
|
.append({ value: 2, key: 'test2' })
|
||||||
|
.append({ value: 3, key: 'test3' });
|
||||||
|
|
||||||
|
const node = linkedList.find({ callback: value => value.key === 'test2' });
|
||||||
|
|
||||||
|
expect(node).toBeDefined();
|
||||||
|
expect(node.value.value).toBe(2);
|
||||||
|
expect(node.value.key).toBe('test2');
|
||||||
|
expect(linkedList.find({ callback: value => value.key === 'test5' })).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,46 @@
|
|||||||
import LinkedListNode from '../LinkedListNode';
|
import LinkedListNode from '../LinkedListNode';
|
||||||
|
|
||||||
describe('LinkedListNode', () => {
|
describe('LinkedListNode', () => {
|
||||||
it('should create list node with kay and value', () => {
|
it('should create list node with value', () => {
|
||||||
const node = new LinkedListNode({ value: 1, key: 'test' });
|
const node = new LinkedListNode(1);
|
||||||
|
|
||||||
expect(node.value).toBe(1);
|
expect(node.value).toBe(1);
|
||||||
expect(node.key).toBe('test');
|
|
||||||
expect(node.next).toBeNull();
|
expect(node.next).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create list node with object as a value', () => {
|
||||||
|
const nodeValue = { value: 1, key: 'test' };
|
||||||
|
const node = new LinkedListNode(nodeValue);
|
||||||
|
|
||||||
|
expect(node.value.value).toBe(1);
|
||||||
|
expect(node.value.key).toBe('test');
|
||||||
|
expect(node.next).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should link nodes together', () => {
|
||||||
|
const node2 = new LinkedListNode(2);
|
||||||
|
const node1 = new LinkedListNode(1, node2);
|
||||||
|
|
||||||
|
expect(node1.next).toBeDefined();
|
||||||
|
expect(node2.next).toBeNull();
|
||||||
|
expect(node1.value).toBe(1);
|
||||||
|
expect(node1.next.value).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
it('should convert node to string', () => {
|
it('should convert node to string', () => {
|
||||||
const node = new LinkedListNode({ value: 1 });
|
const node = new LinkedListNode(1);
|
||||||
const nodeWithKey = new LinkedListNode({ value: 1, key: 'test' });
|
|
||||||
|
|
||||||
expect(node.toString()).toBe('1');
|
expect(node.toString()).toBe('1');
|
||||||
expect(nodeWithKey.toString()).toBe('test:1');
|
|
||||||
|
node.value = 'string value';
|
||||||
|
expect(node.toString()).toBe('string value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert node to string with custom stringifier', () => {
|
||||||
|
const nodeValue = { value: 1, key: 'test' };
|
||||||
|
const node = new LinkedListNode(nodeValue);
|
||||||
|
const toStringCallback = value => `value: ${value.value}, key: ${value.key}`;
|
||||||
|
|
||||||
|
expect(node.toString(toStringCallback)).toBe('value: 1, key: test');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -18,11 +18,15 @@ export default class Queue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enqueue(value) {
|
enqueue(value) {
|
||||||
this.linkedList.append({ value });
|
this.linkedList.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dequeue() {
|
dequeue() {
|
||||||
const removedHead = this.linkedList.deleteHead();
|
const removedHead = this.linkedList.deleteHead();
|
||||||
return removedHead ? removedHead.value : null;
|
return removedHead ? removedHead.value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString(callback) {
|
||||||
|
return this.linkedList.toString(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,20 @@ describe('Queue', () => {
|
|||||||
queue.enqueue(1);
|
queue.enqueue(1);
|
||||||
queue.enqueue(2);
|
queue.enqueue(2);
|
||||||
|
|
||||||
expect(queue.linkedList.toString()).toBe('1,2');
|
expect(queue.toString()).toBe('1,2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be possible to enqueue/dequeue objects', () => {
|
||||||
|
const queue = new Queue();
|
||||||
|
|
||||||
|
queue.enqueue({ value: 'test1', key: 'key1' });
|
||||||
|
queue.enqueue({ value: 'test2', key: 'key2' });
|
||||||
|
|
||||||
|
const stringifier = value => `${value.key}:${value.value}`;
|
||||||
|
|
||||||
|
expect(queue.toString(stringifier)).toBe('key1:test1,key2:test2');
|
||||||
|
expect(queue.dequeue().value).toBe('test1');
|
||||||
|
expect(queue.dequeue().value).toBe('test2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should peek data from queue', () => {
|
it('should peek data from queue', () => {
|
||||||
|
@ -18,11 +18,15 @@ export default class Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
push(value) {
|
push(value) {
|
||||||
this.linkedList.append({ value });
|
this.linkedList.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pop() {
|
pop() {
|
||||||
const removedTail = this.linkedList.deleteTail();
|
const removedTail = this.linkedList.deleteTail();
|
||||||
return removedTail ? removedTail.value : null;
|
return removedTail ? removedTail.value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString(callback) {
|
||||||
|
return this.linkedList.toString(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ describe('Stack', () => {
|
|||||||
stack.push(1);
|
stack.push(1);
|
||||||
stack.push(2);
|
stack.push(2);
|
||||||
|
|
||||||
expect(stack.linkedList.toString()).toBe('1,2');
|
expect(stack.toString()).toBe('1,2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should peek data from stack', () => {
|
it('should peek data from stack', () => {
|
||||||
@ -49,4 +49,17 @@ describe('Stack', () => {
|
|||||||
expect(stack.pop()).toBeNull();
|
expect(stack.pop()).toBeNull();
|
||||||
expect(stack.isEmpty()).toBeTruthy();
|
expect(stack.isEmpty()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be possible to push/pop objects', () => {
|
||||||
|
const stack = new Stack();
|
||||||
|
|
||||||
|
stack.push({ value: 'test1', key: 'key1' });
|
||||||
|
stack.push({ value: 'test2', key: 'key2' });
|
||||||
|
|
||||||
|
const stringifier = value => `${value.key}:${value.value}`;
|
||||||
|
|
||||||
|
expect(stack.toString(stringifier)).toBe('key1:test1,key2:test2');
|
||||||
|
expect(stack.pop().value).toBe('test2');
|
||||||
|
expect(stack.pop().value).toBe('test1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user