Last active
October 31, 2015 08:24
-
-
Save softwarespot/d94d7bd161632589cc72 to your computer and use it in GitHub Desktop.
A linked list in JavaScript with ES2015
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note: Save as linkedlist.js and run 'babel-node linkedlist.js' to display in the command window. This is written in ES2015 | |
((global) => { | |
// Return strings of toString() found on the Object prototype | |
// Based on the implementation by lodash inc. is* function as well | |
const _objectStrings = { | |
BOOLEAN: '[object Boolean]', | |
}; | |
// Store a reference of the toString function on the Object prototype chain | |
const _objectToString = global.Object.prototype.toString; | |
/** | |
* LinkedList interface | |
*/ | |
function LinkedList() { | |
this.head = null; | |
} | |
/** | |
* LinkedList node interface | |
* @param {mixed} data Data to store in the node | |
*/ | |
function LinkedListNode(data) { | |
this.data = data; | |
this.next = null; | |
} | |
/** | |
* Append functions to the LinkedList prototype chain | |
* @type {object} | |
*/ | |
LinkedList.prototype = { | |
/** | |
* Insert either a primitive data e.g. number, string etc... or a LinkedListNode | |
* | |
* @param {LinkedListNode|mixed} data A primitive datatype e.g. number, string etc... or a LinkedListNode object reference | |
* @return {LinkedList} LinkedList object reference | |
*/ | |
insert: (data) => { | |
// Create a new node if data is not an object reference of this.node | |
const node = _isNode(data) ? data : new LinkedListNode(data); | |
// If the head is already assigned with a node reference, then set the newly created node above | |
// to point to the head's node reference | |
if (this.head !== null) { | |
node.next = this.head; | |
} | |
// Set the head to point to the newly create node reference | |
this.head = node; | |
return this; | |
}, | |
// Helper functions | |
/** | |
* Get the number of nodes in the linked list | |
* | |
* @return {number} Number of node object references in the linked list | |
*/ | |
count: () => { | |
let length = 0; | |
let node = this.head; | |
while (node !== null) { | |
node = node.next; | |
length++; | |
} | |
return length; | |
}, | |
/** | |
* Get a node object reference (cloned or not) at a particular index value. | |
* If less than zero or out of bounds, null will be returned instead | |
* | |
* @param {number} index Index value | |
* @param {boolean} clone True clone the node; otherwise, false | |
* @return {LinkedListNode|null} The linked list node; otherwise, null | |
*/ | |
get: (index, clone) => { | |
// Invalid index value | |
if (index < 0) { | |
return null; | |
} | |
// Set to true by default if not a boolean type | |
if (!_isBoolean(clone)) { | |
clone = true; | |
} | |
let count = 0; | |
let node = this.head; | |
while (node !== null) { | |
// Return the node at the specified index | |
if (index === count) { | |
// Clone the node or return the node object reference | |
return clone ? new LinkedListNode(node.data) : node; | |
} | |
// Get the next node | |
node = node.next; | |
count++; | |
} | |
// Out of bounds index | |
return null; | |
}, | |
/** | |
* Reverse a linked list | |
* | |
* @return {LinkedList} LinkedList object reference | |
*/ | |
reverse: () => { | |
let node = this.head; | |
let next = null; | |
let previous = null; | |
while (node !== null) { | |
next = node.next; | |
node.next = previous; | |
previous = node; | |
node = next; | |
} | |
this.head = previous; | |
return this; | |
}, | |
/** | |
* Display the linked list contents by passing the node data to the callback function | |
* | |
* @param {function} callback Callback function to pass the data property of the node to | |
* @return {LinkedList} LinkedList object reference | |
*/ | |
print: (callback) => { | |
// Store the head node temporarily | |
let node = this.head; | |
while (node !== null) { | |
// Print to the console | |
callback(node.data); | |
// Get the next node | |
node = node.next; | |
} | |
return this; | |
}, | |
}; | |
// Methods (private) | |
/** | |
* Check if a variable is a boolean datatype | |
* | |
* @param {mixed} value Value to check | |
* @returns {boolean} True, the value is a boolean datatype; otherwise, false | |
*/ | |
function _isBoolean(value) { | |
return value === true || value === false || (_isObjectLike(value) && _objectToString.call(value) === _objectStrings.BOOLEAN); | |
} | |
/** | |
* Check of a variable is linked list node | |
* | |
* @param {LinkedListNode} node Value to check | |
* @return {boolean} True, the value is a node; otherwise, false | |
*/ | |
function _isNode(node) { | |
return node !== null && // If not null | |
_isObjectLike(node) && // An object datatype | |
node.hasOwnProperty('data') && // Has the data property | |
node.hasOwnProperty('next'); // Has the next property | |
} | |
/** | |
* Check if a variable is an object | |
* | |
* @param {mixed} value Value to check | |
* @returns {boolean} True, the value is an object; otherwise, false | |
*/ | |
function _isObjectLike(value) { | |
return !!value && typeof value === 'object'; | |
} | |
// Example | |
(() => { | |
// Create a linked list | |
const list = new LinkedList(); | |
// Add primitive datatypes e.g. string, number to the linked list | |
list.insert('Some data 1'); | |
list.insert('Some data 2'); | |
list.insert('Some data 3'); | |
// Add a new object reference of a linked list node | |
list.insert(new LinkedListNode('Some data 4')); | |
// Display the number of nodes in the linked list | |
global.console.log('LinkedList count: ', list.count()); | |
// Get the linked list node at the index position 1. Note: The index count starts from zero | |
global.console.log('LinkedList index at 1: ', global.JSON.stringify(list.get(1, true))); | |
// Get the linked list node at 100th position (Note: It will return null as there are only 4 nodes in the linked list) | |
global.console.log('LinkedList index at 100: ', list.get(100)); | |
// Display the contents of the linked list before reversal | |
global.console.log('LinkedList print: . . .'); | |
list.print(global.console.log); | |
// Reverse the linked list | |
list.reverse(); | |
// Display the contents of the linked list after reversal | |
global.console.log('LinkedList print: . . .'); | |
list.print(global.console.log); | |
})(); | |
})(window); // An IIFE for function scope i.e. creating a namespace |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment