[project] Achieve a rational subpackage structure that enables individual subpackages to be independently exportable.

This commit is contained in:
Revone 2023-10-25 11:19:03 +08:00
parent 5978159d9e
commit 063b702236
18 changed files with 629 additions and 598 deletions

62
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "data-structure-typed",
"version": "1.37.9",
"version": "1.38.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data-structure-typed",
"version": "1.37.9",
"version": "1.38.1",
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.37.5"
@ -18,17 +18,17 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.37.9",
"avl-tree-typed": "^1.38.1",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.37.9",
"bst-typed": "^1.37.9",
"binary-tree-typed": "^1.38.1",
"bst-typed": "^1.38.1",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"heap-typed": "^1.37.9",
"heap-typed": "^1.38.1",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",
@ -2405,13 +2405,10 @@
}
},
"node_modules/avl-tree-typed": {
"version": "1.37.9",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.37.9.tgz",
"integrity": "sha512-FC7ezzT3Yw8H65oZgf/3RGYo9gnZRgORzlGGO4PyC19ZeIu0UZMHu1+kT0yEfbIE1qGBb4lnuwk4ia8CitcgLg==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.37.9"
}
"version": "1.38.1",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.1.tgz",
"integrity": "sha512-owzl0/cOijCKDyL8RAR+8Q2ibtqA+datgKQEbs1qNpCvMgYBtaytIgwyR68jYD+u7QGTXWYdO288H6NiKI0eTA==",
"dev": true
},
"node_modules/babel-jest": {
"version": "29.7.0",
@ -2595,13 +2592,10 @@
}
},
"node_modules/binary-tree-typed": {
"version": "1.37.9",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.37.9.tgz",
"integrity": "sha512-8nCjU4V6ViR8NQfxCBsLRFx5Z8D4jpUIx4NuvjliR1R8YIzL6wMmahemve+UbCUWhZJNG5Dv0kVnnCWIK+T0hw==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.37.9"
}
"version": "1.38.1",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.1.tgz",
"integrity": "sha512-h4dBfVSaqUPfpVRHI7ZWUv3BSFYF9VtzoRu5X2rIq4se89QX+1cQTirQ7bCG0mDLJ9A4GfmEVMvQvvmVhorBEQ==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@ -2679,13 +2673,10 @@
}
},
"node_modules/bst-typed": {
"version": "1.37.9",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.37.9.tgz",
"integrity": "sha512-KUp29JhTbNVdA1ePP7gUdi7uaRpM8DVhve9LMHQSUzxTDtHGc8mFTA+njFY7LLU2Rqtu/vqBgTu7bJRVJbWrPA==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.37.9"
}
"version": "1.38.1",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.1.tgz",
"integrity": "sha512-jNBmdOaSAApSx5iYo5ijunp3rtATcTmNOVnRiasCqKzSYTLfCJiGqIoXkDYMIFWK7hlgbAsVJkzTLciKf4RjcQ==",
"dev": true
},
"node_modules/buffer-from": {
"version": "1.1.2",
@ -3037,9 +3028,9 @@
}
},
"node_modules/data-structure-typed": {
"version": "1.37.9",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.37.9.tgz",
"integrity": "sha512-6CUX8ANDv2IsJTB8tbdUrXFgWV1AAPxWdcco1ZRUX8caCM0Ge6Snwfse1G1BF6M8kVEuGO2r4q6zkw1z2DxAtQ==",
"version": "1.38.0",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.0.tgz",
"integrity": "sha512-KXYXlyQm7k09Gp4hhsneMOL1bLEPse6Kv3qeE6CU78jidJEh8SY66K9auAUio1mpkjbKTCqjf7q3Ep4pXkhB2w==",
"dependencies": {
"data-structure-typed": "^1.37.5"
}
@ -4387,13 +4378,10 @@
}
},
"node_modules/heap-typed": {
"version": "1.37.9",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.37.9.tgz",
"integrity": "sha512-oYkcappLoSb8Zs9gbMaUfIwsm2arykNoQ6gF28x1PQuKa0/a9zonEqqRN6dKlfOT28JIvqhnrSed039YDlZhrQ==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.37.9"
}
"version": "1.38.1",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.1.tgz",
"integrity": "sha512-PvLlO5lSds9zOOX4GvVS2mgZfLk0f7Ev+++hYkGrlCqpcCGDsXVn+B0k/Jel0mkTXIK3zVkev2if7Cxsmk1pEQ==",
"dev": true
},
"node_modules/html-escaper": {
"version": "2.0.2",

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.37.9",
"version": "1.38.1",
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
"main": "dist/index.js",
"module": "lib/index.js",
@ -59,17 +59,17 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.37.9",
"avl-tree-typed": "^1.38.1",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.37.9",
"bst-typed": "^1.37.9",
"binary-tree-typed": "^1.38.1",
"bst-typed": "^1.38.1",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"heap-typed": "^1.37.9",
"heap-typed": "^1.38.1",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",

View file

@ -12,7 +12,25 @@ source_dir_default=$(jq -r .sourceDir ./scripts/config.json)
# List of directories
directories=(
"avl-tree-typed"
"binary-tree-typed"
"bst-typed"
"deque-typed"
"directed-graph-typed"
"doubly-linked-list-typed"
"graph-typed"
"heap-typed"
"linked-list-typed"
"max-heap-typed"
"max-priority-queue-typed"
"min-heap-typed"
"min-priority-queue-typed"
"priority-queue-typed"
"singly-linked-list-typed"
"queue-typed"
"stack-typed"
"tree-multiset-typed"
"trie-typed"
"undirected-graph-typed"
)
# Loop through each directory

View file

@ -61,8 +61,8 @@ for dir in "${directories[@]}"; do
# jq ".dependencies[\"data-structure-typed\"] = \"$version_prompted\"" package.json > temp.json
# mv temp.json package.json
# Install data-structure-typed package and build
npm i data-structure-typed@"$version_prompted"
# # Install data-structure-typed package and build
# npm i data-structure-typed@"$version_prompted"
npm run build:publish
cd ..

View file

@ -32,33 +32,6 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
super(options);
}
/**
* The function swaps the key, value, and height properties between two nodes in a binary tree.
* @param {N} srcNode - The `srcNode` parameter represents the source node that needs to be swapped
* with the `destNode`.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values
* from the source node (`srcNode`) will be swapped to.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
protected override _swap(srcNode: N, destNode: N): N {
const {key, val, height} = destNode;
const tempNode = this.createNode(key, val);
if (tempNode) {
tempNode.height = height;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.height = tempNode.height;
}
return destNode;
}
/**
* The function creates a new AVL tree node with the specified key and value.
* @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with
@ -105,6 +78,33 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
return deletedResults;
}
/**
* The function swaps the key, value, and height properties between two nodes in a binary tree.
* @param {N} srcNode - The `srcNode` parameter represents the source node that needs to be swapped
* with the `destNode`.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values
* from the source node (`srcNode`) will be swapped to.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
protected override _swap(srcNode: N, destNode: N): N {
const {key, val, height} = destNode;
const tempNode = this.createNode(key, val);
if (tempNode) {
tempNode.height = height;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.height = tempNode.height;
}
return destNode;
}
/**
* The function calculates the balance factor of a node in a binary tree.
* @param {N} node - The parameter "node" represents a node in a binary tree data structure.

View file

@ -26,16 +26,6 @@ import {Queue} from '../queue';
* @template FAMILY - The type of the family relationship in the binary tree.
*/
export class BinaryTreeNode<V = any, FAMILY extends BinaryTreeNode<V, FAMILY> = BinaryTreeNodeNested<V>> {
/**
* Creates a new instance of BinaryTreeNode.
* @param {BinaryTreeNodeKey} key - The key associated with the node.
* @param {V} val - The value stored in the node.
*/
constructor(key: BinaryTreeNodeKey, val?: V) {
this.key = key;
this.val = val;
}
/**
* The key associated with the node.
*/
@ -46,6 +36,21 @@ export class BinaryTreeNode<V = any, FAMILY extends BinaryTreeNode<V, FAMILY> =
*/
val: V | undefined;
/**
* The parent node of the current node.
*/
parent: FAMILY | null | undefined;
/**
* Creates a new instance of BinaryTreeNode.
* @param {BinaryTreeNodeKey} key - The key associated with the node.
* @param {V} val - The value stored in the node.
*/
constructor(key: BinaryTreeNodeKey, val?: V) {
this.key = key;
this.val = val;
}
private _left: FAMILY | null | undefined;
/**
@ -86,11 +91,6 @@ export class BinaryTreeNode<V = any, FAMILY extends BinaryTreeNode<V, FAMILY> =
this._right = v;
}
/**
* The parent node of the current node.
*/
parent: FAMILY | null | undefined;
/**
* Get the position of the node within its family.
* @returns {FamilyPosition} - The family position of the node.
@ -128,6 +128,8 @@ export class BinaryTreeNode<V = any, FAMILY extends BinaryTreeNode<V, FAMILY> =
* @template N - The type of the binary tree's nodes.
*/
export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode> implements IBinaryTree<N> {
private _loopType: IterationType = IterationType.ITERATIVE;
/**
* Creates a new instance of BinaryTree.
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
@ -139,16 +141,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
}
}
/**
* Creates a new instance of BinaryTreeNode with the given key and value.
* @param {BinaryTreeNodeKey} key - The key for the new node.
* @param {N['val']} val - The value for the new node.
* @returns {N} - The newly created BinaryTreeNode.
*/
createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new BinaryTreeNode<N['val'], N>(key, val) as N;
}
private _root: N | null = null;
/**
@ -167,8 +159,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
return this._size;
}
private _loopType: IterationType = IterationType.ITERATIVE;
/**
* Get the iteration type used in the binary tree.
*/
@ -185,24 +175,13 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
}
/**
* Swap the data of two nodes in the binary tree.
* @param {N} srcNode - The source node to swap.
* @param {N} destNode - The destination node to swap.
* @returns {N} - The destination node after the swap.
* Creates a new instance of BinaryTreeNode with the given key and value.
* @param {BinaryTreeNodeKey} key - The key for the new node.
* @param {N['val']} val - The value for the new node.
* @returns {N} - The newly created BinaryTreeNode.
*/
protected _swap(srcNode: N, destNode: N): N {
const {key, val} = destNode;
const tempNode = this.createNode(key, val);
if (tempNode) {
destNode.key = srcNode.key;
destNode.val = srcNode.val;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
}
return destNode;
createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new BinaryTreeNode<N['val'], N>(key, val) as N;
}
/**
@ -449,8 +428,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
}
}
protected _defaultCallbackByKey: MapCallback<N> = node => node.key;
/**
* The `getMinHeight` function calculates the minimum height of a binary tree using either a
* recursive or iterative approach.
@ -902,8 +879,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
return ans;
}
// --- start additional methods ---
/**
* The bfs function performs a breadth-first search traversal on a binary tree, executing a callback
* function on each node.
@ -973,13 +948,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
}
}
/**
* Time complexity is O(n)
* Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack
* The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete,
* the tree's structure should be restored to its original state to maintain the tree's integrity.
* This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape.
*/
// --- start additional methods ---
/**
* The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal
@ -1080,6 +1049,37 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
return ans;
}
/**
* Swap the data of two nodes in the binary tree.
* @param {N} srcNode - The source node to swap.
* @param {N} destNode - The destination node to swap.
* @returns {N} - The destination node after the swap.
*/
protected _swap(srcNode: N, destNode: N): N {
const {key, val} = destNode;
const tempNode = this.createNode(key, val);
if (tempNode) {
destNode.key = srcNode.key;
destNode.val = srcNode.val;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
}
return destNode;
}
/**
* Time complexity is O(n)
* Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack
* The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete,
* the tree's structure should be restored to its original state to maintain the tree's integrity.
* This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape.
*/
protected _defaultCallbackByKey: MapCallback<N> = node => node.key;
/**
* The function `_addTo` adds a new node to a binary tree if there is an available position.
* @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to

View file

@ -153,22 +153,26 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] {
return arr.indexOf(null) === -1;
}
if (!isBalanceAdd || !hasNoNull(keysOrNodes)) {
return super.addMany(keysOrNodes, data);
}
const inserted: (N | null | undefined)[] = [];
const combinedArr: [BinaryTreeNodeKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]);
let sorted = [];
function isNodeOrNullTuple(arr: [BinaryTreeNodeKey | N, N['val']][]): arr is [N, N['val']][] {
for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true;
return false;
}
function isBinaryTreeKeyOrNullTuple(
arr: [BinaryTreeNodeKey | N, N['val']][]
): arr is [BinaryTreeNodeKey, N['val']][] {
for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true;
return false;
}
let sortedKeysOrNodes: (number | N | null)[] = [],
sortedData: (N['val'] | undefined)[] | undefined = [];

View file

@ -6,13 +6,13 @@ export class RBTreeNode<V = any, FAMILY extends RBTreeNode<V, FAMILY> = RBTreeNo
V,
FAMILY
> {
private _color: RBColor;
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);
this._color = RBColor.RED;
}
private _color: RBColor;
get color(): RBColor {
return this._color;
}

View file

@ -14,6 +14,8 @@ export class TreeMultisetNode<
V = any,
FAMILY extends TreeMultisetNode<V, FAMILY> = TreeMultisetNodeNested<V>
> extends AVLTreeNode<V, FAMILY> {
count: number;
/**
* The constructor function initializes a BinaryTreeNode object with a key, value, and count.
* @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier
@ -28,8 +30,6 @@ export class TreeMultisetNode<
super(key, val);
this.count = count;
}
count: number;
}
/**
@ -68,33 +68,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
return new TreeMultisetNode(key, val, count) as N;
}
/**
* The function swaps the values of two nodes in a binary tree.
* @param {N} srcNode - The source node that needs to be swapped with the destination node.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values
* from `srcNode` will be swapped into.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
protected override _swap(srcNode: N, destNode: N): N {
const {key, val, count, height} = destNode;
const tempNode = this.createNode(key, val, count);
if (tempNode) {
tempNode.height = height;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}
return destNode;
}
/**
* The `add` function adds a new node to a binary search tree, updating the count if the key already
* exists, and balancing the tree if necessary.
@ -365,6 +338,33 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
this._setCount(0);
}
/**
* The function swaps the values of two nodes in a binary tree.
* @param {N} srcNode - The source node that needs to be swapped with the destination node.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values
* from `srcNode` will be swapped into.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
protected override _swap(srcNode: N, destNode: N): N {
const {key, val, count, height} = destNode;
const tempNode = this.createNode(key, val, count);
if (tempNode) {
tempNode.height = height;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}
return destNode;
}
/**
* The function sets the value of the "_count" property.
* @param {number} v - number

View file

@ -8,60 +8,6 @@ import {HashFunction} from '../../types';
* @license MIT License
*/
export class HashMap<K, V> {
get hashFn(): HashFunction<K> {
return this._hashFn;
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
get table(): Array<Array<[K, V]>> {
return this._table;
}
set table(value: Array<Array<[K, V]>>) {
this._table = value;
}
get capacityMultiplier(): number {
return this._capacityMultiplier;
}
set capacityMultiplier(value: number) {
this._capacityMultiplier = value;
}
get loadFactor(): number {
return this._loadFactor;
}
set loadFactor(value: number) {
this._loadFactor = value;
}
get initialCapacity(): number {
return this._initialCapacity;
}
set initialCapacity(value: number) {
this._initialCapacity = value;
}
get size(): number {
return this._size;
}
set size(value: number) {
this._size = value;
}
private _initialCapacity: number;
private _loadFactor: number;
private _capacityMultiplier: number;
private _size: number;
private _table: Array<Array<[K, V]>>;
private _hashFn: HashFunction<K>;
/**
* The constructor initializes the properties of a hash table, including the initial capacity, load factor, capacity
* multiplier, size, table array, and hash function.
@ -92,31 +38,64 @@ export class HashMap<K, V> {
});
}
private _hash(key: K): number {
return this._hashFn(key);
private _initialCapacity: number;
get initialCapacity(): number {
return this._initialCapacity;
}
/**
* The `resizeTable` function resizes the table used in a hash map by creating a new table with a specified capacity and
* rehashing the key-value pairs from the old table into the new table.
* @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents
* the number of buckets that the new table should have.
*/
private resizeTable(newCapacity: number): void {
const newTable = new Array(newCapacity);
for (const bucket of this._table) {
// Note that this is this._table
if (bucket) {
for (const [key, value] of bucket) {
const newIndex = this._hash(key) % newCapacity;
if (!newTable[newIndex]) {
newTable[newIndex] = [];
}
newTable[newIndex].push([key, value]);
}
}
}
this._table = newTable; // Again, here is this._table
set initialCapacity(value: number) {
this._initialCapacity = value;
}
private _loadFactor: number;
get loadFactor(): number {
return this._loadFactor;
}
set loadFactor(value: number) {
this._loadFactor = value;
}
private _capacityMultiplier: number;
get capacityMultiplier(): number {
return this._capacityMultiplier;
}
set capacityMultiplier(value: number) {
this._capacityMultiplier = value;
}
private _size: number;
get size(): number {
return this._size;
}
set size(value: number) {
this._size = value;
}
private _table: Array<Array<[K, V]>>;
get table(): Array<Array<[K, V]>> {
return this._table;
}
set table(value: Array<Array<[K, V]>>) {
this._table = value;
}
private _hashFn: HashFunction<K>;
get hashFn(): HashFunction<K> {
return this._hashFn;
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
set(key: K, value: V): void {
@ -200,4 +179,31 @@ export class HashMap<K, V> {
isEmpty(): boolean {
return this.size === 0;
}
private _hash(key: K): number {
return this._hashFn(key);
}
/**
* The `resizeTable` function resizes the table used in a hash map by creating a new table with a specified capacity and
* rehashing the key-value pairs from the old table into the new table.
* @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents
* the number of buckets that the new table should have.
*/
private resizeTable(newCapacity: number): void {
const newTable = new Array(newCapacity);
for (const bucket of this._table) {
// Note that this is this._table
if (bucket) {
for (const [key, value] of bucket) {
const newIndex = this._hash(key) % newCapacity;
if (!newTable[newIndex]) {
newTable[newIndex] = [];
}
newTable[newIndex].push([key, value]);
}
}
}
this._table = newTable; // Again, here is this._table
}
}

View file

@ -21,21 +21,17 @@ export class HashTableNode<K, V> {
import {HashFunction} from '../../types';
export class HashTable<K, V> {
get hashFn(): HashFunction<K> {
return this._hashFn;
private static readonly DEFAULT_CAPACITY = 16;
private static readonly LOAD_FACTOR = 0.75;
constructor(capacity: number = HashTable.DEFAULT_CAPACITY, hashFn?: HashFunction<K>) {
this._hashFn = hashFn || this._defaultHashFn;
this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
this._size = 0;
this._buckets = new Array<HashTableNode<K, V> | null>(this._capacity).fill(null);
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
get buckets(): Array<HashTableNode<K, V> | null> {
return this._buckets;
}
set buckets(value: Array<HashTableNode<K, V> | null>) {
this._buckets = value;
}
private _capacity: number;
get capacity(): number {
return this._capacity;
@ -45,19 +41,118 @@ export class HashTable<K, V> {
this._capacity = value;
}
private static readonly DEFAULT_CAPACITY = 16;
private static readonly LOAD_FACTOR = 0.75;
private _capacity: number;
private _size: number;
get size(): number {
return this._size;
}
private _buckets: Array<HashTableNode<K, V> | null>;
get buckets(): Array<HashTableNode<K, V> | null> {
return this._buckets;
}
set buckets(value: Array<HashTableNode<K, V> | null>) {
this._buckets = value;
}
private _hashFn: HashFunction<K>;
constructor(capacity: number = HashTable.DEFAULT_CAPACITY, hashFn?: HashFunction<K>) {
this._hashFn = hashFn || this._defaultHashFn;
this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
this._size = 0;
this._buckets = new Array<HashTableNode<K, V> | null>(this._capacity).fill(null);
get hashFn(): HashFunction<K> {
return this._hashFn;
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
/**
* The set function adds a key-value pair to the hash table, handling collisions and resizing if necessary.
* @param {K} key - The key parameter represents the key of the key-value pair that you want to insert into the hash
* table. It is of type K, which is a generic type representing the key's data type.
* @param {V} val - The parameter `val` represents the value that you want to associate with the given key in the hash
* table.
* @returns Nothing is being returned. The return type of the `put` method is `void`, which means it does not return any
* value.
*/
set(key: K, val: V): void {
const index = this._hash(key);
const newNode = new HashTableNode<K, V>(key, val);
if (!this._buckets[index]) {
this._buckets[index] = newNode;
} else {
// Handle collisions, consider using open addressing, etc.
let currentNode = this._buckets[index]!;
while (currentNode) {
if (currentNode.key === key) {
// If the key already exists, update the value
currentNode.val = val;
return;
}
if (!currentNode.next) {
break;
}
currentNode = currentNode.next;
}
// Add to the end of the linked list
currentNode.next = newNode;
}
this._size++;
// If the load factor is too high, resize the hash table
if (this._size / this._capacity >= HashTable.LOAD_FACTOR) {
this._expand();
}
}
/**
* The `get` function retrieves the value associated with a given key from a hash table.
* @param {K} key - The `key` parameter represents the key of the element that we want to retrieve from the data
* structure.
* @returns The method is returning the value associated with the given key if it exists in the hash table. If the key is
* not found, it returns `undefined`.
*/
get(key: K): V | undefined {
const index = this._hash(key);
let currentNode = this._buckets[index];
while (currentNode) {
if (currentNode.key === key) {
return currentNode.val;
}
currentNode = currentNode.next;
}
return undefined; // Key not found
}
/**
* The delete function removes a key-value pair from a hash table.
* @param {K} key - The `key` parameter represents the key of the key-value pair that needs to be removed from the hash
* table.
* @returns Nothing is being returned. The `delete` method has a return type of `void`, which means it does not return
* any value.
*/
delete(key: K): void {
const index = this._hash(key);
let currentNode = this._buckets[index];
let prevNode: HashTableNode<K, V> | null = null;
while (currentNode) {
if (currentNode.key === key) {
if (prevNode) {
prevNode.next = currentNode.next;
} else {
this._buckets[index] = currentNode.next;
}
this._size--;
currentNode.next = null; // Release memory
return;
}
prevNode = currentNode;
currentNode = currentNode.next;
}
}
/**
@ -152,94 +247,6 @@ export class HashTable<K, V> {
return this._stringHash(JSON.stringify(key));
}
/**
* The set function adds a key-value pair to the hash table, handling collisions and resizing if necessary.
* @param {K} key - The key parameter represents the key of the key-value pair that you want to insert into the hash
* table. It is of type K, which is a generic type representing the key's data type.
* @param {V} val - The parameter `val` represents the value that you want to associate with the given key in the hash
* table.
* @returns Nothing is being returned. The return type of the `put` method is `void`, which means it does not return any
* value.
*/
set(key: K, val: V): void {
const index = this._hash(key);
const newNode = new HashTableNode<K, V>(key, val);
if (!this._buckets[index]) {
this._buckets[index] = newNode;
} else {
// Handle collisions, consider using open addressing, etc.
let currentNode = this._buckets[index]!;
while (currentNode) {
if (currentNode.key === key) {
// If the key already exists, update the value
currentNode.val = val;
return;
}
if (!currentNode.next) {
break;
}
currentNode = currentNode.next;
}
// Add to the end of the linked list
currentNode.next = newNode;
}
this._size++;
// If the load factor is too high, resize the hash table
if (this._size / this._capacity >= HashTable.LOAD_FACTOR) {
this._expand();
}
}
/**
* The `get` function retrieves the value associated with a given key from a hash table.
* @param {K} key - The `key` parameter represents the key of the element that we want to retrieve from the data
* structure.
* @returns The method is returning the value associated with the given key if it exists in the hash table. If the key is
* not found, it returns `undefined`.
*/
get(key: K): V | undefined {
const index = this._hash(key);
let currentNode = this._buckets[index];
while (currentNode) {
if (currentNode.key === key) {
return currentNode.val;
}
currentNode = currentNode.next;
}
return undefined; // Key not found
}
/**
* The delete function removes a key-value pair from a hash table.
* @param {K} key - The `key` parameter represents the key of the key-value pair that needs to be removed from the hash
* table.
* @returns Nothing is being returned. The `delete` method has a return type of `void`, which means it does not return
* any value.
*/
delete(key: K): void {
const index = this._hash(key);
let currentNode = this._buckets[index];
let prevNode: HashTableNode<K, V> | null = null;
while (currentNode) {
if (currentNode.key === key) {
if (prevNode) {
prevNode.next = currentNode.next;
} else {
this._buckets[index] = currentNode.next;
}
this._size--;
currentNode.next = null; // Release memory
return;
}
prevNode = currentNode;
currentNode = currentNode.next;
}
}
/**
* The `expand` function increases the capacity of a hash table by creating a new array of buckets with double the
* capacity and rehashing all the existing key-value pairs into the new buckets.
@ -270,8 +277,4 @@ export class HashTable<K, V> {
this._buckets = newBuckets;
this._capacity = newCapacity;
}
get size(): number {
return this._size;
}
}

View file

@ -15,6 +15,34 @@ export class Heap<E> {
this.comparator = comparator;
}
/**
* Get the size (number of elements) of the heap.
*/
get size(): number {
return this.nodes.length;
}
/**
* Get the last element in the heap, which is not necessarily a leaf node.
* @returns The last element or undefined if the heap is empty.
*/
get leaf(): E | undefined {
return this.nodes[this.size - 1] ?? undefined;
}
/**
* Static method that creates a binary heap from an array of nodes and a comparison function.
* @param nodes
* @param comparator - Comparison function.
* @returns A new Heap instance.
*/
static heapify<E>(nodes: E[], comparator: Comparator<E>): Heap<E> {
const binaryHeap = new Heap<E>(comparator);
binaryHeap.nodes = [...nodes];
binaryHeap.fix(); // Fix heap properties
return binaryHeap;
}
/**
* Insert an element into the heap and maintain the heap properties.
* @param element - The element to be inserted.
@ -59,57 +87,6 @@ export class Heap<E> {
return this.poll();
}
/**
* Float operation to maintain heap properties after adding an element.
* @param index - The index of the newly added element.
*/
protected bubbleUp(index: number): void {
const element = this.nodes[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.nodes[parentIndex];
if (this.comparator(element, parent) < 0) {
this.nodes[index] = parent;
this.nodes[parentIndex] = element;
index = parentIndex;
} else {
break;
}
}
}
/**
* Sinking operation to maintain heap properties after removing the top element.
* @param index - The index from which to start sinking.
*/
protected sinkDown(index: number): void {
const leftChildIndex = 2 * index + 1;
const rightChildIndex = 2 * index + 2;
const length = this.nodes.length;
let targetIndex = index;
if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) {
targetIndex = leftChildIndex;
}
if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) {
targetIndex = rightChildIndex;
}
if (targetIndex !== index) {
const temp = this.nodes[index];
this.nodes[index] = this.nodes[targetIndex];
this.nodes[targetIndex] = temp;
this.sinkDown(targetIndex);
}
}
/**
* Fix the entire heap to maintain heap properties.
*/
protected fix() {
for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i);
}
/**
* Peek at the top element of the heap without removing it.
* @returns The top element or undefined if the heap is empty.
@ -121,21 +98,6 @@ export class Heap<E> {
return this.nodes[0];
}
/**
* Get the size (number of elements) of the heap.
*/
get size(): number {
return this.nodes.length;
}
/**
* Get the last element in the heap, which is not necessarily a leaf node.
* @returns The last element or undefined if the heap is empty.
*/
get leaf(): E | undefined {
return this.nodes[this.size - 1] ?? undefined;
}
/**
* Check if the heap is empty.
* @returns True if the heap is empty, otherwise false.
@ -238,16 +200,54 @@ export class Heap<E> {
}
/**
* Static method that creates a binary heap from an array of nodes and a comparison function.
* @param nodes
* @param comparator - Comparison function.
* @returns A new Heap instance.
* Float operation to maintain heap properties after adding an element.
* @param index - The index of the newly added element.
*/
static heapify<E>(nodes: E[], comparator: Comparator<E>): Heap<E> {
const binaryHeap = new Heap<E>(comparator);
binaryHeap.nodes = [...nodes];
binaryHeap.fix(); // Fix heap properties
return binaryHeap;
protected bubbleUp(index: number): void {
const element = this.nodes[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.nodes[parentIndex];
if (this.comparator(element, parent) < 0) {
this.nodes[index] = parent;
this.nodes[parentIndex] = element;
index = parentIndex;
} else {
break;
}
}
}
/**
* Sinking operation to maintain heap properties after removing the top element.
* @param index - The index from which to start sinking.
*/
protected sinkDown(index: number): void {
const leftChildIndex = 2 * index + 1;
const rightChildIndex = 2 * index + 2;
const length = this.nodes.length;
let targetIndex = index;
if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) {
targetIndex = leftChildIndex;
}
if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) {
targetIndex = rightChildIndex;
}
if (targetIndex !== index) {
const temp = this.nodes[index];
this.nodes[index] = this.nodes[targetIndex];
this.nodes[targetIndex] = temp;
this.sinkDown(targetIndex);
}
}
/**
* Fix the entire heap to maintain heap properties.
*/
protected fix() {
for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i);
}
}
@ -259,6 +259,7 @@ export class FibonacciHeapNode<E> {
child?: FibonacciHeapNode<E>;
parent?: FibonacciHeapNode<E>;
marked: boolean;
constructor(element: E, degree = 0) {
this.element = element;
this.degree = degree;
@ -268,8 +269,8 @@ export class FibonacciHeapNode<E> {
export class FibonacciHeap<E> {
root?: FibonacciHeapNode<E>;
protected min?: FibonacciHeapNode<E>;
size: number = 0;
protected min?: FibonacciHeapNode<E>;
protected readonly comparator: Comparator<E>;
constructor(comparator?: Comparator<E>) {
@ -281,18 +282,6 @@ export class FibonacciHeap<E> {
}
}
/**
* Default comparator function used by the heap.
* @param {E} a
* @param {E} b
* @protected
*/
protected defaultComparator(a: E, b: E): number {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
/**
* Get the size (number of elements) of the heap.
* @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid.
@ -303,30 +292,6 @@ export class FibonacciHeap<E> {
this.size = 0;
}
/**
* Create a new node.
* @param element
* @protected
*/
protected createNode(element: E): FibonacciHeapNode<E> {
return new FibonacciHeapNode<E>(element);
}
/**
* Merge the given node with the root list.
* @param node - The node to be merged.
*/
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
if (!this.root) {
this.root = node;
} else {
node.right = this.root.right;
node.left = this.root;
this.root.right!.left = node;
this.root.right = node;
}
}
/**
* O(1) time operation.
* Insert an element into the heap and maintain the heap properties.
@ -394,18 +359,6 @@ export class FibonacciHeap<E> {
return nodes;
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @param node - The node to be removed.
* @protected
*/
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
if (this.root === node) this.root = node.right;
if (node.left) node.left.right = node.right;
if (node.right) node.right.left = node.left;
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
@ -423,63 +376,6 @@ export class FibonacciHeap<E> {
}
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @param y
* @param x
* @protected
*/
protected link(y: FibonacciHeapNode<E>, x: FibonacciHeapNode<E>): void {
this.removeFromRoot(y);
y.left = y;
y.right = y;
this.mergeWithChild(x, y);
x.degree++;
y.parent = x;
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @protected
*/
protected consolidate(): void {
const A: (FibonacciHeapNode<E> | undefined)[] = new Array(this.size);
const nodes = this.consumeLinkedList(this.root);
let x: FibonacciHeapNode<E> | undefined,
y: FibonacciHeapNode<E> | undefined,
d: number,
t: FibonacciHeapNode<E> | undefined;
for (const node of nodes) {
x = node;
d = x.degree;
while (A[d]) {
y = A[d] as FibonacciHeapNode<E>;
if (this.comparator(x.element, y.element) > 0) {
t = x;
x = y;
y = t;
}
this.link(y, x);
A[d] = undefined;
d++;
}
A[d] = x;
}
for (let i = 0; i < this.size; i++) {
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
this.min = A[i]!;
}
}
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
@ -557,4 +453,109 @@ export class FibonacciHeap<E> {
// Clear the heap that was merged
heapToMerge.clear();
}
/**
* Default comparator function used by the heap.
* @param {E} a
* @param {E} b
* @protected
*/
protected defaultComparator(a: E, b: E): number {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
/**
* Create a new node.
* @param element
* @protected
*/
protected createNode(element: E): FibonacciHeapNode<E> {
return new FibonacciHeapNode<E>(element);
}
/**
* Merge the given node with the root list.
* @param node - The node to be merged.
*/
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
if (!this.root) {
this.root = node;
} else {
node.right = this.root.right;
node.left = this.root;
this.root.right!.left = node;
this.root.right = node;
}
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @param node - The node to be removed.
* @protected
*/
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
if (this.root === node) this.root = node.right;
if (node.left) node.left.right = node.right;
if (node.right) node.right.left = node.left;
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @param y
* @param x
* @protected
*/
protected link(y: FibonacciHeapNode<E>, x: FibonacciHeapNode<E>): void {
this.removeFromRoot(y);
y.left = y;
y.right = y;
this.mergeWithChild(x, y);
x.degree++;
y.parent = x;
}
/**
* O(log n) time operation.
* Remove and return the top element (smallest or largest element) from the heap.
* @protected
*/
protected consolidate(): void {
const A: (FibonacciHeapNode<E> | undefined)[] = new Array(this.size);
const nodes = this.consumeLinkedList(this.root);
let x: FibonacciHeapNode<E> | undefined,
y: FibonacciHeapNode<E> | undefined,
d: number,
t: FibonacciHeapNode<E> | undefined;
for (const node of nodes) {
x = node;
d = x.degree;
while (A[d]) {
y = A[d] as FibonacciHeapNode<E>;
if (this.comparator(x.element, y.element) > 0) {
t = x;
x = y;
y = t;
}
this.link(y, x);
A[d] = undefined;
d++;
}
A[d] = x;
}
for (let i = 0; i < this.size; i++) {
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
this.min = A[i]!;
}
}
}
}

View file

@ -84,6 +84,10 @@ export class DoublyLinkedList<E = any> {
return this._length;
}
get size(): number {
return this.length;
}
/**
* The `fromArray` function creates a new instance of a DoublyLinkedList and populates it with the elements from the
* given array.
@ -222,10 +226,6 @@ export class DoublyLinkedList<E = any> {
return this.tail?.val;
}
get size(): number {
return this.length;
}
/**
* The `getAt` function returns the value at a specified index in a linked list, 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 we want to

View file

@ -19,39 +19,6 @@ export class SkipListNode<K, V> {
}
export class SkipList<K, V> {
get probability(): number {
return this._probability;
}
set probability(value: number) {
this._probability = value;
}
get maxLevel(): number {
return this._maxLevel;
}
set maxLevel(value: number) {
this._maxLevel = value;
}
get level(): number {
return this._level;
}
set level(value: number) {
this._level = value;
}
get head(): SkipListNode<K, V> {
return this._head;
}
set head(value: SkipListNode<K, V>) {
this._head = value;
}
private _head: SkipListNode<K, V>;
private _level: number;
private _maxLevel: number;
private _probability: number;
/**
* The constructor initializes a SkipList with a specified maximum level and probability.
* @param [maxLevel=16] - The `maxLevel` parameter represents the maximum level that a skip list can have. It determines
@ -66,16 +33,44 @@ export class SkipList<K, V> {
this._probability = probability;
}
/**
* The function "randomLevel" generates a random level based on a given probability and maximum level.
* @returns the level, which is a number.
*/
private randomLevel(): number {
let level = 1;
while (Math.random() < this.probability && level < this.maxLevel) {
level++;
}
return level;
private _head: SkipListNode<K, V>;
get head(): SkipListNode<K, V> {
return this._head;
}
set head(value: SkipListNode<K, V>) {
this._head = value;
}
private _level: number;
get level(): number {
return this._level;
}
set level(value: number) {
this._level = value;
}
private _maxLevel: number;
get maxLevel(): number {
return this._maxLevel;
}
set maxLevel(value: number) {
this._maxLevel = value;
}
private _probability: number;
get probability(): number {
return this._probability;
}
set probability(value: number) {
this._probability = value;
}
/**
@ -163,4 +158,16 @@ export class SkipList<K, V> {
return false;
}
/**
* The function "randomLevel" generates a random level based on a given probability and maximum level.
* @returns the level, which is a number.
*/
private randomLevel(): number {
let level = 1;
while (Math.random() < this.probability && level < this.maxLevel) {
level++;
}
return level;
}
}

View file

@ -58,16 +58,6 @@ export class Matrix2D {
return this._matrix;
}
/**
* The function "toVector" returns a new Vector2D object with the values from the first and second elements of the
* _matrix array.
* @returns A new instance of the Vector2D class is being returned. The values of the returned vector are taken from
* the first column of the matrix.
*/
toVector(): Vector2D {
return new Vector2D(this._matrix[0][0], this._matrix[1][0]);
}
/**
* The function takes two 2D matrices as input and returns their sum as a new 2D matrix.
* @param {Matrix2D} matrix1 - Matrix2D - The first matrix to be added.
@ -208,6 +198,16 @@ export class Matrix2D {
[0, 0, vector.w]
]);
}
/**
* The function "toVector" returns a new Vector2D object with the values from the first and second elements of the
* _matrix array.
* @returns A new instance of the Vector2D class is being returned. The values of the returned vector are taken from
* the first column of the matrix.
*/
toVector(): Vector2D {
return new Vector2D(this._matrix[0][0], this._matrix[1][0]);
}
}
export default Matrix2D;

View file

@ -52,6 +52,8 @@ export class TrieNode {
* Trie represents a Trie data structure. It provides basic Trie operations and additional methods.
*/
export class Trie {
private readonly _caseSensitive: boolean;
constructor(words?: string[], caseSensitive = true) {
this._root = new TrieNode('');
this._caseSensitive = caseSensitive;
@ -72,8 +74,6 @@ export class Trie {
this._root = v;
}
private readonly _caseSensitive: boolean;
/**
* Add a word to the Trie structure.
* @param {string} word - The word to add.
@ -110,13 +110,6 @@ export class Trie {
return cur.isEnd;
}
private _caseProcess(str: string) {
if (!this._caseSensitive) {
str = str.toLowerCase(); // Convert str to lowercase if case-insensitive
}
return str;
}
/**
* Remove a word from the Trie structure.
* @param{string} word - The word to delete.
@ -282,5 +275,12 @@ export class Trie {
return words;
}
private _caseProcess(str: string) {
if (!this._caseSensitive) {
str = str.toLowerCase(); // Convert str to lowercase if case-insensitive
}
return str;
}
// --- end additional methods ---
}

View file

@ -6,4 +6,8 @@ export type MapCallback<N> = (node: N) => any;
export type MapCallbackReturn<N> = ReturnType<MapCallback<N>>;
export enum CP {lt = 'lt', eq = 'eq', gt = 'gt'}
export enum CP {
lt = 'lt',
eq = 'eq',
gt = 'gt'
}

View file

@ -1,7 +1,7 @@
import {BinaryIndexedTree} from '../../../../src';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
// const isDebug = isDebugTest;
describe('BinaryIndexedTree simple', () => {
let bit: BinaryIndexedTree;