diff --git a/README.md b/README.md index bc722406..334d48b0 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,9 @@ a set of rules that precisely define a sequence of operations. * `B` [Shellsort](src/algorithms/sorting/shell-sort) * `B` [Counting Sort](src/algorithms/sorting/counting-sort) * `B` [Radix Sort](src/algorithms/sorting/radix-sort) +* **Linked Lists** + * `B` [Straight Traversal](src/algorithms/linked-list/traversal) + * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal) * **Trees** * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS) diff --git a/src/algorithms/linked-list/reverse-traversal/README.md b/src/algorithms/linked-list/reverse-traversal/README.md new file mode 100644 index 00000000..89187e4f --- /dev/null +++ b/src/algorithms/linked-list/reverse-traversal/README.md @@ -0,0 +1,19 @@ +# Reversed Linked List Traversal + +The task is to traverse the given linked list in reversed order. + +For example for the following linked list: + +![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) + +The order of traversal should be: + +```text +37 → 99 → 12 +``` + +The time complexity is `O(n)` because we visit every node only once. + +## Reference + +- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) diff --git a/src/algorithms/linked-list/reverse-traversal/__test__/reverseTraversal.test.js b/src/algorithms/linked-list/reverse-traversal/__test__/reverseTraversal.test.js new file mode 100644 index 00000000..63ddb24c --- /dev/null +++ b/src/algorithms/linked-list/reverse-traversal/__test__/reverseTraversal.test.js @@ -0,0 +1,36 @@ +import LinkedList from '../../../../data-structures/linked-list/LinkedList'; +import reverseTraversal from '../reverseTraversal'; + +describe('reverseTraversal', () => { + it('should traverse linked list in reverse order', () => { + const linkedList = new LinkedList(); + + linkedList + .append(1) + .append(2) + .append(3); + + const traversedNodeValues = []; + const traversalCallback = (nodeValue) => { + traversedNodeValues.push(nodeValue); + }; + + reverseTraversal(linkedList, traversalCallback); + + expect(traversedNodeValues).toEqual([3, 2, 1]); + }); +}); + + +// 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(); +// }); diff --git a/src/algorithms/linked-list/reverse-traversal/reverseTraversal.js b/src/algorithms/linked-list/reverse-traversal/reverseTraversal.js new file mode 100644 index 00000000..d39260aa --- /dev/null +++ b/src/algorithms/linked-list/reverse-traversal/reverseTraversal.js @@ -0,0 +1,24 @@ +/** + * Traversal callback function. + * @callback traversalCallback + * @param {*} nodeValue + */ + +/** + * @param {LinkedListNode} node + * @param {traversalCallback} callback + */ +function reverseTraversalRecursive(node, callback) { + if (node) { + reverseTraversalRecursive(node.next, callback); + callback(node.value); + } +} + +/** + * @param {LinkedList} linkedList + * @param {traversalCallback} callback + */ +export default function reverseTraversal(linkedList, callback) { + reverseTraversalRecursive(linkedList.head, callback); +} diff --git a/src/algorithms/linked-list/traversal/README.md b/src/algorithms/linked-list/traversal/README.md new file mode 100644 index 00000000..25609518 --- /dev/null +++ b/src/algorithms/linked-list/traversal/README.md @@ -0,0 +1,19 @@ +# Linked List Traversal + +The task is to traverse the given linked list in straight order. + +For example for the following linked list: + +![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) + +The order of traversal should be: + +```text +12 → 99 → 37 +``` + +The time complexity is `O(n)` because we visit every node only once. + +## Reference + +- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) diff --git a/src/algorithms/linked-list/traversal/__test__/traversal.test.js b/src/algorithms/linked-list/traversal/__test__/traversal.test.js new file mode 100644 index 00000000..77ce79b6 --- /dev/null +++ b/src/algorithms/linked-list/traversal/__test__/traversal.test.js @@ -0,0 +1,22 @@ +import LinkedList from '../../../../data-structures/linked-list/LinkedList'; +import traversal from '../traversal'; + +describe('traversal', () => { + it('should traverse linked list', () => { + const linkedList = new LinkedList(); + + linkedList + .append(1) + .append(2) + .append(3); + + const traversedNodeValues = []; + const traversalCallback = (nodeValue) => { + traversedNodeValues.push(nodeValue); + }; + + traversal(linkedList, traversalCallback); + + expect(traversedNodeValues).toEqual([1, 2, 3]); + }); +}); diff --git a/src/algorithms/linked-list/traversal/traversal.js b/src/algorithms/linked-list/traversal/traversal.js new file mode 100644 index 00000000..cfbfe4fb --- /dev/null +++ b/src/algorithms/linked-list/traversal/traversal.js @@ -0,0 +1,18 @@ +/** + * Traversal callback function. + * @callback traversalCallback + * @param {*} nodeValue + */ + +/** + * @param {LinkedList} linkedList + * @param {traversalCallback} callback + */ +export default function traversal(linkedList, callback) { + let currentNode = linkedList.head; + + while (currentNode) { + callback(currentNode.value); + currentNode = currentNode.next; + } +} diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index d98b6284..e256b1fe 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -208,40 +208,6 @@ export default class LinkedList { 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 linked list. * @returns {LinkedList} diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index 32290145..3a4241c9 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -218,31 +218,6 @@ describe('LinkedList', () => { 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 linked list', () => { const linkedList = new LinkedList(); @@ -258,9 +233,14 @@ describe('LinkedList', () => { // Reverse linked list. linkedList.reverse(); - expect(linkedList.toString()).toBe('3,2,1'); expect(linkedList.head.value).toBe(3); expect(linkedList.tail.value).toBe(1); + + // Reverse linked list back to initial state. + linkedList.reverse(); + expect(linkedList.toString()).toBe('1,2,3'); + expect(linkedList.head.value).toBe(1); + expect(linkedList.tail.value).toBe(3); }); });