From 4989a6a3b018501df52031950716f6cdc6febf60 Mon Sep 17 00:00:00 2001 From: "Hanh D. TRAN" Date: Sat, 8 Sep 2018 17:55:51 +0900 Subject: [PATCH] Add LinkedList traversal and reverse implementations (#194) * Add LinkedList traverse function * Add LinkedList reverse traversal implementations * Update LinkedList traverse function * Update LinkedList reverse traversal and test cases * Update LinkedList traversal tests --- src/data-structures/linked-list/LinkedList.js | 62 +++++++++++++++++++ src/data-structures/linked-list/README.md | 10 +-- .../linked-list/__test__/LinkedList.test.js | 37 +++++++++++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index dfb17aaf..15b54e25 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -207,4 +207,66 @@ export default class LinkedList { toString(callback) { return this.toArray().map(node => node.toString(callback)).toString(); } + + /** + * Traverse through all nodes of the list from head to tail + * @param {*} callback + * @return {LinkedListNode[]} + */ + traverse(callback = undefined) { + if (typeof callback !== 'function') { + throw new TypeError(`traverse method requires a callback function as an argument.\nArgument given: ${typeof callback}`); + } + + let currentNode = this.head; + const traversedNodes = []; + + while (currentNode) { + traversedNodes.push(callback(currentNode.value)); + currentNode = currentNode.next; + } + + return traversedNodes; + } + + /** + * The items in the list have been traversed in reverse order + */ + reverseTraversal(node, callback = undefined) { + if (typeof callback !== 'function') { + throw new TypeError(`reverseTraverse method requires a callback function as an argument.\nArgument given: ${typeof callback}`); + } + + if (!node) return []; + + return this.reverseTraversal(node.next, callback).concat(callback(node.value)); + } + + /** + * Reverse a singly linked list use to three variables + * @returns {ReservedLinkedList} + */ + reverse() { + let currNode = this.head; + let prevNode = null; + let nextNode = null; + + while (currNode) { + // Store next node + nextNode = currNode.next; + + // Change next node of the current + currNode.next = prevNode; + + // Move forward prev and current nodes one step + prevNode = currNode; + currNode = nextNode; + } + + // Reset head, tail + this.tail = this.head; + this.head = prevNode; + + return this; + } } diff --git a/src/data-structures/linked-list/README.md b/src/data-structures/linked-list/README.md index 8f1a46c8..bb0ad476 100644 --- a/src/data-structures/linked-list/README.md +++ b/src/data-structures/linked-list/README.md @@ -110,24 +110,24 @@ Traverse(head) Pre: head is the head node in the list Post: the items in the list have been traversed n ← head - while n = 0 + while n != ø yield n.value n ← n.next end while end Traverse ``` - + ### Traverse in Reverse ```text ReverseTraversal(head, tail) Pre: head and tail belong to the same list Post: the items in the list have been traversed in reverse order - if tail = ø + if tail != ø curr ← tail - while curr = head + while curr != head prev ← head - while prev.next = curr + while prev.next != curr prev ← prev.next end while yield curr.value diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index 795bb247..f88891cb 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -217,4 +217,41 @@ describe('LinkedList', () => { expect(node.value.customValue).toBe('test2'); expect(linkedList.find({ value: 2, customValue: 'test5' })).toBeNull(); }); + + it('should traverse through all nodes of the list from head to tail with callback', () => { + const linkedList = new LinkedList(); + + linkedList + .append(1) + .append(2) + .append(3); + + expect(linkedList.traverse(value => value * 2)).toEqual([2, 4, 6]); + expect(() => linkedList.traverse()).toThrow(); + }); + + it('should reverse traversal the linked list with callback', () => { + const linkedList = new LinkedList(); + + linkedList + .append(1) + .append(2) + .append(3); + + expect(linkedList.toString()).toBe('1,2,3'); + expect(linkedList.reverseTraversal(linkedList.head, value => value * 2)).toEqual([6, 4, 2]); + expect(() => linkedList.reverseTraversal(linkedList.head)).toThrow(); + }); + + it('should reverse the singly linked list', () => { + const linkedList = new LinkedList(); + + linkedList + .append(1) + .append(2) + .append(3); + + expect(linkedList.toString()).toBe('1,2,3'); + expect(linkedList.reverse().toString()).toBe('3,2,1'); + }); });