/** * Linked list. * * @example * * var LL = require('path-to-algorithms/src/data-structures/linked-list'); * * var linkedList = new LL.LinkedList(); * * linkedList.push({ * name: 'John', * birthyear: 1981 * }); * linkedList.push({ * name: 'Pavlo', * birthyear: 2000 * }); * linkedList.push({ * name: 'Garry', * birthyear: 1989 * }); * linkedList.push({ * name: 'Derek', * birthyear: 1990 * }); * linkedList.push({ * name: 'Ivan', * birthyear: 1966 * }); * * console.log(linkedList.shift().data); // { name: 'John', birthyear: 1981 } * console.log(linkedList.pop().data); // { name: 'Ivan', birthyear: 1966 } * * @module data-structures/linked-list */ (function (exports) { 'use strict'; /** * Linked list node. * * @public * @constructor * @param {Object} data Data of the node. */ exports.Node = function (data) { /** * Data of the node. * @member {Object} */ this.data = data; /** * Next node. * @member {Node} */ this.next = null; /** * Previous node. * @member {Node} */ this.prev = null; }; /** * Linked list. * * @public * @constructor */ exports.LinkedList = function () { this.first = null; this.last = null; }; /** * Add data to the end of linked list. * * @public * @method * @param {Object} data Data which should be added. */ exports.LinkedList.prototype.push = function (data) { var node = new exports.Node(data); if (this.first === null) { this.first = this.last = node; } else { var temp = this.last; this.last = node; node.prev = temp; temp.next = node; } }; /** * Add data to the beginning of linked list. * * @public * @method * @param {Object} data Data which should be added. */ exports.LinkedList.prototype.unshift = function (data) { var node = new exports.Node(data); if (this.first === null) { this.first = this.last = node; } else { var temp = this.first; this.first = node; node.next = temp; temp.prev = node; } }; /** * In order traversal of the linked list. * * @public * @method * @param {Function} cb Callback which should be executed on each node. */ exports.LinkedList.prototype.inorder = function (cb) { var temp = this.first; while (temp) { cb(temp); temp = temp.next; } }; /** * Remove data from the linked list. * * @public * @method * @param {Object} data Data which should be removed. * @return {Boolean} Returns true if data has been removed. */ exports.LinkedList.prototype.remove = function (data) { if (this.first === null) { return false; } var temp = this.first; var next; var prev; while (temp) { if (temp.data === data) { next = temp.next; prev = temp.prev; if (next) { next.prev = prev; } if (prev) { prev.next = next; } if (temp === this.first) { this.first = next; } if (temp === this.last) { this.last = prev; } return true; } temp = temp.next; } return false; }; /** * Check if linked list contains cycle. * * @public * @method * @return {Boolean} Returns true if linked list contains cycle. */ exports.LinkedList.prototype.hasCycle = function () { var fast = this.first; var slow = this.first; while (true) { if (fast === null) { return false; } fast = fast.next; if (fast === null) { return false; } fast = fast.next; slow = slow.next; if (fast === slow) { return true; } } }; /** * Return last node from the linked list. * * @public * @method * @return {Node} Last node. */ exports.LinkedList.prototype.pop = function () { if (this.last === null) { return null; } var temp = this.last; this.last = this.last.prev; return temp; }; /** * Return first node from the linked list. * * @public * @method * @return {Node} First node. */ exports.LinkedList.prototype.shift = function () { if (this.first === null) { return null; } var temp = this.first; this.first = this.first.next; return temp; }; /** * Reverses the linked list recursively * * @public * @method */ exports.LinkedList.prototype.recursiveReverse = function () { function inverse(current, next) { if (!next) { return; } inverse(next, next.next); next.next = current; } if (!this.first) { return; } inverse(this.first, this.first.next); this.first.next = null; var temp = this.first; this.first = this.last; this.last = temp; }; /** * Reverses the linked list iteratively * * @public * @method */ exports.LinkedList.prototype.reverse = function () { if (!this.first || !this.first.next) { return; } var current = this.first.next; var prev = this.first; var temp; while (current) { temp = current.next; current.next = prev; prev.prev = current; prev = current; current = temp; } this.first.next = null; this.last.prev = null; temp = this.first; this.first = prev; this.last = temp; }; })(typeof window === 'undefined' ? module.exports : window);