From 3303051d75056da20a839314bc59f08d3ce73ac7 Mon Sep 17 00:00:00 2001 From: Yair Temkin Date: Fri, 28 Jan 2022 15:26:39 -0500 Subject: [PATCH] Inserting, removing, accessing, modifying, by index, on linked list with tests --- src/data-structures/linked-list/LinkedList.js | 76 +++++++++++++++- .../linked-list/__test__/LinkedList.test.js | 88 ++++++++++++++++--- 2 files changed, 150 insertions(+), 14 deletions(-) diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index ba7d0e3e..f3e429d4 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -87,6 +87,28 @@ export default class LinkedList { } return this; } + /** + * @param {*} value + * @param {number} index + * @return {LinkedList} + */ + setAtIndex(value, index) { + if (index < 0) { + return this; + } else { + let count = 0; + let currentNode = this.head; + while (currentNode) { + if (count === index) break; + currentNode = currentNode.next; + count += 1; + } + if (currentNode) { + currentNode.value = value; + } + return this; + } + } /** * @param {*} value @@ -128,6 +150,36 @@ export default class LinkedList { return deletedNode; } + /** + * @param {number} index + * @return {LinkedListNode} + */ + deleteAtIndex(index) { + if (!this.head || index < 0) { + return null; + } + let deletedNode = null; + if (index === 0) { + deletedNode = this.head; + this.head = this.head.next; + } else { + let count = 1; + let currentNode = this.head; + while (currentNode) { + if (count === index) break; + currentNode = currentNode.next; + count += 1; + } + if (currentNode) { + deletedNode = currentNode.next; + if (deletedNode) { + currentNode.next = deletedNode.next; + } + } + } + return deletedNode; + } + /** * @param {Object} findParams * @param {*} findParams.value @@ -158,6 +210,26 @@ export default class LinkedList { return null; } + /** + * @param {*} index + * @return {LinkedListNode} + */ + findByIndex(index) { + if (!this.head || index < 0) { + return null; + } else if (index === 0) { + return this.head; + } + let count = 0; + let currentNode = this.head; + while (currentNode) { + if (count === index) break; + currentNode = currentNode.next; + count += 1; + } + return currentNode; + } + /** * @return {LinkedListNode} */ @@ -239,7 +311,9 @@ export default class LinkedList { * @return {string} */ toString(callback) { - return this.toArray().map((node) => node.toString(callback)).toString(); + return this.toArray() + .map((node) => node.toString(callback)) + .toString(); } /** diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index 6ac41ddf..9bce6bcf 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -47,6 +47,26 @@ describe('LinkedList', () => { expect(linkedList.toString()).toBe('1,4,2,3,10'); }); + it('should insert node to linked list', () => { + const linkedList = new LinkedList(); + + linkedList.append(1).append(2).append(3).append(4).append(5); + + expect(linkedList.toString()).toBe('1,2,3,4,5'); + + linkedList.setAtIndex(5, -2); + expect(linkedList.toString()).toBe('1,2,3,4,5'); + + linkedList.setAtIndex(12, 3); + expect(linkedList.toString()).toBe('1,2,3,12,5'); + + linkedList.setAtIndex(55, 0); + expect(linkedList.toString()).toBe('55,2,3,12,5'); + + linkedList.setAtIndex(0, 55); + expect(linkedList.toString()).toBe('55,2,3,12,5'); + }); + it('should delete node by value from linked list', () => { const linkedList = new LinkedList(); @@ -93,6 +113,34 @@ describe('LinkedList', () => { expect(linkedList.toString()).toBe(''); }); + it('should delete node at index from linked list', () => { + const linkedList = new LinkedList(); + + expect(linkedList.delete(5)).toBeNull(); + + linkedList.append(1); + linkedList.append(2); + linkedList.append(3); + linkedList.append(4); + linkedList.append(5); + + expect(linkedList.head.toString()).toBe('1'); + expect(linkedList.tail.toString()).toBe('5'); + + let deletedNode = linkedList.deleteAtIndex(3); + expect(deletedNode.value).toBe(4); + expect(linkedList.toString()).toBe('1,2,3,5'); + + linkedList.deleteAtIndex(1); + expect(linkedList.toString()).toBe('1,3,5'); + + deletedNode = linkedList.delete(-5); + expect(deletedNode).toBeNull(); + + deletedNode = linkedList.delete(10); + expect(deletedNode).toBeNull(); + }); + it('should delete linked list tail', () => { const linkedList = new LinkedList(); @@ -157,9 +205,7 @@ describe('LinkedList', () => { const nodeValue1 = { value: 1, key: 'key1' }; const nodeValue2 = { value: 2, key: 'key2' }; - linkedList - .append(nodeValue1) - .prepend(nodeValue2); + linkedList.append(nodeValue1).prepend(nodeValue2); const nodeStringifier = (value) => `${value.key}:${value.value}`; @@ -174,9 +220,7 @@ describe('LinkedList', () => { linkedList.append(1); expect(linkedList.find({ value: 1 })).toBeDefined(); - linkedList - .append(2) - .append(3); + linkedList.append(2).append(3); const node = linkedList.find({ value: 2 }); @@ -184,6 +228,21 @@ describe('LinkedList', () => { expect(linkedList.find({ value: 5 })).toBeNull(); }); + it('should find node by index', () => { + const linkedList = new LinkedList(); + + expect(linkedList.findByIndex(5)).toBeNull(); + linkedList.append(1); + expect(linkedList.findByIndex(0).value).toBe(1); + + linkedList.append(2).append(3); + + const node = linkedList.findByIndex(2); + expect(node.value).toBe(3); + expect(linkedList.findByIndex(5)).toBeNull(); + expect(linkedList.findByIndex(-3)).toBeNull(); + }); + it('should find node by callback', () => { const linkedList = new LinkedList(); @@ -192,12 +251,16 @@ describe('LinkedList', () => { .append({ value: 2, key: 'test2' }) .append({ value: 3, key: 'test3' }); - const node = linkedList.find({ callback: (value) => value.key === 'test2' }); + 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(); + expect( + linkedList.find({ callback: (value) => value.key === 'test5' }) + ).toBeNull(); }); it('should create linked list from array', () => { @@ -230,7 +293,9 @@ describe('LinkedList', () => { expect(node).toBeDefined(); expect(node.value.value).toBe(2); expect(node.value.customValue).toBe('test2'); - expect(linkedList.find({ value: { value: 2, customValue: 'test5' } })).toBeNull(); + expect( + linkedList.find({ value: { value: 2, customValue: 'test5' } }) + ).toBeNull(); }); it('should find preferring callback over compare function', () => { @@ -258,10 +323,7 @@ describe('LinkedList', () => { const linkedList = new LinkedList(); // Add test values to linked list. - linkedList - .append(1) - .append(2) - .append(3); + linkedList.append(1).append(2).append(3); expect(linkedList.toString()).toBe('1,2,3'); expect(linkedList.head.value).toBe(1);