Implement non-native data structures in JavaScript with style.
Sometimes, the built-in data structures in JavaScript simply aren't adequate for the application being developed.
Fear not. DS-Plus gives developers fast and reliable data structures.
To use DS-Plus
in one's project, all one needs to do is download its package with the following command:npm i ds-plus
Queues are very easy to implement with Plus. There are two initialization options for the data storage in the queue: an array, or a linked list.
constructor(data = null)
Initialize a new Queue
object. Possible parameter(s) are: 'linkedlist'
.
The returned Queue
object has the following structure:
. . . . .
enqueue(...arguments)
Appends element(s) to the end of the data
property. To pass several elements at once, simply separate each element by a comma.
. . . . .
dequeue()
Removes and returns the first element from the data
property. Returns null
if the store is empty.
. . . . .
front()
Returns the first element or node from the data
property. Returns undefined
or null
if there are no elements.
. . . . .
rear()
Returns the last element or node from the data
property. Returns undefined
or null
if there are no elements.
. . . . .
search(value)
Returns the element or node from the data
property if it exists. Returns null
if there are no elements.
. . . . .
length()
Returns the length of the data
property. If a LinkedList
object is empty, it will still have a length of 1, since it still technically has a node: { val: null, next: null }
.
Stacks are almost identical to the Queue
objects in Plus. There are also only two initialization options for the data storage, just like in a Queue
object: an array, or a linked list.
constructor(data = null)
Initialize a new Stack
object. Possible parameter(s) are: 'linkedlist'
.
The returned Stack
object has the following structure:
. . . . .
push(...arguments)
Appends element(s) to the end of the data
property. To pass several elements at once, simply separate each element by a comma.
. . . . .
pop()
Removes and returns the last element from the data
property. Returns null
if the store is empty.
. . . . .
peek()
Returns the last element or node from the data
property. Returns undefined
or null
if there are no elements.
. . . . .
isEmpty()
Returns true || false
based on whether the data
property has data or not.
. . . . .
search(value)
Returns the element or node from the data
property if it exists. Returns null
if there are no elements.
. . . . .
length()
Returns the length of the data
property. If a LinkedList
object is empty, it will still have a length of 1, since it still technically has a node: { val: null, next: null }
.
The Linked List
object is exactly what a developer would expect: a head node with a single next
pointer to the next node or null
.
constructor(value = null)
Initialize a new Linked List
object. Possible parameter(s) are any valid data in JavaScript. May or may not be initialized with a value.
The returned Linked List
object has the following structure:
. . . . .
assignHeadValue(value = null)
Assigns the head node's value to the passed parameter. This method can be used in the case that the Linked List
object is initialized without a value, or when the first node's value should be changed.
. . . . .
insert(...newData)
Inserts elements of ...newData
as nodes to the tail of the linked list. Returns this
for daisy-chaining.
. . . . .
insertAtIndex(index, ...newData)
Inserts elements of ...newData
as nodes at the passed index of the linked list. Does not overwrite nodes already in the linked list. Returns this
for daisy-chaining.
. . . . .
removeByValue(value)
Removes the first node with given value and returns value
. Returns null
if the value is not found.
. . . . .
removeByIndex(index)
Removes the first node with given value and returns value
. Returns null
if the index is not found, the index is not a number, or the index is less than -1
.
. . . . .
getNodeAtIndex(index)
Returns the node at the given index. Returns null
if the index is not found.
. . . . .
getNodeIndexByValue(value)
Returns the first node and index for the given value.
The returned object
has the following structure:
. . . . .
updateValueAtIndex(index, value)
Updates the val
property of the node at the given index
. Returns this || null
depending on the success of the invocation.
. . . . .
getMiddleNode()
Returns the node in the middle of the Linked List
object. Returns undefined
for a list with no middle.
. . . . .
tail()
Returns the last node in the Linked List
object.
. . . . .
removeByTail()
Removes the last node in the Linked List
object. Returns value
from deleted node.
. . . . .
toArray()
Returns []
comprised of the values from the nodes in the Linked List
object, starting from the head and ending with the tail.
. . . . .
reverse()
Returns this
and destructively reverses the nodes in the Linked List
object, starting from the head and ending with the tail.
. . . . .
clear()
Returns this
and destructively clears the nodes in the Linked List
object.
. . . . .
contains(value)
Returns true || false
depending on whether the passed value can be found in the Linked List
object.
. . . . .
length()
Returns this.size
, which is a count of the nodes in the Linked List
object. This will always be an integer greater than or equal to 1
.
. . . . .
count(value = null)
Returns count of how many nodes in the Linked List
object have a val
property with value
.
. . . . .
countMultiple(...values)
Returns an object with properties which represent the count of that given property in the Linked List
object. The value must be deeply equal to the val
property of a given node. Only strings and numbers may be used as values. Use count(value)
for getting the count of specific objects.
The main difference between BinaryTree
and BST
objects are that the former have no data constraints. This means that any data can be inserted into the tree; however, the BST
object enforces data consistency which creates O(log2n)
search, insert, and removal times.
constructor(array = [1])
Initialize a new BinaryTree
object. Possible parameter value(s) are: []
.
Use undefined
for nodes in the tree which should be null
.
The returned BinaryTree
object has the following structure:
Nodes are inserted in level-order, meaning that the number of nodes possible for a given level dictates where each node is placed. The first level, the root, has one possible node, so the first element of [1, 2, 3, undefined...]
is converted to a node in that level. The next level has two possible nodes, so the next two values in the array are the left
and right
nodes of the root
node. Each level doubles in size.
Since the placement of nodes is entirely up the []
passed in as the parameter, it is possible that the binary tree will have nodes attached to a node with a null
value. This may cause problems with searching for values in certain cases. For absolute certainty in the validity of the tree structure, use the BST
object.
. . . . .
insert(value)
Replaces a null
value in either the left
or right
property with a new node with passed value
. Only one element may be passed at a time. left
is evaluated for a null
before right
.
Returns this
for daisy chaining.
The value is inserted in level-order, meaning that the first node in the level with either a null left
or right
is replaced with a new TreeNode
with the passed value
.
. . . . .
remove(value)
Removes the first node with the passed value
and returns this
for daisy chaining. Will not return null
if the given value
cannot be found.
. . . . .
getNode(value)
Returns the first node with the passed value
. Will return null
if the node cannot be found.
. . . . .
findHeight(node)
Returns a number
representing the height of the passed node
. Throws an error if the passed node
does not have TreeNode
as its prototype object.
. . . . .
findMaxDepth()
Returns a number
representing the maximum depth of this.root
.
. . . . .
getValuesTraversal(type = 'post')
Returns an []
representing the elements in a certain order traversal. The possible options are in: ['post', 'pre', 'in']
. Will not include null
values in the return value.
. . . . .
manipulateTraversal(func, type = 'post')
Mutates this.root
with the passed function, func
, in whatever order designated by the passed type
parameter. The possible options for type
are: ['post', 'pre', 'in']
. Returns this
which makes it daisy chainable.
BST
objects are self-balancing, meaning that the difference in height between the left
and right
branches of a given node cannot be less than -1 or greater than 1.
The type of Binary Search Tree used in this class is an AVL Tree.
All nodes in the tree must have unique values.
constructor(dataType, options)
Initialize a new BST
object.
The dataType
parameter represents the single type of data that the initialized BST
object can store. The possible options are in the following array and correspond to the actual primitive and/or object in vanilla JavaScript: ['number', 'string', 'date', 'object']
. Only pass one string, otherwise an error will be thrown.
The options
parameter represents an optional object which may be passed into the constructor function to further customize the way data is handled in the BST
object. The only properties available to this object are in the following arrays: ['key', 'keyType', 'compareFunction']
for 'object'
typed trees, and ['compareFunction']
for ['number', 'string', 'date']
typed trees.
key
represents the property that will be on every object passed into the BST
object. This key is then used to sort and balance the tree as elements are inserted and removed. This must be a string.
keyType
represents the type of primitive data that will be stored in the key
property of each object. The available options are in the following array: ['string', 'number']
. Incorrect values will result in thrown errors.
compareFunction
represents the function which will be used to determine if one value is less than another value. Using this, the tree will insert, remove, and rebalance itself. This can be passed with any data type, not just object
.
The function must come in the following form:
BST
objects may be instantiated as shown in the following code snippet:
The returned BST
object has the following structure:
. . . . .
insert(values)
Inserts node(s) with the passed value
property. To pass several elements at once, pass an []
with the elements separated with commas.
. . . . .
remove(values)
Removes node(s) with the passed value
property. To pass several elements at once, pass an []
with the elements separated with commas. Returns this
, so methods can be chained after its invocation.
. . . . .
maxValue(root = this.root)
Returns the node with the greatest val
property.
. . . . .
minValue(root = this.root)
Returns the node with the smallest val
property.
. . . . .
search(value, root = this.root)
Returns the node from this.root
with the passed value
if it exists. Returns null
if there are no elements which match the passed value.
Objects
will be matched with the toString()
method, so deep equality is not necessary for the search
method to return the correct node.
. . . . .
length()
Returns this.size
, which is the number of nodes in the tree.
. . . . .
contains(value)
Returns true || false
, depending on if value
is a property on this.duplicates
with true
value.
. . . . .
isEmpty()
Returns true || false
, depending on if this.root
is null
.
. . . . .
getValuesTraversal(type = 'post')
Returns an []
representing the elements in a certain order traversal. The possible options are in: ['post', 'pre', 'in']
. Will not include null
values in the return value.
The Graph
object in DS-Plus takes the form of an Adjacency List, which is an efficient implementation of a graph. Vertices are stored as keys in an object for O(1) lookup time.
constructor(dataType, direction)
Initialize a new Graph
object.
The returned Graph
object has the following structure:
The dataType
parameter can take either of the following options: ['string', 'number', 'object']
. As one can guess, these are the three kinds of data that can be stored in the data
property of the Graph
object.
The direction
parameter can take either of the following options: ['one', 'two']
. This parameter determines the whether or not an edge is bi-directional or uni-directional.
If 'one'
is selected, an edge will only go in one direction. Check the following example to see the difference between 'one'
and 'two'
.
. . . . .
addVertices(...vertices)
Inserts vertice(s) to the data
property as keys. The keys will have []
value by default. To pass several elements at once, simply separate each element by a comma.
Objects passed into this method will be converted to strings with JSON.stringify(obj)
.
Errors will be thrown for invalid data or already existing vertices being passed into this method.
Returns this
for method chaining.
. . . . .
removeVertex(vertex)
Removes and returns the vertex
that was passed into the method. This will mutate the other vertexes accordingly and requires no repointing on the developer's end.
. . . . .
addEdges(vertex, arr)
Inserts edges from arr
for the passed vertex
and returns this
for method chaining.
Errors will be thrown for incorrect data, missing parameters, or if arr
is not an Array
object.
. . . . .
removeEdges(vertex, arr)
Removes edges from arr
for the passed vertex
and returns this
for method chaining.
Errors will be thrown for incorrect data, missing parameters, or if arr
is not an Array
object.
. . . . .
getSize()
Returns the number of vertices in the Graph
object.
. . . . .
getEdges(vertex)
Returns the []
of edges for the passed vertex
.
Errors will be thrown for vertices which are not in the data
property.
. . . . .
numberOfEdges(vertex)
Returns the number of elements in []
of the passed vertex
.
null
will be returned for vertices which are not in the data
property.
. . . . .
hasEdge(vertexOne, vertexTwo)
Returns true || false
based on if vertexOne
has vertexTwo
as one of its edges.
Errors will be thrown for vertices which are not in the data
property.
. . . . .
hasVertex(vertex)
Returns true || false
based on if vertex
is a property in the data
object.
. . . . .
edgesToArray(vertex)
Returns [[vertex, edgeOne], [vertex, edgeTwo] ...]
based on the []
for a given vertex
. Essentially, it will return sub-arrays of all the pairs of edges possible for a given vertex.
Errors will be thrown for vertices which are not in the data
property.