Skip to content

Commit

Permalink
Move linked list traversals into separate section.
Browse files Browse the repository at this point in the history
  • Loading branch information
trekhleb committed Sep 8, 2018
1 parent 2feec48 commit 80ecbe0
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 60 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions src/algorithms/linked-list/reverse-traversal/README.md
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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();
// });
24 changes: 24 additions & 0 deletions src/algorithms/linked-list/reverse-traversal/reverseTraversal.js
Original file line number Diff line number Diff line change
@@ -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);
}
19 changes: 19 additions & 0 deletions src/algorithms/linked-list/traversal/README.md
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 22 additions & 0 deletions src/algorithms/linked-list/traversal/__test__/traversal.test.js
Original file line number Diff line number Diff line change
@@ -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]);
});
});
18 changes: 18 additions & 0 deletions src/algorithms/linked-list/traversal/traversal.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
34 changes: 0 additions & 34 deletions src/data-structures/linked-list/LinkedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
32 changes: 6 additions & 26 deletions src/data-structures/linked-list/__test__/LinkedList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
});
});

0 comments on commit 80ecbe0

Please sign in to comment.