Doublie
⚡ Doubly circular & linear linked lists for ES6
Description
Progressive implementation of the circular and linear doubly linked list data structures in ES6 with TypeScript support.
Come over to Twitter to share your thoughts on the project.
Visit the contributing guidelines to learn more on how to translate this document into more languages.
Contents
Install
Yarn
yarn add doublie
NPM
npm install doublie
Usage
Doublie exposes a progressive and composable API, that can be utilized through a simple and minimal syntax, allowing you to combine and chain methods effectively.
Usage examples can be also found at the test
directory.
'use strict';
const {Circular, Linear} = require('doublie');
const linear = new Linear();
linear.prepend('A').append('B');
linear.head;
linear.head.next;
linear.head.next.next;
linear.head.prev;
linear.map(x => `[${x}]`).reverse().join(' -> ');
const circular = new Circular();
circular.append(2).prepend(1);
circular.head;
circular.head.next;
circular.head.next.next;
circular.head.prev;
circular.reduce((x, y) => x > y ? x : y, -Infinity);
In Depth
Linear Doubly Linked List
Linear doubly linked lists can contain multiple nodes, where each node has only a value
, a prev
and next
attribute. The value
attribute holds the value stored inside of the node and the prev
& next
attributes point to the previous and next nodes in line respectively. The only exceptions are that the first node of the list has null
stored to its prev
attribute, indicating the lack of nodes before it, thus the beginning of the list, and the last node has null
stored to its next
attribute, indicating the lack of further nodes down the line, thus the end of the list.
The following example demonstrates the operations that can be performed on any linear doubly linked list.
'use strict';
const {Linear} = require('doublie');
const linear = new Linear();
linear.append('E');
linear.head;
linear.last;
linear.get(0);
linear.node(0);
linear.node(0).value;
linear.node(0).next;
linear.node(0).prev;
linear.append('F', 'G');
linear.length;
linear.node(0).next.value;
linear.node(0).next.next.value;
linear.toArray();
linear.prepend('B', 'A');
linear.join(' ');
linear.insert({value: ['D', 'C', 'X'], index: 2});
linear.join(' ');
linear.remove(2);
linear.join(' ');
linear.node(linear.length - 1).value = '!';
linear.join(' ');
linear.set({value: 'G', index: linear.length - 1});
linear.join(' ');
const array = [];
linear.forEach(x => array.push(x));
linear.reverse().map(x => `[${x}]`).join('->');
linear.clear();
linear.append(5, 10, 15, 20, 25).reduce((x, y) => x + y, 0);
Circular Doubly Linked List
Circular doubly linked lists can also contain multiple nodes, where again each node has the same value
, prev
and next
attributes. The only difference compared to linear lists, is that the last node always points back to the first node/head of the list, and similarly the first node/head points back to the last node of the list, thus the list is said to be circular or circularly linked.
The following example demonstrates the operations that can be performed on any circular doubly linked list.
'use strict';
const {Circular} = require('doublie');
const circular = new Circular();
circular.append('E');
circular.head;
circular.last;
circular.get(0);
circular.node(0);
circular.node(0).value;
circular.node(0).next.value;
circular.node(0).next.next.value;
circular.node(0).prev.value;
circular.node(0).prev.prev.value;
circular.append('F', 'G');
circular.length;
circular.node(0).next.value;
circular.node(0).next.next.value;
circular.node(0).next.next.next.value;
circular.node(0).prev.value;
circular.node(0).prev.prev.value;
circular.node(0).prev.prev.prev.value;
circular.toArray();
circular.prepend('B', 'A');
circular.join(' ');
circular.insert({value: ['D', 'C', 'X'], index: 2});
circular.join(' ');
circular.remove(2);
circular.join(' ');
circular.node(circular.length - 1).value = '!';
circular.join(' ');
circular.set({value: 'G', index: circular.length - 1});
circular.join(' ');
const array = [];
circular.forEach(x => array.push(x));
circular.reverse().map(x => `[${x}]`).join('->');
circular.clear();
circular.append(5, 10, 15, 20, 25).reduce((x, y) => x + y, 0);
API
The following documentation holds for both circular & linear lists. The described list
instance is used to depict the same methods that are applicable to both a linear and a circular linked list, without overlooking their above described differences and unique qualities.
list.append(value[, value])
Appends one of more nodes to the list.
value
Can be one or more comma delimited values. Each value corresponds to a single node.
list.append('A', 'B', 'C', 'D');
list.prepend(value[, value])
Prepends one of more nodes to the list.
value
Can be one or more comma delimited values. Each value corresponds to a single node.
list.append('C' , 'D');
list.prepend('B', 'A');
list.head
Returns the first node / head on the list.
list.append('A', 'B');
list.head;
list.last
Returns the last node on the list.
list.append('A', 'B');
list.last;
list.length
Returns the length of the list.
list.append('A', 'B');
list.length;
list.isEmpty()
Checks whether or not the list is empty.
list.append('A', 'B');
list.isEmpty();
list.insert({value[, value], index})
Inserts one or more nodes to the given index.
value
Can be one or more comma delimited values. Each value corresponds to a single node.
index
Can be an integer corresponding to a list index.
list.append('A', 'B', 'E');
list.insert({value: ['C', 'D'], index: 1});
list.node(index)
Return the node corresponding to the given index.
index
Can be an integer corresponding to a list index.
list.append('A', 'B', 'C', 'D');
const node = list.node(0);
node.value;
node.next;
list.get(index)
Return the value of node corresponding to the given index.
index
Can be an integer corresponding to a list index.
list.append('A', 'B');
list.get(0);
list.get(0);
list.remove(index)
Removes from the list the node located to the given index.
index
Can be an integer corresponding to a list index.
If not provided, the last node of the list will be removed.
list.append('A', 'B', 'C', 'D');
list.remove(0);
list.remove(0);
list.toArray()
Converts the list into an array.
list.append('A', 'B', 'C');
const array = list.toArray();
list.clear()
Removes all nodes from the list.
list.append('A', 'B', 'C');
list.head;
list.clear();
list.join([separator])
Joins the values of all nodes on the list into a string and returns the string.
separator
- Type:
String
- Default:
Comma ','
Specifies a string to separate each pair of adjacent node values of the array.
If omitted, the node values are separated with a comma ','
.
list.append('A', 'B', 'C');
list.join();
list.join('');
list.join(' ');
list.forEach(function)
Executes a provided function once for each node value.
function
Function to execute for each node value.
const array = [];
list.append('A', 'B', 'C');
list.forEach(x => array.push(x));
console.log(array);
list.map(function)
Executes a provided function once for each node value.
function
Function that produces a new node value for the new list.
list.append('A', 'B', 'C');
const mapped = list.map(x => `[${x}]`);
array.join(' ');
list.filter(function)
Creates a new liked list with all elements that pass the test implemented by the provided function.
function
Function is a predicate, to test each element of the list. Return true to keep the element, false otherwise.
list.append(1, 2, 3, 4, 5, 6);
const filtered = list.filter(x => x % 2 > 0);
filtered.toArray();
list.reduce(function, initialValue)
Executes a reducer function on each member of the list resulting in a single output value.
function
The reducer function takes two arguments: accumulator & current value. The reducer function's returned value is assigned to the accumulator, whose value is remembered across each iteration throughout the list and ultimately becomes the final, single resulting value.
list.append(20, 50, 35, 41, 5, 67);
list.reduce((acc, x) => acc > x ? acc : x, -Infinity);
list.reduceRight(function, initialValue)
Executes a reducer function on each member of the list, from right-to-left, resulting in a single output value.
function
The reducer function takes two arguments: accumulator & current value. The reducer function's returned value is assigned to the accumulator, whose value is remembered across each iteration throughout the list and ultimately becomes the final, single resulting value.
list.append('A', 'B', 'C', 'D', 'E', 'F');
list.reduceRight((acc, x) => acc + x, '');
list.includes(value)
The method determines whether a list, circular or linear, includes a certain value among its nodes, returning true
or false
as appropriate.
value
The value to search for.
list.append(20, 50, 35, 41, 5, 67);
list.includes();
list.includes(0);
list.includes(50);
list.indexOf(value)
The method returns the first index at which a given element can be found in the circular/linear linked list, or -1 if it is not present.
value
Element to locate in the array.
list.append(20, 50, 35, 41, 5, 67);
list.indexOf();
list.indexOf(0);
list.indexOf(41);
list.toString()
Returns a string representing the specified list and its elements.
list.append(20, 50, 35, 41, 5, 67);
list.isCircular()
Returns true
if the linked list is circular or false
if it is linear.
const {Circular} = require('doublie');
const list = new Circular();
list.isCircular();
list.isLinear()
Returns true
if the linked list is linear or false
if it is circular.
const {Circular} = require('doublie');
const list = new Circular();
list.isLinear();
linear.toCircular()
- Return Type:
Circular Linked List
Returns a new circular linked list containing all elements of the original linear linked list.
const {Linear} = require('doublie');
const list = new Linear();
list.toCircular().isLinear();
circular.toLinear()
- Return Type:
Linear Linked List
Returns a new linear linked list containing all elements of the original circular linked list.
const {Circular} = require('doublie');
const list = new Circular();
list.toLinear().isLinear();
Also available, along with the Circular
and Linear
exposed classes, is the Node
class, mainly useful for testing purposes, since it can be utilized to compare nodes residing in linear & circular linked lists. The class has a unary constructor method, with a 'value'
parameter, corresponding to the data stored in the created instance.
Additionally, each Node
instance has the following two public properties:
node.value
The value that the node contains.
const {Node} = require('doublie');
const node = new Node('A');
node.value;
node.value = 'B'
node.prev
The previous node in line, that the node instance points to.
const {Node} = require('doublie');
const node1 = new Node('A');
node1.prev
const node2 = new Node('B');
node1.prev = node2;
node.next
The next node in line, that the node instance points to.
const {Node} = require('doublie');
const node1 = new Node('A');
node1.next
const node2 = new Node('B');
node1.next = node2;
Development
For more info on how to contribute to the project, please read the contributing guidelines.
- Fork the repository and clone it to your machine
- Navigate to your local fork:
cd doublie
- Install the project dependencies:
npm install
or yarn install
- Lint the code and run the tests:
npm test
or yarn test
Related
- singlie - Singly circular & linear linked lists for ES6
Team
License
MIT