first commit
This commit is contained in:
39
build/node_modules/dbly-linked-list/.circleci/config.yml
generated
vendored
Normal file
39
build/node_modules/dbly-linked-list/.circleci/config.yml
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Javascript Node CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
|
||||
#
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
# specify the version you desire here
|
||||
- image: circleci/node:7.10
|
||||
|
||||
# Specify service dependencies here if necessary
|
||||
# CircleCI maintains a library of pre-built images
|
||||
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||
# - image: circleci/mongo:3.4.4
|
||||
|
||||
working_directory: ~/projects/doubly-linked-list
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v1-dependencies-
|
||||
|
||||
- run: yarn install
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
|
||||
# run tests!
|
||||
- run: yarn test
|
||||
|
||||
|
||||
7
build/node_modules/dbly-linked-list/.eslintrc.json
generated
vendored
Normal file
7
build/node_modules/dbly-linked-list/.eslintrc.json
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "eslint:recommended",
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true
|
||||
}
|
||||
}
|
||||
22
build/node_modules/dbly-linked-list/LICENSE-MIT
generated
vendored
Normal file
22
build/node_modules/dbly-linked-list/LICENSE-MIT
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Doubly Linked List: Javascript implementation of doubly linked list data
|
||||
structure
|
||||
|
||||
Copyright (C) 2015 Jason S. Jones
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
246
build/node_modules/dbly-linked-list/README.md
generated
vendored
Normal file
246
build/node_modules/dbly-linked-list/README.md
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
[![npm pkg][npm-image]][npm-url]
|
||||
[![Build Status][circleci-image]][circleci-url]
|
||||
[![dependency status][dm-image]][dm-url]
|
||||
[![devDependency status][devdep-image]][devdep-url]
|
||||
[]()
|
||||
|
||||
# Doubly Linked List
|
||||
|
||||
## Description
|
||||
|
||||
This is a javascript implementation of a [doubly linked
|
||||
list](http://en.wikipedia.org/wiki/Linked_list) data structure.
|
||||
|
||||
In simple terms, a doubly linked list consists of one or more 'nodes'. Each
|
||||
node has a data field (which can contain any data--a primitive value or complex
|
||||
object) and a pointer to the next 'node' and the previous 'node'. This
|
||||
additional pointer to the previous node is what distinguishes a doubly linked
|
||||
list from a singly linked list--a singly linked list only contains a pointer,
|
||||
or reference, to the next node. The major advantage to having pointers to
|
||||
both the next and previous node is that the list can be traversed in both
|
||||
directions, as well as making operations that operate on the 'middle' of
|
||||
the list a bit more efficient since each node has a reference the one
|
||||
before it and the one after it. The idea of having a links to the
|
||||
previous and next nodes is where this data structure got its descriptive
|
||||
name.
|
||||
|
||||
This implementation provides basic functionality of adding nodes to the front
|
||||
or back of the list, as well as the ability to insert a node at a given
|
||||
position in the list. It also provides the ability to remove nodes at the
|
||||
front or back of the list, or from any given position.
|
||||
|
||||
The find, or search, functionality provides the ability to find the first node
|
||||
containing specified data. It also provides the ability to find a node given a
|
||||
specific position, or index, in the list.
|
||||
|
||||
### Advantages
|
||||
|
||||
- List will grow dynamically with each node added; no requirement to
|
||||
'resize' list when it reaches a certain size, saving considerable overhead
|
||||
in 'house-keeping' operations.
|
||||
- Flexibility to add or remove nodes at the beginning or end of the list in
|
||||
O(1) time. This is a significant improvement over its
|
||||
[singly linked list](https://github.com/jasonsjones/singly-linked-list)
|
||||
counterpart.
|
||||
|
||||
### Disadvantages
|
||||
|
||||
- All 'find' operations take O(n) time to iterate over the list to find the
|
||||
requested node. This is the case for both the singly and doubly linked
|
||||
list.
|
||||
|
||||
*For specific examples and documentation, see the below sections*
|
||||
|
||||
### Motivation:
|
||||
|
||||
The main purpose of this project is revisit the basics, and focus on the
|
||||
development process.
|
||||
|
||||
*I wholehearedly acknowledge that the basic data structure space is populated
|
||||
with well-written code and efficient implementations, and one could easily grab
|
||||
one of those libraries and integrate it in their project. However, the main
|
||||
difference between those libraries/implementations and this one is that this is
|
||||
the best implementation I have ever written. My hope is that someone else will
|
||||
find this useful, but understand, this code is not the goal; this will simply
|
||||
be a useful bi-product of the journey. The underlying motivation is to
|
||||
understand and, more importantly, learn from the process to get to the desired
|
||||
end-state—for me it is all about the joy of the journey.*
|
||||
|
||||
#### Environment:
|
||||
|
||||
Although this implementation is designed to be used with
|
||||
[Node.js](http://www.nodejs.org), it could be used in other contexts with minor
|
||||
modifications. This implementation does not have any external dependencies that
|
||||
would preclude it from being used in the browser--just include it with a
|
||||
`<script>` tag and it should be good to go. _Disclaimer: I have not tested
|
||||
this implementation in any other context/environment; only tested with node.js_
|
||||
|
||||
----
|
||||
|
||||
## Basic Usage
|
||||
Install with npm :
|
||||
|
||||
```sh
|
||||
npm install dbly-linked-list --save
|
||||
```
|
||||
|
||||
Install with yarn :
|
||||
|
||||
```sh
|
||||
yarn add dbly-linked-list
|
||||
```
|
||||
|
||||
Basic usage example below. _Note: it does not cover all the available
|
||||
methods, rather just highlights the main functionality to get up and running
|
||||
with this data structure. For a description of all the methods, see the
|
||||
API section._
|
||||
|
||||
```javascript
|
||||
var LinkedList = require('dbly-linked-list');
|
||||
var list = new LinkedList();
|
||||
|
||||
list.isEmpty();
|
||||
// --> true
|
||||
|
||||
list.insert('data item 1');
|
||||
list.insert('data item 2');
|
||||
list.insert('data item 3');
|
||||
list.insert('data item 4');
|
||||
// list contains:
|
||||
// 'data item 1', ... ,'data item 4'
|
||||
|
||||
list.isEmpty();
|
||||
// --> false
|
||||
|
||||
list.getSize();
|
||||
// --> 4
|
||||
|
||||
list.insertFirst('data item 0');
|
||||
// list contains:
|
||||
// 'data item 0', ... ,'data item 4'
|
||||
|
||||
list.getHeadNode().getData();
|
||||
// --> 'data item 0'
|
||||
|
||||
list.remove();
|
||||
// --> removes 'data item 4'
|
||||
|
||||
list.removeFirst();
|
||||
// --> removes 'data item 0'
|
||||
|
||||
list.getHeadNode().getData();
|
||||
// --> 'data item 1'
|
||||
|
||||
list.clear();
|
||||
list.isEmpty();
|
||||
// --> true
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
**Available methods for a doubly-linked-list instance:**
|
||||
|
||||
* ### getHeadNode()
|
||||
Returns the first node in the list
|
||||
|
||||
* ### getTailNode()
|
||||
Returns the last node in the list
|
||||
|
||||
* ### isEmpty()
|
||||
Determines if the list is empty or not. Returns true if is empty, false
|
||||
otherwise.
|
||||
|
||||
* ### getSize()
|
||||
Returns the size of the list, or number of nodes
|
||||
|
||||
* ### clear()
|
||||
Clears the list of all nodes/data
|
||||
|
||||
* ### insert(data)
|
||||
Inserts a node (with the provided `data`) to the end of the list
|
||||
|
||||
* ### insertFirst(data)
|
||||
Inserts a node (with the provided `data`) to the front of the list
|
||||
|
||||
* ### insertAt(index, data)
|
||||
Inserts a node (with the provided `data`) at the `index` indicated.
|
||||
|
||||
* ### insertBefore(nodeData, dataToInsert)
|
||||
Inserts a node (with the `dataToInsert`) _before_ the first node containing
|
||||
`nodeData`
|
||||
|
||||
* ### insertAfter(nodeData, dataToInsert)
|
||||
Inserts a node (with the `dataToInsert`) _after_ the first node containing
|
||||
`nodeData`
|
||||
|
||||
* ### remove()
|
||||
Removes the tail node from the list
|
||||
|
||||
* ### removeFirst()
|
||||
Removes the head node from the list
|
||||
|
||||
* ### removeAt(index)
|
||||
Removes the node at the `index` provided
|
||||
|
||||
* ### removeNode(nodeData)
|
||||
Removes the first node that contains the `nodeData` provided
|
||||
|
||||
* ### indexOf(nodeData)
|
||||
Returns the index of the first node containing the provided `nodeData`. If
|
||||
a node cannot be found containing the provided data, -1 is returned.
|
||||
|
||||
* ### contains(nodeData)
|
||||
Determines whether or not the list contains the provided `nodeData`
|
||||
|
||||
* ### find(nodeData)
|
||||
Returns the fist node containing the provided `nodeData`. If a node
|
||||
cannot be found containing the provided data, -1 is returned.
|
||||
|
||||
* ### findAt(index)
|
||||
Returns the node at the location provided by `index`
|
||||
|
||||
* ### forEach(fn, reverse)
|
||||
Utility function to iterate over the list and call the `fn` provided
|
||||
on each node, or element, of the list. The optional `reverse` parameter
|
||||
is a boolean used to specify the direction of iteration
|
||||
(true: tail -> head, false: head -> tail, default: false)
|
||||
|
||||
* ### toArray()
|
||||
Returns an array of all the data contained in the list
|
||||
|
||||
* ### printList()
|
||||
Prints to the console the data property of each node in the list
|
||||
|
||||
* ### interruptEnumeration()
|
||||
Interrupts and breaks out of the loop induced by `forEach()`, making partial iterations possible. An iteration cannot be resumed after having been interrupted.
|
||||
|
||||
**Available methods for an individual node instance:**
|
||||
|
||||
* ### getData()
|
||||
Returns the data of the the node
|
||||
|
||||
* ### hasNext()
|
||||
Returns whether or not the node has a pointer to the next node
|
||||
|
||||
* ### hasPrev()
|
||||
Returns whether or not the node has a pointer to the previous node
|
||||
|
||||
* ### toString()
|
||||
Returns a string represenation of the node. If the data is an object,
|
||||
it returns the JSON.stringify version of the object. Otherwise, it
|
||||
simply returns the data
|
||||
|
||||
----
|
||||
|
||||
## License
|
||||
MIT © Jason Jones
|
||||
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/dbly-linked-list.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/dbly-linked-list
|
||||
[circleci-image]: https://img.shields.io/circleci/project/github/jasonsjones/doubly-linked-list.svg?style=flat-square
|
||||
[circleci-url]: https://circleci.com/gh/jasonsjones/doubly-linked-list
|
||||
[dm-image]: https://img.shields.io/david/jasonsjones/doubly-linked-list.svg?style=flat-square
|
||||
[dm-url]: https://david-dm.org/jasonsjones/doubly-linked-list
|
||||
[devdep-image]: https://img.shields.io/david/dev/jasonsjones/doubly-linked-list.svg?style=flat-square
|
||||
[devdep-url]: https://david-dm.org/jasonsjones/doubly-linked-list?type=dev
|
||||
474
build/node_modules/dbly-linked-list/index.js
generated
vendored
Normal file
474
build/node_modules/dbly-linked-list/index.js
generated
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
/**
|
||||
* @fileOverview Implementation of a doubly linked-list data structure
|
||||
* @author Jason S. Jones
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var isEqual = require('lodash.isequal');
|
||||
var Node = require('./lib/list-node');
|
||||
var Iterator = require('./lib/iterator');
|
||||
|
||||
/**************************************************
|
||||
* Doubly linked list class
|
||||
*
|
||||
* Implementation of a doubly linked list data structure. This
|
||||
* implementation provides the general functionality of adding nodes to
|
||||
* the front or back of the list, as well as removing node from the front
|
||||
* or back. This functionality enables this implemention to be the
|
||||
* underlying data structure for the more specific stack or queue data
|
||||
* structure.
|
||||
*
|
||||
***************************************************/
|
||||
|
||||
/**
|
||||
* Creates a LinkedList instance. Each instance has a head node, a tail
|
||||
* node and a size, which represents the number of nodes in the list.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function DoublyLinkedList() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
this.size = 0;
|
||||
|
||||
// add iterator as a property of this list to share the same
|
||||
// iterator instance with all other methods that may require
|
||||
// its use. Note: be sure to call this.iterator.reset() to
|
||||
// reset this iterator to point the head of the list.
|
||||
this.iterator = new Iterator(this);
|
||||
}
|
||||
|
||||
/* Functions attached to the Linked-list prototype. All linked-list
|
||||
* instances will share these methods, meaning there will NOT be copies
|
||||
* made for each instance. This will be a huge memory savings since there
|
||||
* may be several different linked lists.
|
||||
*/
|
||||
DoublyLinkedList.prototype = {
|
||||
|
||||
/**
|
||||
* Creates a new Node object with 'data' assigned to the node's data
|
||||
* property
|
||||
*
|
||||
* @param {object|string|number} data The data to initialize with the
|
||||
* node
|
||||
* @returns {object} Node object intialized with 'data'
|
||||
*/
|
||||
createNewNode: function(data) {
|
||||
return new Node(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the first node in the list, commonly referred to as the
|
||||
* 'head' node
|
||||
*
|
||||
* @returns {object} the head node of the list
|
||||
*/
|
||||
getHeadNode: function() {
|
||||
return this.head;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the last node in the list, commonly referred to as the
|
||||
* 'tail'node
|
||||
*
|
||||
* @returns {object} the tail node of the list
|
||||
*/
|
||||
getTailNode: function() {
|
||||
return this.tail;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the list is empty
|
||||
*
|
||||
* @returns {boolean} true if the list is empty, false otherwise
|
||||
*/
|
||||
isEmpty: function() {
|
||||
return (this.size === 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the size of the list, or number of nodes
|
||||
*
|
||||
* @returns {number} the number of nodes in the list
|
||||
*/
|
||||
getSize: function() {
|
||||
return this.size;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the list of all nodes/data
|
||||
*/
|
||||
clear: function () {
|
||||
while (!this.isEmpty()) {
|
||||
this.remove();
|
||||
}
|
||||
},
|
||||
|
||||
//################## INSERT methods ####################
|
||||
|
||||
/**
|
||||
* Inserts a node with the provided data to the end of the list
|
||||
*
|
||||
* @param {object|string|number} data The data to initialize with the
|
||||
* node
|
||||
* @returns {boolean} true if insert operation was successful
|
||||
*/
|
||||
insert: function(data) {
|
||||
var newNode = this.createNewNode(data);
|
||||
if (this.isEmpty()) {
|
||||
this.head = this.tail = newNode;
|
||||
} else {
|
||||
this.tail.next = newNode;
|
||||
newNode.prev = this.tail;
|
||||
this.tail = newNode;
|
||||
}
|
||||
this.size += 1;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a node with the provided data to the front of the list
|
||||
*
|
||||
* @param {object|string|number} data The data to initialize with the
|
||||
* node
|
||||
* @returns {boolean} true if insert operation was successful
|
||||
*/
|
||||
insertFirst: function(data) {
|
||||
if (this.isEmpty()) {
|
||||
this.insert(data);
|
||||
} else {
|
||||
var newNode = this.createNewNode(data);
|
||||
|
||||
newNode.next = this.head;
|
||||
this.head.prev = newNode;
|
||||
this.head = newNode;
|
||||
|
||||
this.size += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a node with the provided data at the index indicated.
|
||||
*
|
||||
* @param {number} index The index in the list to insert the new node
|
||||
* @param {object|string|number} data The data to initialize with the node
|
||||
*/
|
||||
insertAt: function (index, data) {
|
||||
var current = this.getHeadNode(),
|
||||
newNode = this.createNewNode(data),
|
||||
position = 0;
|
||||
|
||||
// check for index out-of-bounds
|
||||
if (index < 0 || index > this.getSize() - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if index is 0, we just need to insert the first node
|
||||
if (index === 0) {
|
||||
this.insertFirst(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
while (position < index) {
|
||||
current = current.next;
|
||||
position += 1;
|
||||
}
|
||||
|
||||
current.prev.next = newNode;
|
||||
newNode.prev = current.prev;
|
||||
current.prev = newNode;
|
||||
newNode.next = current;
|
||||
|
||||
this.size += 1;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a node before the first node containing the provided data
|
||||
*
|
||||
* @param {object|string|number} nodeData The data of the node to
|
||||
* find to insert the new node before
|
||||
* @param {object|string|number} dataToInsert The data to initialize with the node
|
||||
* @returns {boolean} true if insert operation was successful
|
||||
*/
|
||||
insertBefore: function (nodeData, dataToInsert) {
|
||||
var index = this.indexOf(nodeData);
|
||||
return this.insertAt(index, dataToInsert);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a node after the first node containing the provided data
|
||||
*
|
||||
* @param {object|string|number} nodeData The data of the node to
|
||||
* find to insert the new node after
|
||||
* @param {object|string|number} dataToInsert The data to initialize with the node
|
||||
* @returns {boolean} true if insert operation was successful
|
||||
*/
|
||||
insertAfter: function (nodeData, dataToInsert) {
|
||||
var index = this.indexOf(nodeData);
|
||||
var size = this.getSize();
|
||||
|
||||
// check if we want to insert new node after the tail node
|
||||
if (index + 1 === size) {
|
||||
|
||||
// if so, call insert, which will append to the end by default
|
||||
return this.insert(dataToInsert);
|
||||
|
||||
} else {
|
||||
|
||||
// otherwise, increment the index and insert there
|
||||
return this.insertAt(index + 1, dataToInsert);
|
||||
}
|
||||
},
|
||||
|
||||
//################## REMOVE methods ####################
|
||||
|
||||
/**
|
||||
* Removes the tail node from the list
|
||||
*
|
||||
* There is a significant performance improvement with the operation
|
||||
* over its singly linked list counterpart. The mere fact of having
|
||||
* a reference to the previous node improves this operation from O(n)
|
||||
* (in the case of singly linked list) to O(1).
|
||||
*
|
||||
* @returns the node that was removed
|
||||
*/
|
||||
remove: function() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get handle for the tail node
|
||||
var nodeToRemove = this.getTailNode();
|
||||
|
||||
// if there is only one node in the list, set head and tail
|
||||
// properties to null
|
||||
if (this.getSize() === 1) {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
|
||||
// more than one node in the list
|
||||
} else {
|
||||
this.tail = this.getTailNode().prev;
|
||||
this.tail.next = null;
|
||||
}
|
||||
this.size -= 1;
|
||||
|
||||
return nodeToRemove;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the head node from the list
|
||||
*
|
||||
* @returns the node that was removed
|
||||
*/
|
||||
removeFirst: function() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var nodeToRemove;
|
||||
|
||||
if (this.getSize() === 1) {
|
||||
nodeToRemove = this.remove();
|
||||
} else {
|
||||
nodeToRemove = this.getHeadNode();
|
||||
this.head = this.head.next;
|
||||
this.head.prev = null;
|
||||
this.size -= 1;
|
||||
}
|
||||
|
||||
return nodeToRemove;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the node at the index provided
|
||||
*
|
||||
* @param {number} index The index of the node to remove
|
||||
* @returns the node that was removed
|
||||
*/
|
||||
removeAt: function (index) {
|
||||
var nodeToRemove = this.findAt(index);
|
||||
|
||||
// check for index out-of-bounds
|
||||
if (index < 0 || index > this.getSize() - 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if index is 0, we just need to remove the first node
|
||||
if (index === 0) {
|
||||
return this.removeFirst();
|
||||
}
|
||||
|
||||
// if index is size-1, we just need to remove the last node,
|
||||
// which remove() does by default
|
||||
if (index === this.getSize() - 1) {
|
||||
return this.remove();
|
||||
}
|
||||
|
||||
nodeToRemove.prev.next = nodeToRemove.next;
|
||||
nodeToRemove.next.prev = nodeToRemove.prev;
|
||||
nodeToRemove.next = nodeToRemove.prev = null;
|
||||
|
||||
this.size -= 1;
|
||||
|
||||
return nodeToRemove;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the first node that contains the data provided
|
||||
*
|
||||
* @param {object|string|number} nodeData The data of the node to remove
|
||||
* @returns the node that was removed
|
||||
*/
|
||||
removeNode: function (nodeData) {
|
||||
var index = this.indexOf(nodeData);
|
||||
return this.removeAt(index);
|
||||
},
|
||||
|
||||
//################## FIND methods ####################
|
||||
|
||||
/**
|
||||
* Returns the index of the first node containing the provided data. If
|
||||
* a node cannot be found containing the provided data, -1 is returned.
|
||||
*
|
||||
* @param {object|string|number} nodeData The data of the node to find
|
||||
* @returns the index of the node if found, -1 otherwise
|
||||
*/
|
||||
indexOf: function(nodeData) {
|
||||
this.iterator.reset();
|
||||
var current;
|
||||
|
||||
var index = 0;
|
||||
|
||||
// iterate over the list (keeping track of the index value) until
|
||||
// we find the node containg the nodeData we are looking for
|
||||
while (this.iterator.hasNext()) {
|
||||
current = this.iterator.next();
|
||||
if (isEqual(current.getData(), nodeData)) {
|
||||
return index;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// only get here if we didn't find a node containing the nodeData
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the fist node containing the provided data. If a node
|
||||
* cannot be found containing the provided data, -1 is returned.
|
||||
*
|
||||
* @param {object|string|number} nodeData The data of the node to find
|
||||
* @returns the node if found, -1 otherwise
|
||||
*/
|
||||
find: function(nodeData) {
|
||||
// start at the head of the list
|
||||
this.iterator.reset();
|
||||
var current;
|
||||
|
||||
// iterate over the list until we find the node containing the data
|
||||
// we are looking for
|
||||
while (this.iterator.hasNext()) {
|
||||
current = this.iterator.next();
|
||||
if (isEqual(current.getData(), nodeData)) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
// only get here if we didn't find a node containing the nodeData
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the node at the location provided by index
|
||||
*
|
||||
* @param {number} index The index of the node to return
|
||||
* @returns the node located at the index provided.
|
||||
*/
|
||||
findAt: function(index) {
|
||||
// if idx is out of bounds or fn called on empty list, return -1
|
||||
if (this.isEmpty() || index > this.getSize() - 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// else, loop through the list and return the node in the
|
||||
// position provided by idx. Assume zero-based positions.
|
||||
var node = this.getHeadNode();
|
||||
var position = 0;
|
||||
|
||||
while (position < index) {
|
||||
node = node.next;
|
||||
position += 1;
|
||||
}
|
||||
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not the list contains the provided nodeData
|
||||
*
|
||||
* @param {object|string|number} nodeData The data to check if the list
|
||||
* contains
|
||||
* @returns the true if the list contains nodeData, false otherwise
|
||||
*/
|
||||
contains: function (nodeData) {
|
||||
if (this.indexOf(nodeData) > -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
//################## UTILITY methods ####################
|
||||
|
||||
/**
|
||||
* Utility function to iterate over the list and call the fn provided
|
||||
* on each node, or element, of the list
|
||||
*
|
||||
* @param {object} fn The function to call on each node of the list
|
||||
* @param {bool} reverse Use or not reverse iteration (tail to head), default to false
|
||||
*/
|
||||
forEach: function(fn, reverse) {
|
||||
reverse = reverse || false;
|
||||
if (reverse) {
|
||||
this.iterator.reset_reverse();
|
||||
this.iterator.each_reverse(fn)
|
||||
} else {
|
||||
this.iterator.reset();
|
||||
this.iterator.each(fn);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an array of all the data contained in the list
|
||||
*
|
||||
* @returns {array} the array of all the data from the list
|
||||
*/
|
||||
toArray: function() {
|
||||
var listArray = [];
|
||||
this.forEach(function(node) {
|
||||
listArray.push(node.getData());
|
||||
});
|
||||
|
||||
return listArray;
|
||||
},
|
||||
|
||||
/**
|
||||
* Interrupts iteration over the list
|
||||
*/
|
||||
interruptEnumeration: function() {
|
||||
this.iterator.interrupt();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DoublyLinkedList;
|
||||
|
||||
}());
|
||||
195
build/node_modules/dbly-linked-list/lib/iterator.js
generated
vendored
Normal file
195
build/node_modules/dbly-linked-list/lib/iterator.js
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @fileOverview Implementation of an iterator for a linked list
|
||||
* data structure
|
||||
* @author Jason S. Jones
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**************************************************
|
||||
* Iterator class
|
||||
*
|
||||
* Represents an instantiation of an iterator to be used
|
||||
* within a linked list. The iterator will provide the ability
|
||||
* to iterate over all nodes in a list by keeping track of the
|
||||
* postition of a 'currentNode'. This 'currentNode' pointer
|
||||
* will keep state until a reset() operation is called at which
|
||||
* time it will reset to point the head of the list.
|
||||
*
|
||||
* Even though this iterator class is inextricably linked
|
||||
* (no pun intended) to a linked list instatiation, it was removed
|
||||
* from within the linked list code to adhere to the best practice
|
||||
* of separation of concerns.
|
||||
*
|
||||
***************************************************/
|
||||
|
||||
/**
|
||||
* Creates an iterator instance to iterate over the linked list provided.
|
||||
*
|
||||
* @constructor
|
||||
* @param {object} theList the linked list to iterate over
|
||||
*/
|
||||
function Iterator(theList) {
|
||||
this.list = theList || null;
|
||||
this.stopIterationFlag = false;
|
||||
|
||||
// a pointer the current node in the list that will be returned.
|
||||
// initially this will be null since the 'list' will be empty
|
||||
this.currentNode = null;
|
||||
}
|
||||
|
||||
/* Functions attached to the Iterator prototype. All iterator instances
|
||||
* will share these methods, meaning there will NOT be copies made for each
|
||||
* instance.
|
||||
*/
|
||||
Iterator.prototype = {
|
||||
|
||||
/**
|
||||
* Returns the next node in the iteration.
|
||||
*
|
||||
* @returns {object} the next node in the iteration.
|
||||
*/
|
||||
next: function() {
|
||||
var current = this.currentNode;
|
||||
// a check to prevent error if randomly calling next() when
|
||||
// iterator is at the end of the list, meaining the currentNode
|
||||
// will be pointing to null.
|
||||
//
|
||||
// When this function is called, it will return the node currently
|
||||
// assigned to this.currentNode and move the pointer to the next
|
||||
// node in the list (if it exists)
|
||||
if (this.currentNode !== null) {
|
||||
this.currentNode = this.currentNode.next;
|
||||
}
|
||||
|
||||
return current;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the iterator has a node to return
|
||||
*
|
||||
* @returns true if the iterator has a node to return, false otherwise
|
||||
*/
|
||||
hasNext: function() {
|
||||
return this.currentNode !== null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the iterator to the beginning of the list.
|
||||
*/
|
||||
reset: function() {
|
||||
this.currentNode = this.list.getHeadNode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the first node in the list and moves the iterator to
|
||||
* point to the second node.
|
||||
*
|
||||
* @returns the first node in the list
|
||||
*/
|
||||
first: function() {
|
||||
this.reset();
|
||||
return this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the list to iterate over
|
||||
*
|
||||
* @param {object} theList the linked list to iterate over
|
||||
*/
|
||||
setList: function(theList) {
|
||||
this.list = theList;
|
||||
this.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterates over all nodes in the list and calls the provided callback
|
||||
* function with each node as an argument.
|
||||
* Iteration will break if interrupt() is called
|
||||
*
|
||||
* @param {function} callback the callback function to be called with
|
||||
* each node of the list as an arg
|
||||
*/
|
||||
each: function(callback) {
|
||||
this.reset();
|
||||
var el;
|
||||
while (this.hasNext() && !this.stopIterationFlag) {
|
||||
el = this.next();
|
||||
callback(el);
|
||||
}
|
||||
this.stopIterationFlag = false;
|
||||
},
|
||||
|
||||
/*
|
||||
* ### REVERSE ITERATION (TAIL -> HEAD) ###
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the first node in the list and moves the iterator to
|
||||
* point to the second node.
|
||||
*
|
||||
* @returns the first node in the list
|
||||
*/
|
||||
last: function() {
|
||||
this.reset_reverse();
|
||||
return this.next_reverse();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the iterator to the tail of the list.
|
||||
*/
|
||||
reset_reverse: function() {
|
||||
this.currentNode = this.list.getTailNode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the next node in the iteration, when iterating from tail to head
|
||||
*
|
||||
* @returns {object} the next node in the iteration.
|
||||
*/
|
||||
next_reverse: function() {
|
||||
var current = this.currentNode;
|
||||
if (this.currentNode !== null) {
|
||||
this.currentNode = this.currentNode.prev;
|
||||
}
|
||||
|
||||
return current;
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterates over all nodes in the list and calls the provided callback
|
||||
* function with each node as an argument,
|
||||
* starting from the tail and going towards the head.
|
||||
* The iteration will break if interrupt() is called.
|
||||
*
|
||||
* @param {function} callback the callback function to be called within
|
||||
* each node as an arg
|
||||
*/
|
||||
each_reverse: function(callback) {
|
||||
this.reset_reverse();
|
||||
var el;
|
||||
while (this.hasNext() && !this.stopIterationFlag) {
|
||||
el = this.next_reverse();
|
||||
callback(el);
|
||||
}
|
||||
this.stopIterationFlag = false;
|
||||
},
|
||||
|
||||
/*
|
||||
* ### INTERRUPT ITERATION ###
|
||||
*/
|
||||
|
||||
/**
|
||||
* Raises interrupt flag (that will stop each() or each_reverse())
|
||||
*/
|
||||
|
||||
interrupt: function() {
|
||||
this.stopIterationFlag = true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Iterator;
|
||||
|
||||
}());
|
||||
83
build/node_modules/dbly-linked-list/lib/list-node.js
generated
vendored
Normal file
83
build/node_modules/dbly-linked-list/lib/list-node.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**************************************************
|
||||
* Linked list node class
|
||||
*
|
||||
* Internal private class to represent a node within
|
||||
* a linked list. Each node has a 'data' property and
|
||||
* a pointer the previous node and the next node in the list.
|
||||
*
|
||||
* Since the 'Node' function is not assigned to
|
||||
* module.exports it is not visible outside of this
|
||||
* file, therefore, it is private to the LinkedList
|
||||
* class.
|
||||
*
|
||||
***************************************************/
|
||||
|
||||
/**
|
||||
* Creates a node object with a data property and pointer
|
||||
* to the next node
|
||||
*
|
||||
* @constructor
|
||||
* @param {object|number|string} data The data to initialize with the node
|
||||
*/
|
||||
function Node(data) {
|
||||
this.data = data || null;
|
||||
this.next = null;
|
||||
this.prev = null;
|
||||
}
|
||||
|
||||
/* Functions attached to the Node prototype. All node instances will
|
||||
* share these methods, meaning there will NOT be copies made for each
|
||||
* instance. This will be a huge memory savings since there will likely
|
||||
* be a large number of individual nodes.
|
||||
*/
|
||||
Node.prototype = {
|
||||
|
||||
/**
|
||||
* Returns whether or not the node has a pointer to the next node
|
||||
*
|
||||
* @returns {boolean} true if there is a next node; false otherwise
|
||||
*/
|
||||
hasNext: function() {
|
||||
return (this.next !== null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether or not the node has a pointer to the previous node
|
||||
*
|
||||
* @returns {boolean} true if there is a previous node; false otherwise
|
||||
*/
|
||||
hasPrev: function() {
|
||||
return (this.prev !== null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the data of the the node
|
||||
*
|
||||
* @returns {object|string|number} the data of the node
|
||||
*/
|
||||
getData: function() {
|
||||
return this.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a string represenation of the node. If the data is an
|
||||
* object, it returns the JSON.stringify version of the object.
|
||||
* Otherwise, it simply returns the data
|
||||
*
|
||||
* @return {string} the string represenation of the node data
|
||||
*/
|
||||
toString: function() {
|
||||
if (typeof this.data === 'object') {
|
||||
return JSON.stringify(this.data);
|
||||
} else {
|
||||
return String(this.data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Node;
|
||||
|
||||
}());
|
||||
64
build/node_modules/dbly-linked-list/package.json
generated
vendored
Normal file
64
build/node_modules/dbly-linked-list/package.json
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"_from": "dbly-linked-list@0.2.0",
|
||||
"_id": "dbly-linked-list@0.2.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-Ool7y15f6JRDs0YKx7Dh9uiTb1jS1SZLNdT3Y2q16DlaEghXbMsmODS/XittjR2xztt1gJUpz7jVxpqAPF8VGg==",
|
||||
"_location": "/dbly-linked-list",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "dbly-linked-list@0.2.0",
|
||||
"name": "dbly-linked-list",
|
||||
"escapedName": "dbly-linked-list",
|
||||
"rawSpec": "0.2.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "0.2.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/queue-fifo"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.2.0.tgz",
|
||||
"_shasum": "d30f5225dc1ce72220d7931489b0c5703b1aa8aa",
|
||||
"_spec": "dbly-linked-list@0.2.0",
|
||||
"_where": "/Users/asciidisco/Desktop/asciidisco.com/build/node_modules/queue-fifo",
|
||||
"author": {
|
||||
"name": "Jason Jones"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/jasonsjones/doubly-linked-list/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"lodash.isequal": "^4.5.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Javascript implementation of a doubly linked-list data structure",
|
||||
"devDependencies": {
|
||||
"eslint": "^4.12.0",
|
||||
"mocha": "^4.0.1",
|
||||
"nyc": "^11.3.0",
|
||||
"should": "^13.1.3"
|
||||
},
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"homepage": "https://github.com/jasonsjones/doubly-linked-list#readme",
|
||||
"keywords": [
|
||||
"doubly linked-list",
|
||||
"linked list",
|
||||
"data structure"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"name": "dbly-linked-list",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jasonsjones/doubly-linked-list.git"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint index.js lib/*.js test/*.js",
|
||||
"test": "nyc mocha"
|
||||
},
|
||||
"version": "0.2.0"
|
||||
}
|
||||
400
build/node_modules/dbly-linked-list/test/list.spec.js
generated
vendored
Normal file
400
build/node_modules/dbly-linked-list/test/list.spec.js
generated
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
/* globals describe it beforeEach afterEach */
|
||||
|
||||
var should = require('should');
|
||||
var LinkedList = require('../');
|
||||
|
||||
describe('Linked List', function() {
|
||||
var list = null;
|
||||
|
||||
// Utility function to populate the list with dummy data.
|
||||
// The number of nodes added will be specified by the 'numNodes'
|
||||
// parameter.
|
||||
var populateList = function (aList, numNodes) {
|
||||
for (var i = 0; i < numNodes; i++) {
|
||||
aList.insert('test item ' + (i + 1));
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
list = new LinkedList();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
list = null;
|
||||
});
|
||||
|
||||
it('should have a working test environment', function() {
|
||||
true.should.equal(true);
|
||||
});
|
||||
|
||||
it('should initially contain zero items', function() {
|
||||
list.isEmpty().should.equal(true);
|
||||
list.getSize().should.equal(0);
|
||||
});
|
||||
|
||||
it('should clear the list and set head and tail to null', function () {
|
||||
populateList(list, 10);
|
||||
list.getSize().should.equal(10);
|
||||
list.clear();
|
||||
list.getSize().should.equal(0);
|
||||
should.not.exist(list.getHeadNode());
|
||||
should.not.exist(list.getTailNode());
|
||||
});
|
||||
|
||||
it('should return an array of all the data in the list', function() {
|
||||
list.insert({
|
||||
id: 1,
|
||||
name: 'test item 1'
|
||||
});
|
||||
list.insert({
|
||||
id: 2,
|
||||
name: 'test item 2'
|
||||
});
|
||||
list.insert({
|
||||
id: 3,
|
||||
name: 'test item 3'
|
||||
});
|
||||
var listArray = list.toArray();
|
||||
listArray.should.be.an.Array;
|
||||
listArray.should.have.length(3);
|
||||
});
|
||||
|
||||
describe('iterator functionality', function() {
|
||||
it('should exist when a list is instantiated', function() {
|
||||
list.iterator.should.be.ok;
|
||||
});
|
||||
|
||||
it('should have iterator currentNode be null when first instantiated',
|
||||
function() {
|
||||
should.not.exist(list.iterator.next());
|
||||
});
|
||||
|
||||
it('should return the tail node when iterator.last() is called', function() {
|
||||
populateList(list, 10);
|
||||
var last = list.iterator.last();
|
||||
last.should.equal(list.getTailNode());
|
||||
})
|
||||
|
||||
it('should return the head node when iterator.first() is called',
|
||||
function() {
|
||||
populateList(list, 10);
|
||||
var first = list.iterator.first();
|
||||
first.should.equal(list.getHeadNode());
|
||||
});
|
||||
|
||||
it('should return correct boolean value for hasNext()', function() {
|
||||
populateList(list, 3);
|
||||
list.iterator.reset();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
// get first element
|
||||
list.iterator.next();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
// get second element
|
||||
list.iterator.next();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
// get third element
|
||||
list.iterator.next();
|
||||
|
||||
// should be no more element in list
|
||||
list.iterator.hasNext().should.equal(false);
|
||||
});
|
||||
|
||||
it('should return correct boolean value for hasNext() in reverse order', function() {
|
||||
populateList(list, 3);
|
||||
list.iterator.reset_reverse();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
list.iterator.next_reverse();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
list.iterator.next_reverse();
|
||||
|
||||
list.iterator.hasNext().should.equal(true);
|
||||
list.iterator.next_reverse();
|
||||
|
||||
list.iterator.hasNext().should.equal(false);
|
||||
});
|
||||
|
||||
it('should go through elements from head to tail when calling iterator.each()', function() {
|
||||
populateList(list, 3);
|
||||
var array = [];
|
||||
//expected result
|
||||
var expectedArray = ["test item 1", "test item 2", "test item 3"];
|
||||
var dummyCallback = function(node) {
|
||||
array.push(node.getData());
|
||||
}
|
||||
list.iterator.reset()
|
||||
list.iterator.each(dummyCallback);
|
||||
array.should.be.eql(expectedArray);
|
||||
});
|
||||
|
||||
it('should go through elements from tail to head when calling iterator.each_reverse()', function() {
|
||||
populateList(list, 3);
|
||||
var array = [];
|
||||
var expectedArray = ["test item 3", "test item 2", "test item 1"];
|
||||
var dummyCallback = function(node) {
|
||||
array.push(node.getData());
|
||||
};
|
||||
list.iterator.reset_reverse();
|
||||
list.iterator.each_reverse(dummyCallback);
|
||||
array.should.be.eql(expectedArray);
|
||||
});
|
||||
|
||||
it('should stop in the middle of iteration if iterator.interrupt() is called', function() {
|
||||
populateList(list, 5);
|
||||
var count = 0;
|
||||
var dummyCallback = function() {
|
||||
count += 1;
|
||||
if (count === 3) {
|
||||
list.iterator.interrupt();
|
||||
}
|
||||
};
|
||||
|
||||
// head to tail
|
||||
list.iterator.reset();
|
||||
list.iterator.each(dummyCallback);
|
||||
count.should.be.equal(3);
|
||||
|
||||
// tail to head
|
||||
count = 0;
|
||||
list.iterator.reset_reverse();
|
||||
list.iterator.each_reverse(dummyCallback);
|
||||
count.should.be.equal(3);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('insert functionality', function() {
|
||||
it('should set the head node equal to the tail node when first item ' +
|
||||
'is inserted', function() {
|
||||
list.insert('test item 1');
|
||||
list.getHeadNode().should.equal(list.getTailNode());
|
||||
list.getSize().should.equal(1);
|
||||
});
|
||||
|
||||
it('should insert items to the back of the list', function() {
|
||||
populateList(list, 5);
|
||||
list.isEmpty().should.equal(false);
|
||||
list.getSize().should.equal(5);
|
||||
var tail = list.getTailNode();
|
||||
tail.getData().should.equal('test item 5');
|
||||
});
|
||||
|
||||
it('should insert items to the front of the list', function() {
|
||||
list.insert('test item 1');
|
||||
list.insert('test item 2');
|
||||
list.insertFirst('new item 0');
|
||||
list.getHeadNode().data.should.equal('new item 0');
|
||||
list.getHeadNode().hasPrev().should.equal(false);
|
||||
list.getSize().should.equal(3);
|
||||
});
|
||||
|
||||
it('should insert item at a particular index', function() {
|
||||
populateList(list, 3);
|
||||
list.insert('test item 5');
|
||||
list.getSize().should.equal(4);
|
||||
var success = list.insertAt(3, 'test item 4');
|
||||
success.should.equal(true);
|
||||
list.getSize().should.equal(5);
|
||||
var node = list.findAt(3);
|
||||
node.getData().should.equal('test item 4');
|
||||
});
|
||||
|
||||
it('should insert new head node when inserting at index 0', function() {
|
||||
populateList(list, 3);
|
||||
list.getSize().should.equal(3);
|
||||
var success = list.insertAt(0, 'test item 0');
|
||||
success.should.equal(true);
|
||||
list.getSize().should.equal(4);
|
||||
var node = list.getHeadNode();
|
||||
node.getData().should.equal('test item 0');
|
||||
});
|
||||
|
||||
it('should return false when trying to insert at index out of bounds', function() {
|
||||
populateList(list, 3);
|
||||
var success = list.insertAt(5, 'test item 4');
|
||||
success.should.equal(false);
|
||||
});
|
||||
|
||||
it('should insert item before a particular node', function () {
|
||||
populateList(list, 3);
|
||||
list.insert('test item 5');
|
||||
list.getSize().should.equal(4);
|
||||
|
||||
list.insertBefore('test item 5', 'test item 4');
|
||||
list.getSize().should.equal(5);
|
||||
var node = list.findAt(3);
|
||||
node.getData().should.equal('test item 4');
|
||||
|
||||
// test for inserting before the head node
|
||||
list.insertBefore('test item 1', 'test item 0');
|
||||
list.getSize().should.equal(6);
|
||||
node = list.getHeadNode();
|
||||
node.getData().should.equal('test item 0');
|
||||
});
|
||||
|
||||
it('should insert item after a particular node', function () {
|
||||
populateList(list, 3);
|
||||
list.insert('test item 5');
|
||||
list.getSize().should.equal(4);
|
||||
|
||||
list.insertAfter('test item 3', 'test item 4');
|
||||
list.getSize().should.equal(5);
|
||||
var node = list.findAt(3);
|
||||
node.getData().should.equal('test item 4');
|
||||
|
||||
// test for inserting after the tail node
|
||||
list.insertAfter('test item 5', 'test item 6');
|
||||
list.getSize().should.equal(6);
|
||||
node = list.getTailNode();
|
||||
node.getData().should.equal('test item 6');
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove functionality', function() {
|
||||
it('should return null if remove is called on an empty list',
|
||||
function() {
|
||||
var node = list.remove();
|
||||
should.not.exist(node);
|
||||
});
|
||||
|
||||
it('should remove items from the back of the list', function() {
|
||||
populateList(list, 3);
|
||||
list.isEmpty().should.equal(false);
|
||||
list.getSize().should.equal(3);
|
||||
var node = list.remove();
|
||||
node.getData().should.equal('test item 3');
|
||||
list.getSize().should.equal(2);
|
||||
var last = list.getTailNode();
|
||||
last.getData().should.equal('test item 2');
|
||||
last.hasNext().should.equal(false);
|
||||
});
|
||||
|
||||
it('should return null if removeFirst is called on an empty list',
|
||||
function() {
|
||||
var node = list.removeFirst();
|
||||
should.not.exist(node);
|
||||
});
|
||||
|
||||
it('should remove items from the front of the list', function() {
|
||||
populateList(list, 3);
|
||||
list.isEmpty().should.equal(false);
|
||||
list.getSize().should.equal(3);
|
||||
var node = list.removeFirst();
|
||||
node.getData().should.equal('test item 1');
|
||||
list.getSize().should.equal(2);
|
||||
var first = list.getHeadNode();
|
||||
first.getData().should.equal('test item 2');
|
||||
first.hasPrev().should.equal(false);
|
||||
});
|
||||
|
||||
it('should remove item from the front of a list with only one node', function () {
|
||||
list.insert('test item 1');
|
||||
var node = list.removeFirst();
|
||||
node.getData().should.equal('test item 1');
|
||||
list.getSize().should.equal(0);
|
||||
});
|
||||
|
||||
it('should remove item at a particulary index', function() {
|
||||
populateList(list, 4);
|
||||
list.getSize().should.equal(4);
|
||||
var node = list.removeAt(1);
|
||||
node.getData().should.equal('test item 2');
|
||||
list.getSize().should.equal(3);
|
||||
});
|
||||
|
||||
it('should remove a node with given data', function() {
|
||||
populateList(list, 4);
|
||||
list.getSize().should.equal(4);
|
||||
var node = list.removeNode('test item 3');
|
||||
node.getData().should.equal('test item 3');
|
||||
list.getSize().should.equal(3);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('find functionality', function() {
|
||||
it('should find a node with the data provided', function() {
|
||||
populateList(list, 3);
|
||||
var node = list.find('test item 2');
|
||||
node.should.be.an.Object;
|
||||
node.getData().should.equal('test item 2');
|
||||
});
|
||||
|
||||
it('should find a node with a complex obj', function () {
|
||||
list.insert({key: 'key', value: 'value123'});
|
||||
var node = list.find({key: 'key', value: 'value123'});
|
||||
node.getData().should.be.an.Object;
|
||||
node.getData().should.have.properties(['key', 'value']);
|
||||
});
|
||||
|
||||
it('should return -1 if a node does not exist with the given data',
|
||||
function() {
|
||||
populateList(list, 3);
|
||||
var node = list.find('not found...');
|
||||
node.should.not.be.an.Object;
|
||||
node.should.equal(-1);
|
||||
});
|
||||
|
||||
it('should return -1 if find() is called on an empty list',
|
||||
function() {
|
||||
var node = list.find('not found...');
|
||||
node.should.not.be.an.Object;
|
||||
node.should.equal(-1);
|
||||
});
|
||||
|
||||
it('should return the index of node containing the provided data',
|
||||
function() {
|
||||
populateList(list, 3);
|
||||
var index = list.indexOf('test item 1');
|
||||
index.should.equal(0);
|
||||
|
||||
index = list.indexOf('test item 2');
|
||||
index.should.equal(1);
|
||||
|
||||
index = list.indexOf('test item 3');
|
||||
index.should.equal(2);
|
||||
});
|
||||
|
||||
it('should return -1 for the index of node with the given data if the' +
|
||||
'node does not exist',
|
||||
function() {
|
||||
populateList(list, 3);
|
||||
var index = list.indexOf('not found');
|
||||
index.should.equal(-1);
|
||||
});
|
||||
|
||||
it('should return node at given index', function() {
|
||||
list.insert('test item 1');
|
||||
list.insert('test item 2');
|
||||
var node = list.findAt(0);
|
||||
node.should.be.an.Object;
|
||||
node.getData().should.equal('test item 1');
|
||||
|
||||
node = list.findAt(1);
|
||||
node.should.be.an.Object;
|
||||
node.getData().should.equal('test item 2');
|
||||
});
|
||||
|
||||
it('should return -1 when findAt() is called w/ index > than list size',
|
||||
function() {
|
||||
var node = list.findAt(0);
|
||||
node.should.not.be.an.Object;
|
||||
node.should.equal(-1);
|
||||
});
|
||||
|
||||
it('should return true if list contains specified data,' +
|
||||
'false otherwise',
|
||||
function () {
|
||||
populateList(list, 3);
|
||||
var result = list.contains('test item 2');
|
||||
result.should.equal(true);
|
||||
|
||||
result = list.contains('not found');
|
||||
result.should.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
72
build/node_modules/dbly-linked-list/test/node.spec.js
generated
vendored
Normal file
72
build/node_modules/dbly-linked-list/test/node.spec.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/* globals describe it beforeEach before afterEach */
|
||||
|
||||
var should = require('should');
|
||||
var LinkedList = require('../');
|
||||
|
||||
describe('List Node', function() {
|
||||
var list = null;
|
||||
|
||||
before(function() {
|
||||
list = new LinkedList();
|
||||
});
|
||||
|
||||
it('should have a working test environment', function() {
|
||||
true.should.equal(true);
|
||||
});
|
||||
|
||||
it('should exist when instantiated', function() {
|
||||
var node = list.createNewNode('test data');
|
||||
should.exist(node);
|
||||
node.should.be.ok;
|
||||
});
|
||||
|
||||
it('should return the correct (primitive) data', function() {
|
||||
var node = list.createNewNode('test data');
|
||||
var data = node.getData();
|
||||
data.should.not.be.an.Object;
|
||||
data.should.be.a.String;
|
||||
data.should.equal('test data');
|
||||
|
||||
node.data = 42;
|
||||
data = node.getData();
|
||||
data.should.not.be.an.Object;
|
||||
data.should.be.a.Number;
|
||||
data.should.equal(42);
|
||||
|
||||
});
|
||||
|
||||
it('should return the correct (object) data', function() {
|
||||
var node = list.createNewNode({
|
||||
name: 'test item',
|
||||
number: 1
|
||||
});
|
||||
var data = node.getData();
|
||||
data.should.be.an.Object;
|
||||
node.toString().should.equal('{"name":"test item","number":1}');
|
||||
});
|
||||
|
||||
it('should return whether or not it has a next node', function() {
|
||||
var firstNode = list.createNewNode('first node');
|
||||
var secondNode = list.createNewNode('second node');
|
||||
firstNode.next = secondNode;
|
||||
firstNode.hasNext().should.equal(true);
|
||||
});
|
||||
|
||||
it('should return whether or not it has a previous node', function() {
|
||||
var firstNode = list.createNewNode('first node');
|
||||
var secondNode = list.createNewNode('second node');
|
||||
secondNode.prev = firstNode;
|
||||
secondNode.hasPrev().should.equal(true);
|
||||
});
|
||||
|
||||
it('should return a proper string representation of its data', function() {
|
||||
var node = list.createNewNode({name: 'test item', number: 1});
|
||||
node.toString().should.equal('{"name":"test item","number":1}');
|
||||
|
||||
node.data = 'string data';
|
||||
node.toString().should.equal('string data');
|
||||
|
||||
node.data = 42;
|
||||
node.toString().should.equal('42');
|
||||
});
|
||||
});
|
||||
1833
build/node_modules/dbly-linked-list/yarn.lock
generated
vendored
Normal file
1833
build/node_modules/dbly-linked-list/yarn.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user