v1.3.1 published, new Queue implemented from SinglyLinkedList, and ArrayQueue implemented from Array

This commit is contained in:
Revone 2023-09-18 22:04:39 +08:00
parent b00964c6fc
commit 55704871b6
10 changed files with 695 additions and 528 deletions

View file

@ -1,19 +1,18 @@
# What
## Brief
Javascript & TypeScript Data Structure collections.
Data Structures of Javascript & TypeScript.
## Algorithms
DFS, DFSIterative, BFS, morris, Bellman-Ford Algorithm, Dijkstra's Algorithm, Floyd-Warshall Algorithm, Tarjan's Algorithm. Listed only a few out, you can discover more in API docs
## Code design
By strictly adhering to object-oriented design (BinaryTree -> BST -> AVLTree -> TreeMultiset), you can seamlessly inherit the existing data structures to implement the customized ones you need. Object-oriented design stands as the optimal approach to data structure design.
## Built-in classic algorithms
DFS(Depth-First Search), DFSIterative, BFS(Breadth-First Search),
morris, Bellman-Ford Algorithm, Dijkstra's Algorithm, Floyd-Warshall Algorithm,
Tarjan's Algorithm.
# How
## install
### npm
```bash
npm install data-structure-typed
npm install data-structure-typed --save
```
### yarn
```bash
@ -28,17 +27,13 @@ const {AVLTree} = dataStructureTyped;
const {Heap, MinHeap, SinglyLinkedList, Stack, AVLTreeNode, BST, Trie, DirectedGraph, DirectedVertex, TreeMultiset} = dataStructureTyped;
```
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/dfs-pre-order.webp?raw=true)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/test-avl-tree.webp?raw=true)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/map-graph.webp?raw=true)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/test-graphs.webp?raw=true)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/cut-off-trees-for-golf.webp?raw=true)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/parenthesis-check.webp?raw=true)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/binary-tree-array-to-binary-tree.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/binary-tree-dfs-in-order.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/avl-tree-test.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/tree-multiset-test.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/matrix-cut-off-tree-for-golf.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/directed-graph-test.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/map-graph-test.webp)
## API docs & Examples
@ -46,12 +41,10 @@ const {Heap, MinHeap, SinglyLinkedList, Stack, AVLTreeNode, BST, Trie, DirectedG
[Live Examples](https://vivid-algorithm.vercel.app)
[//]: # (<a href="https://vivid-algorithm.vercel.app" target="_blank">Live Examples</a>)
<a href="https://github.com/zrwusa/vivid-algorithm" target="_blank">Examples Repository</a>
## Code Snippet
### Binary Search Tree (BST) snippet
#### TS
```typescript
import {BST, BSTNode} from 'data-structure-typed';
@ -142,7 +135,6 @@ const {Heap, MinHeap, SinglyLinkedList, Stack, AVLTreeNode, BST, Trie, DirectedG
```
### Directed Graph simple snippet
#### TS or JS
```typescript
import {DirectedGraph} from 'data-structure-typed';
@ -172,7 +164,6 @@ import {DirectedGraph} from 'data-structure-typed';
```
### Undirected Graph snippet
#### TS or JS
```typescript
import {UndirectedGraph} from 'data-structure-typed';
@ -189,6 +180,7 @@ import {UndirectedGraph} from 'data-structure-typed';
const dijkstraResult = graph.dijkstra('A');
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id) // ['A', 'B', 'D']
```
## Data Structures
<table>
<thead>
@ -431,7 +423,6 @@ import {UndirectedGraph} from 'data-structure-typed';
## Complexities
### performance of Big O
<table>
<thead>
<tr>
@ -496,7 +487,6 @@ import {UndirectedGraph} from 'data-structure-typed';
</table>
### Data Structure Complexity
<table>
<thead>
<tr>
@ -593,7 +583,6 @@ import {UndirectedGraph} from 'data-structure-typed';
</table>
### Sorting Complexity
<table>
<thead>
<tr>
@ -691,6 +680,9 @@ import {UndirectedGraph} from 'data-structure-typed';
</tbody>
</table>
## Code design
By strictly adhering to object-oriented design (BinaryTree -> BST -> AVLTree -> TreeMultiset), you can seamlessly inherit the existing data structures to implement the customized ones you need. Object-oriented design stands as the optimal approach to data structure design.
[//]: # (![overview diagram]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/assets/overview-diagram-of-data-structures.png?raw=true&#41;)
![complexities](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/assets/complexities-diff.jpg?raw=true)

View file

@ -1,7 +1,7 @@
{
"name": "data-structure-typed",
"version": "1.21.4",
"description": "Javascript & TypeScript Data Structure Library, meticulously crafted to empower developers with a versatile set of essential data structures. Our library includes a wide range of data structures, such as Binary Tree, AVL Tree, Binary Search Tree (BST), Tree Multiset, Segment Tree, Binary Indexed Tree, Graph, Directed Graph, Undirected Graph, Singly Linked List, Hash, CoordinateSet, CoordinateMap, Heap, Doubly Linked List, Priority Queue, Max Priority Queue, Min Priority Queue, Queue, ObjectDeque, ArrayDeque, Stack, and Trie. Each data structure is thoughtfully designed and implemented using TypeScript to provide efficient, reliable, and easy-to-use solutions for your programming needs. Whether you're optimizing algorithms, managing data, or enhancing performance, our TypeScript Data Structure Library is your go-to resource. Elevate your coding experience with these fundamental building blocks for software development.",
"version": "1.3.1",
"description": "Data Structures of Javascript & TypeScript. AVLTree, Binary Search Tree, Binary Tree, Tree Multiset, Graph, Heap, Priority Queue, Linked List.",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
@ -19,38 +19,111 @@
"url": "git+https://github.com/zrwusa/data-structure-typed.git"
},
"keywords": [
"data structure",
"Data Structure",
"data-structure",
"data structures",
"Data Structures",
"data-structures",
"algorithm",
"binary search tree",
"Binary Search Tree",
"binary-search-tree",
"binary tree",
"Binary Tree",
"Binary Search Tree (BST)",
"binary-tree",
"bst",
"BST",
"AVL Tree",
"avl tree",
"avl-tree",
"avl",
"tree multiset",
"Tree Multiset",
"Segment Tree",
"Binary Indexed Tree",
"Graph",
"Directed Graph",
"Undirected Graph",
"Linked List",
"Singly Linked List",
"Doubly Linked List",
"Queue",
"Object Deque",
"Array Deque",
"Stack",
"Hash",
"Coordinate Set",
"Coordinate Map",
"Heap",
"Priority Queue",
"Max Priority Queue",
"Min Priority Queue",
"Trie",
"tree-multiset",
"Tree Multiset",
"dfs",
"DFS",
"DFSIterative",
"dfs iterative",
"DFS Iterative",
"bfs",
"BFS",
"graph",
"Graph",
"directed graph",
"Directed Graph",
"directed-graph",
"undirected graph",
"Undirected Graph",
"undirected-graph",
"heap",
"Heap",
"priority queue",
"Priority Queue",
"priority-queue",
"max priority queue",
"Max Priority Queue",
"max-priority-queue",
"min priority queue",
"Min Priority Queue",
"min-priority-queue",
"deque",
"Deque",
"linked list",
"Linked List",
"linked-list",
"trie",
"Trie",
"prefix tree",
"Prefix Tree",
"prefix-tree",
"binary",
"DataStructure",
"DataStructures",
"data",
"structure",
"sort",
"segment tree",
"Segment Tree",
"segment-tree",
"binary indexed tree",
"Binary Indexed Tree",
"binary-indexed-tree",
"linked list",
"Linked List",
"linked-list",
"singly linked list",
"Singly Linked List",
"singly-linked-list",
"doubly linked list",
"Doubly Linked List",
"doubly-linked-list",
"queue",
"array queue",
"Array Queue",
"array-queue",
"Queue",
"object deque",
"Object Deque",
"array deque",
"Array Deque",
"stack",
"Stack",
"hash",
"Hash",
"morris",
"Bellman-Ford ",
"Dijkstra's Algorithm",
"Floyd-Warshall Algorithm",
"Tarjan's Algorithm"
"Morris",
"bellman ford",
"Bellman Ford",
"bellman-ford",
"dijkstra",
"Dijkstra",
"floyd warshall",
"Floyd Warshall",
"floyd-warshall",
"Tarjan",
"tarjan",
"Tarjan's"
],
"author": "Tyler Zeng zrwusa@gmail.com",
"license": "MIT",

View file

@ -725,7 +725,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function isBST checks if the binary search tree is valid.
* The function isBST checks if the binary tree is valid binary search tree.
* @returns The `isBST()` function is returning a boolean value.
*/
isBST(): boolean {

View file

@ -48,7 +48,7 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
// TODO support node as a param
const inserted = super.add(id, val);
if (inserted) this.balancePath(inserted);
if (inserted) this._balancePath(inserted);
return inserted;
}
@ -66,7 +66,7 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
const deletedResults = super.remove(id, isUpdateAllLeftSum);
for (const {needBalanced} of deletedResults) {
if (needBalanced) {
this.balancePath(needBalanced);
this._balancePath(needBalanced);
}
}
return deletedResults;
@ -78,7 +78,7 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
* @param node - The parameter "node" is of type N, which represents a node in an AVL tree.
* @returns The balance factor of the given AVL tree node.
*/
balanceFactor(node: N): number {
protected _balanceFactor(node: N): number {
if (!node.right) // node has no right subtree
return -node.height;
else if (!node.left) // node has no left subtree
@ -91,7 +91,7 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
* The function updates the height of a node in an AVL tree based on the heights of its left and right subtrees.
* @param node - The parameter `node` is an AVLTreeNode object, which represents a node in an AVL tree.
*/
updateHeight(node: N): void {
protected _updateHeight(node: N): void {
if (!node.left && !node.right) // node is a leaf
node.height = 0;
else if (!node.left) {
@ -105,31 +105,31 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
}
/**
* The `balancePath` function balances the AVL tree by performing appropriate rotations based on the balance factor of
* The `_balancePath` function balances the AVL tree by performing appropriate rotations based on the balance factor of
* each node in the path from the given node to the root.
* @param node - The `node` parameter is an AVLTreeNode object, which represents a node in an AVL tree.
*/
balancePath(node: N): void {
protected _balancePath(node: N): void {
const path = this.getPathToRoot(node);
for (let i = path.length - 1; i >= 0; i--) {
const A = path[i];
this.updateHeight(A);
switch (this.balanceFactor(A)) {
this._updateHeight(A);
switch (this._balanceFactor(A)) {
case -2:
if (A && A.left) {
if (this.balanceFactor(A.left) <= 0) {
this.balanceLL(A); // Perform LL rotation
if (this._balanceFactor(A.left) <= 0) {
this._balanceLL(A); // Perform LL rotation
} else {
this.balanceLR(A); // Perform LR rotation
this._balanceLR(A); // Perform LR rotation
}
}
break;
case +2:
if (A && A.right) {
if (this.balanceFactor(A.right) >= 0) {
this.balanceRR(A); // Perform RR rotation
if (this._balanceFactor(A.right) >= 0) {
this._balanceRR(A); // Perform RR rotation
} else {
this.balanceRL(A); // Perform RL rotation
this._balanceRL(A); // Perform RL rotation
}
}
}
@ -137,10 +137,10 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
}
/**
* The `balanceLL` function performs a left-left rotation on an AVL tree to balance it.
* The `_balanceLL` function performs a left-left rotation on an AVL tree to balance it.
* @param A - The parameter A is an AVLTreeNode object.
*/
balanceLL(A: N): void {
protected _balanceLL(A: N): void {
const parentOfA = A.parent;
const B = A.left; // A is left-heavy and B is left-heavy
A.parent = B;
@ -162,15 +162,15 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
A.left = B.right; // Make T2 the left subtree of A
B.right = A; // Make A the left child of B
}
this.updateHeight(A);
if (B) this.updateHeight(B);
this._updateHeight(A);
if (B) this._updateHeight(B);
}
/**
* The `balanceLR` function performs a left-right rotation to balance an AVL tree.
* The `_balanceLR` function performs a left-right rotation to balance an AVL tree.
* @param A - A is an AVLTreeNode object.
*/
balanceLR(A: N): void {
protected _balanceLR(A: N): void {
const parentOfA = A.parent;
const B = A.left; // A is left-heavy
let C = null;
@ -209,16 +209,16 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
C.right = A;
}
this.updateHeight(A); // Adjust heights
B && this.updateHeight(B);
C && this.updateHeight(C);
this._updateHeight(A); // Adjust heights
B && this._updateHeight(B);
C && this._updateHeight(C);
}
/**
* The `balanceRR` function performs a right-right rotation on an AVL tree to balance it.
* The `_balanceRR` function performs a right-right rotation on an AVL tree to balance it.
* @param A - The parameter A is an AVLTreeNode object.
*/
balanceRR(A: N): void {
protected _balanceRR(A: N): void {
const parentOfA = A.parent;
const B = A.right; // A is right-heavy and B is right-heavy
A.parent = B;
@ -245,15 +245,15 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
A.right = B.left; // Make T2 the right subtree of A
B.left = A;
}
this.updateHeight(A);
B && this.updateHeight(B);
this._updateHeight(A);
B && this._updateHeight(B);
}
/**
* The `balanceRL` function performs a right-left rotation to balance an AVL tree.
* The `_balanceRL` function performs a right-left rotation to balance an AVL tree.
* @param A - A is an AVLTreeNode object.
*/
balanceRL(A: N): void {
protected _balanceRL(A: N): void {
const parentOfA = A.parent;
const B = A.right; // A is right-heavy
let C = null;
@ -292,9 +292,9 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
if (C) C.left = A;
if (C) C.right = B;
this.updateHeight(A); // Adjust heights
B && this.updateHeight(B);
C && this.updateHeight(C);
this._updateHeight(A); // Adjust heights
B && this._updateHeight(B);
C && this._updateHeight(C);
}
}

View file

@ -173,7 +173,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
}
}
}
if (inserted) this.balancePath(inserted);
if (inserted) this._balancePath(inserted);
return inserted;
}
@ -351,7 +351,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
if (needBalanced) {
this.balancePath(needBalanced);
this._balancePath(needBalanced);
}
return bstDeletedResult;

View file

@ -38,7 +38,7 @@ export class SinglyLinkedListNode<T = number> {
}
}
export class SinglyLinkedList<T = number> {
export class SinglyLinkedList<T = any> {
/**
* The constructor initializes the linked list with an empty head, tail, and length.
@ -116,8 +116,8 @@ export class SinglyLinkedList<T = number> {
* @returns The method `pop()` returns the value of the node that is being removed from the end of the linked list. If
* the linked list is empty, it returns `null`.
*/
pop(): T | null {
if (!this.head) return null;
pop(): T | undefined {
if (!this.head) return undefined;
if (this.head === this.tail) {
const val = this.head.val;
this.head = null;
@ -141,8 +141,8 @@ export class SinglyLinkedList<T = number> {
* The `shift()` function removes and returns the value of the first node in a linked list.
* @returns The value of the node that is being removed from the beginning of the linked list.
*/
shift(): T | null {
if (!this.head) return null;
shift(): T | undefined {
if (!this.head) return undefined;
const removedNode = this.head;
this.head = this.head.next;
this._length--;
@ -204,8 +204,8 @@ export class SinglyLinkedList<T = number> {
* @returns The method `deleteAt` returns the value of the node that was deleted, or `null` if the index is out of
* bounds.
*/
deleteAt(index: number): T | null {
if (index < 0 || index >= this.length) return null;
deleteAt(index: number): T | undefined {
if (index < 0 || index >= this.length) return undefined;
if (index === 0) return this.shift();
if (index === this.length - 1) return this.pop();

View file

@ -63,6 +63,11 @@ export class ObjectDeque<T = number> {
return this._size;
}
/**
* The "addFirst" function adds a value to the beginning of an array-like data structure.
* @param {T} value - The `value` parameter represents the value that you want to add to the beginning of the data
* structure.
*/
addFirst(value: T) {
if (this._size === 0) {
const mid = Math.floor(this._capacity / 2);
@ -75,6 +80,10 @@ export class ObjectDeque<T = number> {
this._size++;
}
/**
* The addLast function adds a value to the end of an array-like data structure.
* @param {T} value - The `value` parameter represents the value that you want to add to the end of the data structure.
*/
addLast(value: T) {
if (this._size === 0) {
const mid = Math.floor(this._capacity / 2);
@ -87,6 +96,10 @@ export class ObjectDeque<T = number> {
this._size++;
}
/**
* The function `pollFirst()` removes and returns the first element in a data structure.
* @returns The value of the first element in the data structure.
*/
pollFirst() {
if (!this._size) return;
const value = this.peekFirst();
@ -96,10 +109,18 @@ export class ObjectDeque<T = number> {
return value;
}
/**
* The `peekFirst` function returns the first element in an array-like data structure if it exists.
* @returns The element at the first position of the `_nodes` array.
*/
peekFirst() {
if (this._size) return this._nodes[this._first];
}
/**
* The `pollLast()` function removes and returns the last element in a data structure.
* @returns The value that was removed from the data structure.
*/
pollLast() {
if (!this._size) return;
const value = this.peekLast();
@ -110,14 +131,29 @@ export class ObjectDeque<T = number> {
return value;
}
/**
* The `peekLast()` function returns the last element in an array-like data structure.
* @returns The last element in the array "_nodes" is being returned.
*/
peekLast() {
if (this._size) return this._nodes[this._last];
}
/**
* The get function returns the element at the specified index in an array-like data structure.
* @param {number} index - The index parameter is a number that represents the position of the element you want to
* retrieve from the array.
* @returns The element at the specified index in the `_nodes` array is being returned. If there is no element at that
* index, `null` is returned.
*/
get(index: number) {
return this._nodes[this._first + index] || null;
}
/**
* The function checks if the size of a data structure is less than or equal to zero.
* @returns The method is returning a boolean value indicating whether the size of the object is less than or equal to 0.
*/
isEmpty() {
return this._size <= 0;
}
@ -140,6 +176,10 @@ export class ArrayDeque<T> {
return this._nodes.length;
}
/**
* O(n) time complexity of adding at the beginning and the end
*/
/**
* The function "addLast" adds a value to the end of an array.
* @param {T} value - The value parameter represents the value that you want to add to the end of the array.
@ -166,6 +206,10 @@ export class ArrayDeque<T> {
return this._nodes.shift() ?? null;
}
/**
* O(n) time complexity of adding at the beginning and the end
*/
/**
* The function "addFirst" adds a value to the beginning of an array.
* @param {T} value - The value parameter represents the value that you want to add to the beginning of the array.
@ -193,6 +237,10 @@ export class ArrayDeque<T> {
return this._nodes[this._nodes.length - 1] ?? null;
}
/**
* O(1) time complexity of obtaining the value
*/
/**
* The get function returns the element at the specified index in an array, or null if the index is out of bounds.
* @param {number} index - The index parameter is a number that represents the position of the element you want to

View file

@ -3,7 +3,45 @@
* @copyright Tyler Zeng <zrwusa@gmail.com>
* @class
*/
export class Queue<T = number> {
import {SinglyLinkedList} from '../linked-list';
export class Queue<T = any> extends SinglyLinkedList<T> {
/**
* The enqueue function adds a value to the end of an array.
* @param {T} value - The value parameter represents the value that you want to add to the queue.
*/
enqueue(value: T) {
this.push(value);
}
/**
* The `dequeue` function removes and returns the first element from a queue, or returns null if the queue is empty.
* @returns The method is returning the element at the front of the queue, or null if the queue is empty.
*/
dequeue(): T | undefined {
return this.shift();
}
/**
* The `peek` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `peek()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.
*/
peek(): T | undefined {
return this.head?.val;
}
* [Symbol.iterator]() {
let current = this.head;
while (current) {
yield current.val;
current = current.next;
}
}
}
export class ArrayQueue<T = number> {
protected _nodes: T[];
protected _offset: number;
@ -18,6 +56,14 @@ export class Queue<T = number> {
this._offset = 0;
}
/**
* The size function returns the number of elements in an array.
* @returns {number} The size of the array, which is the difference between the length of the array and the offset.
*/
get size(): number {
return this._nodes.length - this._offset;
}
/**
* The function "fromArray" creates a new Queue object from an array of elements.Creates a queue from an existing array.
* @public
@ -26,27 +72,27 @@ export class Queue<T = number> {
* @returns The method is returning a new instance of the Queue class, initialized with the elements from the input
* array.
*/
static fromArray<T>(elements: T[]): Queue<T> {
return new Queue(elements);
static fromArray<T>(elements: T[]): ArrayQueue<T> {
return new ArrayQueue(elements);
}
/**
* The add function adds an element to the end of the queue and returns the updated queue.Adds an element at the back of the queue.
* The push function adds an element to the end of the queue and returns the updated queue.Adds an element at the back of the queue.
* @param {T} element - The `element` parameter represents the element that you want to add to the queue.
* @returns The `add` method is returning a `Queue<T>` object.
*/
add(element: T): Queue<T> {
push(element: T): ArrayQueue<T> {
this._nodes.push(element);
return this;
}
/**
* The `poll` function removes and returns the first element in the queue, and adjusts the internal data structure if
* The `shift` function removes and returns the first element in the queue, and adjusts the internal data structure if
* necessary to optimize performance.
* @returns The function `poll()` returns either the first element in the queue or `null` if the queue is empty.
* @returns The function `shift()` returns either the first element in the queue or `null` if the queue is empty.
*/
poll(): T | null {
if (this.size() === 0) return null;
shift(): T | null {
if (this.size === 0) return null;
const first = this.peek();
this._offset += 1;
@ -66,7 +112,7 @@ export class Queue<T = number> {
* the `_offset` index. If the data structure is empty (size is 0), it returns `null`.
*/
peek(): T | null {
return this.size() > 0 ? this._nodes[this._offset] : null;
return this.size > 0 ? this._nodes[this._offset] : null;
}
/**
@ -75,15 +121,23 @@ export class Queue<T = number> {
* array is empty, it returns `null`.
*/
peekLast(): T | null {
return this.size() > 0 ? this._nodes[this._nodes.length - 1] : null;
return this.size > 0 ? this._nodes[this._nodes.length - 1] : null;
}
/**
* The size function returns the number of elements in an array.
* @returns {number} The size of the array, which is the difference between the length of the array and the offset.
* The enqueue function adds a value to the end of a queue.
* @param {T} value - The value parameter represents the value that you want to add to the queue.
*/
size(): number {
return this._nodes.length - this._offset;
enqueue(value: T) {
this.push(value);
}
/**
* The `dequeue` function removes and returns the first element from a queue, or returns null if the queue is empty.
* @returns The method is returning a value of type T or null.
*/
dequeue(): T | null {
return this.shift();
}
/**
@ -91,7 +145,7 @@ export class Queue<T = number> {
* @returns {boolean} A boolean value indicating whether the size of the object is 0 or not.
*/
isEmpty(): boolean {
return this.size() === 0;
return this.size === 0;
}
/**
@ -114,7 +168,7 @@ export class Queue<T = number> {
* The `clone()` function returns a new Queue object with the same elements as the original Queue.
* @returns The `clone()` method is returning a new instance of the `Queue` class.
*/
clone(): Queue<T> {
return new Queue(this._nodes.slice(this._offset));
clone(): ArrayQueue<T> {
return new ArrayQueue(this._nodes.slice(this._offset));
}
}

View file

@ -12,17 +12,17 @@ export interface IAVLTree<N extends AVLTreeNode<N['val'], N>> extends IBST<N> {
remove(id: BinaryTreeNodeId, isUpdateAllLeftSum?: boolean): BinaryTreeDeletedResult<N>[]
balanceFactor(node: N): number
updateHeight(node: N): void
balancePath(node: N): void
balanceLL(A: N): void
balanceLR(A: N): void
balanceRR(A: N): void
balanceRL(A: N): void
// _balanceFactor(node: N): number
//
// _updateHeight(node: N): void
//
// _balancePath(node: N): void
//
// _balanceLL(A: N): void
//
// _balanceLR(A: N): void
//
// _balanceRR(A: N): void
//
// _balanceRL(A: N): void
}

View file

@ -1,401 +1,401 @@
import {SinglyLinkedList} from '../../../../src';
import {magnitude} from '../constants';
describe('SinglyLinkedList Operation Test', () => {
let list: SinglyLinkedList<number>;
let objectList: SinglyLinkedList<{ keyA: number }>;
beforeEach(() => {
list = new SinglyLinkedList<number>();
objectList = new SinglyLinkedList<{ keyA: number }>();
});
describe('push', () => {
it('should add elements to the end of the list', () => {
list.push(1);
list.push(2);
expect(list.toArray()).toEqual([1, 2]);
});
});
describe('pop', () => {
it('should remove and return the last element of the list', () => {
list.push(1);
list.push(2);
const popped = list.pop();
expect(popped).toBe(2);
expect(list.toArray()).toEqual([1]);
});
it('should return undefined if the list is empty', () => {
const popped = list.pop();
expect(popped).toBeNull();
});
});
describe('shift', () => {
it('should remove and return the first element of the list', () => {
list.push(1);
list.push(2);
const shifted = list.shift();
expect(shifted).toBe(1);
expect(list.toArray()).toEqual([2]);
});
it('should return undefined if the list is empty', () => {
const shifted = list.shift();
expect(shifted).toBeNull();
});
});
describe('unshift', () => {
it('should add elements to the beginning of the list', () => {
list.unshift(1);
list.unshift(2);
expect(list.toArray()).toEqual([2, 1]);
});
});
describe('get', () => {
it('should return the element at the specified index', () => {
list.push(1);
list.push(2);
list.push(3);
const element = list.getAt(1);
expect(element).toBe(2);
});
it('should return undefined for an out-of-bounds index', () => {
list.push(1);
const element = list.getAt(1);
expect(element).toBeNull();
});
});
describe('insertAfter', () => {
it('should insert an element after an existing value', () => {
list.push(1);
list.push(2);
list.push(3);
list.insertAfter(2, 4);
expect(list.toArray()).toEqual([1, 2, 4, 3]);
});
it('should return false if the existing value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.insertAfter(5, 4);
expect(result).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('countOccurrences', () => {
it('should count occurrences of a value in the list', () => {
list.push(1);
list.push(2);
list.push(2);
list.push(3);
const count = list.countOccurrences(2);
expect(count).toBe(2);
});
it('should return 0 if the value is not found', () => {
list.push(1);
list.push(2);
const count = list.countOccurrences(3);
expect(count).toBe(0);
});
});
describe('removeValue', () => {
it('should remove the first occurrence of a value from the list', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.delete(2);
expect(removed).toBe(true);
expect(list.toArray()).toEqual([1, 3]);
});
it('should return false if the value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.delete(4);
expect(removed).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('isEmpty', () => {
it('should return true for an empty list', () => {
expect(list.isEmpty()).toBe(true);
});
it('should return false for a non-empty list', () => {
list.push(1);
expect(list.isEmpty()).toBe(false);
});
});
describe('clear', () => {
it('should clear all elements from the list', () => {
list.push(1);
list.push(2);
list.push(3);
list.clear();
expect(list.toArray()).toEqual([]);
expect(list.length).toBe(0);
expect(list.isEmpty()).toBe(true);
});
});
describe('reverse', () => {
it('should reverse the order of elements in the list', () => {
list.push(1);
list.push(2);
list.push(3);
list.reverse();
expect(list.toArray()).toEqual([3, 2, 1]);
});
it('should handle an empty list', () => {
list.reverse();
expect(list.toArray()).toEqual([]);
});
it('should handle a list with a single element', () => {
list.push(1);
list.reverse();
expect(list.toArray()).toEqual([1]);
});
});
describe('indexOf', () => {
it('should return the index of the first occurrence of a value', () => {
list.push(1);
list.push(2);
list.push(3);
const index = list.indexOf(2);
expect(index).toBe(1);
});
it('should return -1 if the value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const index = list.indexOf(4);
expect(index).toBe(-1);
});
});
describe('toArray', () => {
it('should convert the list to an array', () => {
list.push(1);
list.push(2);
list.push(3);
const array = list.toArray();
expect(array).toEqual([1, 2, 3]);
});
it('should return an empty array for an empty list', () => {
const array = list.toArray();
expect(array).toEqual([]);
});
});
describe('insertBefore', () => {
it('should insert an element before an existing value', () => {
list.push(1);
list.push(2);
list.push(3);
list.insertBefore(2, 4);
expect(list.toArray()).toEqual([1, 4, 2, 3]);
});
it('should insert an element at the beginning', () => {
list.push(1);
list.push(2);
list.insertBefore(1, 3);
expect(list.toArray()).toEqual([3, 1, 2]);
});
it('should return false if the existing value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.insertBefore(5, 4);
expect(result).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('getLength', () => {
it('should return the correct length of the list', () => {
expect(list.length).toBe(0);
list.push(1);
list.push(2);
expect(list.length).toBe(2);
});
});
describe('remove', () => {
it('should remove and return the element at the specified index', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.deleteAt(1);
expect(removed).toBe(2);
expect(list.toArray()).toEqual([1, 3]);
});
it('should return undefined for an out-of-bounds index', () => {
list.push(1);
const removed = list.deleteAt(1);
expect(removed).toBeNull();
});
it('should remove and return the first element', () => {
list.push(1);
list.push(2);
const removed = list.deleteAt(0);
expect(removed).toBe(1);
expect(list.toArray()).toEqual([2]);
});
it('should remove and return the last element', () => {
list.push(1);
list.push(2);
const removed = list.deleteAt(1);
expect(removed).toBe(2);
expect(list.toArray()).toEqual([1]);
});
});
describe('push and pop', () => {
it('should push and pop elements correctly', () => {
list.push(1);
list.push(2);
expect(list.pop()).toBe(2);
expect(list.pop()).toBe(1);
expect(list.pop()).toBeNull();
});
});
describe('shift and unshift', () => {
it('should shift and unshift elements correctly', () => {
list.unshift(1);
list.unshift(2);
expect(list.shift()).toBe(2);
expect(list.shift()).toBe(1);
expect(list.shift()).toBeNull();
});
});
describe('insert and toArray', () => {
it('should insert elements and return array correctly', () => {
list.insertAt(0, 1);
list.insertAt(1, 3);
list.insertAt(1, 2);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('find', () => {
it('should find elements using a callback function', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.find((data) => data % 2 === 0);
expect(result).toBe(2);
});
it('should return undefined if element is not found', () => {
list.push(1);
list.push(3);
const result = list.find((data) => data % 2 === 0);
expect(result).toBeNull();
});
});
describe('reverse', () => {
it('should reverse the order of elements', () => {
list.push(1);
list.push(2);
list.push(3);
list.reverse();
expect(list.toArray()).toEqual([3, 2, 1]);
});
});
describe('countOccurrences', () => {
it('should count occurrences of a value', () => {
list.push(1);
list.push(2);
list.push(2);
list.push(3);
const count = list.countOccurrences(2);
expect(count).toBe(2);
});
it('should return 0 if value is not found', () => {
list.push(1);
list.push(2);
const count = list.countOccurrences(3);
expect(count).toBe(0);
});
});
it('should insert and manipulate objects with numeric properties', () => {
const obj1 = {keyA: 1};
const obj2 = {keyA: 2};
const obj3 = {keyA: 3};
objectList.push(obj1);
objectList.push(obj2);
objectList.push(obj3);
expect(objectList.toArray()).toEqual([obj1, obj2, obj3]);
const newObj = {keyA: 2.5}; // Corrected newObj value
const insertSuccess = objectList.insertBefore(obj2, newObj);
expect(insertSuccess).toBe(true);
const findNode = objectList.findNode(newObj); // Use newObj instead of obj2
expect(findNode?.val).toEqual(newObj);
const deleted = objectList.delete(newObj); // Use newObj instead of obj2
expect(deleted).toBe(true);
const poppedObj = objectList.pop();
expect(poppedObj).toBe(obj3);
const shiftedObj = objectList.shift();
expect(shiftedObj).toBe(obj1);
});
});
describe('SinglyLinkedList Performance Test', () => {
describe('should the push and pop methods adhere to a time complexity of O(n) and executed correctly under large scale data', () => {
const list = new SinglyLinkedList<number>();
const startPushTime = performance.now();
for (let i = 0; i < magnitude.LINEAR; i++) {
list.push(i);
}
expect(performance.now() - startPushTime).toBeLessThan(magnitude.LINEAR * 1000);
const startPopTime = performance.now();
for (let i = 0; i < magnitude.LINEAR; i++) {
list.pop();
}
expect(performance.now() - startPopTime).toBeLessThan(magnitude.LINEAR * 1000);
});
});
import {SinglyLinkedList} from '../../../../src';
import {magnitude} from '../constants';
describe('SinglyLinkedList Operation Test', () => {
let list: SinglyLinkedList<number>;
let objectList: SinglyLinkedList<{ keyA: number }>;
beforeEach(() => {
list = new SinglyLinkedList<number>();
objectList = new SinglyLinkedList<{ keyA: number }>();
});
describe('push', () => {
it('should add elements to the end of the list', () => {
list.push(1);
list.push(2);
expect(list.toArray()).toEqual([1, 2]);
});
});
describe('pop', () => {
it('should remove and return the last element of the list', () => {
list.push(1);
list.push(2);
const popped = list.pop();
expect(popped).toBe(2);
expect(list.toArray()).toEqual([1]);
});
it('should return undefined if the list is empty', () => {
const popped = list.pop();
expect(popped).toBeUndefined();
});
});
describe('shift', () => {
it('should remove and return the first element of the list', () => {
list.push(1);
list.push(2);
const shifted = list.shift();
expect(shifted).toBe(1);
expect(list.toArray()).toEqual([2]);
});
it('should return undefined if the list is empty', () => {
const shifted = list.shift();
expect(shifted).toBeUndefined();
});
});
describe('unshift', () => {
it('should add elements to the beginning of the list', () => {
list.unshift(1);
list.unshift(2);
expect(list.toArray()).toEqual([2, 1]);
});
});
describe('get', () => {
it('should return the element at the specified index', () => {
list.push(1);
list.push(2);
list.push(3);
const element = list.getAt(1);
expect(element).toBe(2);
});
it('should return undefined for an out-of-bounds index', () => {
list.push(1);
const element = list.getAt(1);
expect(element).toBeNull();
});
});
describe('insertAfter', () => {
it('should insert an element after an existing value', () => {
list.push(1);
list.push(2);
list.push(3);
list.insertAfter(2, 4);
expect(list.toArray()).toEqual([1, 2, 4, 3]);
});
it('should return false if the existing value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.insertAfter(5, 4);
expect(result).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('countOccurrences', () => {
it('should count occurrences of a value in the list', () => {
list.push(1);
list.push(2);
list.push(2);
list.push(3);
const count = list.countOccurrences(2);
expect(count).toBe(2);
});
it('should return 0 if the value is not found', () => {
list.push(1);
list.push(2);
const count = list.countOccurrences(3);
expect(count).toBe(0);
});
});
describe('removeValue', () => {
it('should remove the first occurrence of a value from the list', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.delete(2);
expect(removed).toBe(true);
expect(list.toArray()).toEqual([1, 3]);
});
it('should return false if the value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.delete(4);
expect(removed).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('isEmpty', () => {
it('should return true for an empty list', () => {
expect(list.isEmpty()).toBe(true);
});
it('should return false for a non-empty list', () => {
list.push(1);
expect(list.isEmpty()).toBe(false);
});
});
describe('clear', () => {
it('should clear all elements from the list', () => {
list.push(1);
list.push(2);
list.push(3);
list.clear();
expect(list.toArray()).toEqual([]);
expect(list.length).toBe(0);
expect(list.isEmpty()).toBe(true);
});
});
describe('reverse', () => {
it('should reverse the order of elements in the list', () => {
list.push(1);
list.push(2);
list.push(3);
list.reverse();
expect(list.toArray()).toEqual([3, 2, 1]);
});
it('should handle an empty list', () => {
list.reverse();
expect(list.toArray()).toEqual([]);
});
it('should handle a list with a single element', () => {
list.push(1);
list.reverse();
expect(list.toArray()).toEqual([1]);
});
});
describe('indexOf', () => {
it('should return the index of the first occurrence of a value', () => {
list.push(1);
list.push(2);
list.push(3);
const index = list.indexOf(2);
expect(index).toBe(1);
});
it('should return -1 if the value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const index = list.indexOf(4);
expect(index).toBe(-1);
});
});
describe('toArray', () => {
it('should convert the list to an array', () => {
list.push(1);
list.push(2);
list.push(3);
const array = list.toArray();
expect(array).toEqual([1, 2, 3]);
});
it('should return an empty array for an empty list', () => {
const array = list.toArray();
expect(array).toEqual([]);
});
});
describe('insertBefore', () => {
it('should insert an element before an existing value', () => {
list.push(1);
list.push(2);
list.push(3);
list.insertBefore(2, 4);
expect(list.toArray()).toEqual([1, 4, 2, 3]);
});
it('should insert an element at the beginning', () => {
list.push(1);
list.push(2);
list.insertBefore(1, 3);
expect(list.toArray()).toEqual([3, 1, 2]);
});
it('should return false if the existing value is not found', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.insertBefore(5, 4);
expect(result).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('getLength', () => {
it('should return the correct length of the list', () => {
expect(list.length).toBe(0);
list.push(1);
list.push(2);
expect(list.length).toBe(2);
});
});
describe('remove', () => {
it('should remove and return the element at the specified index', () => {
list.push(1);
list.push(2);
list.push(3);
const removed = list.deleteAt(1);
expect(removed).toBe(2);
expect(list.toArray()).toEqual([1, 3]);
});
it('should return undefined for an out-of-bounds index', () => {
list.push(1);
const removed = list.deleteAt(1);
expect(removed).toBeUndefined();
});
it('should remove and return the first element', () => {
list.push(1);
list.push(2);
const removed = list.deleteAt(0);
expect(removed).toBe(1);
expect(list.toArray()).toEqual([2]);
});
it('should remove and return the last element', () => {
list.push(1);
list.push(2);
const removed = list.deleteAt(1);
expect(removed).toBe(2);
expect(list.toArray()).toEqual([1]);
});
});
describe('push and pop', () => {
it('should push and pop elements correctly', () => {
list.push(1);
list.push(2);
expect(list.pop()).toBe(2);
expect(list.pop()).toBe(1);
expect(list.pop()).toBeUndefined();
});
});
describe('shift and unshift', () => {
it('should shift and unshift elements correctly', () => {
list.unshift(1);
list.unshift(2);
expect(list.shift()).toBe(2);
expect(list.shift()).toBe(1);
expect(list.shift()).toBeUndefined();
});
});
describe('insert and toArray', () => {
it('should insert elements and return array correctly', () => {
list.insertAt(0, 1);
list.insertAt(1, 3);
list.insertAt(1, 2);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
describe('find', () => {
it('should find elements using a callback function', () => {
list.push(1);
list.push(2);
list.push(3);
const result = list.find((data) => data % 2 === 0);
expect(result).toBe(2);
});
it('should return undefined if element is not found', () => {
list.push(1);
list.push(3);
const result = list.find((data) => data % 2 === 0);
expect(result).toBeNull();
});
});
describe('reverse', () => {
it('should reverse the order of elements', () => {
list.push(1);
list.push(2);
list.push(3);
list.reverse();
expect(list.toArray()).toEqual([3, 2, 1]);
});
});
describe('countOccurrences', () => {
it('should count occurrences of a value', () => {
list.push(1);
list.push(2);
list.push(2);
list.push(3);
const count = list.countOccurrences(2);
expect(count).toBe(2);
});
it('should return 0 if value is not found', () => {
list.push(1);
list.push(2);
const count = list.countOccurrences(3);
expect(count).toBe(0);
});
});
it('should insert and manipulate objects with numeric properties', () => {
const obj1 = {keyA: 1};
const obj2 = {keyA: 2};
const obj3 = {keyA: 3};
objectList.push(obj1);
objectList.push(obj2);
objectList.push(obj3);
expect(objectList.toArray()).toEqual([obj1, obj2, obj3]);
const newObj = {keyA: 2.5}; // Corrected newObj value
const insertSuccess = objectList.insertBefore(obj2, newObj);
expect(insertSuccess).toBe(true);
const findNode = objectList.findNode(newObj); // Use newObj instead of obj2
expect(findNode?.val).toEqual(newObj);
const deleted = objectList.delete(newObj); // Use newObj instead of obj2
expect(deleted).toBe(true);
const poppedObj = objectList.pop();
expect(poppedObj).toBe(obj3);
const shiftedObj = objectList.shift();
expect(shiftedObj).toBe(obj1);
});
});
describe('SinglyLinkedList Performance Test', () => {
describe('should the push and pop methods adhere to a time complexity of O(n) and executed correctly under large scale data', () => {
const list = new SinglyLinkedList<number>();
const startPushTime = performance.now();
for (let i = 0; i < magnitude.LINEAR; i++) {
list.push(i);
}
expect(performance.now() - startPushTime).toBeLessThan(magnitude.LINEAR * 1000);
const startPopTime = performance.now();
for (let i = 0; i < magnitude.LINEAR; i++) {
list.pop();
}
expect(performance.now() - startPopTime).toBeLessThan(magnitude.LINEAR * 1000);
});
});