mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
fix: #38 Removed includeNull parameter from traversal methods.
feat: Removed unnecessary methods isNotNodeInstance and subTreeTraverse. refactor: Organized the overloads of traversal methods.
This commit is contained in:
parent
8fd35dd1f8
commit
34d4abd9e6
|
@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
|
|||
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
||||
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
|
||||
|
||||
## [v1.49.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
## [v1.49.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
|
|||
* allows the function to accept any number of arguments as an array. In this case, the `args`
|
||||
* parameter is used to pass any additional arguments to the `_getIterator` method.
|
||||
*/
|
||||
*[Symbol.iterator](...args: any[]): IterableIterator<[K, V]> {
|
||||
* [Symbol.iterator](...args: any[]): IterableIterator<[K, V]> {
|
||||
yield* this._getIterator(...args);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
|
|||
* The function returns an iterator that yields key-value pairs from the object, where the value can
|
||||
* be undefined.
|
||||
*/
|
||||
*entries(): IterableIterator<[K, V | undefined]> {
|
||||
* entries(): IterableIterator<[K, V | undefined]> {
|
||||
for (const item of this) {
|
||||
yield item;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
|
|||
*
|
||||
* The function returns an iterator that yields the keys of a data structure.
|
||||
*/
|
||||
*keys(): IterableIterator<K> {
|
||||
* keys(): IterableIterator<K> {
|
||||
for (const item of this) {
|
||||
yield item[0];
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
|
|||
*
|
||||
* The function returns an iterator that yields the values of a collection.
|
||||
*/
|
||||
*values(): IterableIterator<V> {
|
||||
* values(): IterableIterator<V> {
|
||||
for (const item of this) {
|
||||
yield item[1];
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ export abstract class IterableElementBase<V> {
|
|||
* allows the function to accept any number of arguments as an array. In this case, the `args`
|
||||
* parameter is used to pass any number of arguments to the `_getIterator` method.
|
||||
*/
|
||||
*[Symbol.iterator](...args: any[]): IterableIterator<V> {
|
||||
* [Symbol.iterator](...args: any[]): IterableIterator<V> {
|
||||
yield* this._getIterator(...args);
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ export abstract class IterableElementBase<V> {
|
|||
*
|
||||
* The function returns an iterator that yields all the values in the object.
|
||||
*/
|
||||
*values(): IterableIterator<V> {
|
||||
* values(): IterableIterator<V> {
|
||||
for (const item of this) {
|
||||
yield item;
|
||||
}
|
||||
|
|
|
@ -40,14 +40,13 @@ export class AVLTreeNode<K = any, V = any, N extends AVLTreeNode<K, V, N> = AVLT
|
|||
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes.
|
||||
*/
|
||||
export class AVLTree<
|
||||
K = any,
|
||||
V = any,
|
||||
N extends AVLTreeNode<K, V, N> = AVLTreeNode<K, V, AVLTreeNodeNested<K, V>>,
|
||||
TREE extends AVLTree<K, V, N, TREE> = AVLTree<K, V, N, AVLTreeNested<K, V, N>>
|
||||
>
|
||||
K = any,
|
||||
V = any,
|
||||
N extends AVLTreeNode<K, V, N> = AVLTreeNode<K, V, AVLTreeNodeNested<K, V>>,
|
||||
TREE extends AVLTree<K, V, N, TREE> = AVLTree<K, V, N, AVLTreeNested<K, V, N>>
|
||||
>
|
||||
extends BST<K, V, N, TREE>
|
||||
implements IBinaryTree<K, V, N, TREE>
|
||||
{
|
||||
implements IBinaryTree<K, V, N, TREE> {
|
||||
/**
|
||||
* The constructor function initializes an AVLTree object with optional keysOrNodesOrEntries and options.
|
||||
* @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` parameter is an optional iterable of `KeyOrNodeOrEntry<K, V, N>`
|
||||
|
@ -99,16 +98,6 @@ export class AVLTree<
|
|||
return keyOrNodeOrEntry instanceof AVLTreeNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "isNotNodeInstance" checks if a potential key is a K.
|
||||
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
||||
* data type.
|
||||
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
||||
*/
|
||||
override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry<K, V, N>): potentialKey is K {
|
||||
return !(potentialKey instanceof AVLTreeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(log n)
|
||||
* Space Complexity: O(1)
|
||||
|
@ -278,7 +267,7 @@ export class AVLTree<
|
|||
// Balance Restoration: If a balance issue is discovered after inserting a node, it requires balance restoration operations. Balance restoration includes four basic cases where rotation operations need to be performed to fix the balance:
|
||||
switch (
|
||||
this._balanceFactor(A) // second O(1)
|
||||
) {
|
||||
) {
|
||||
case -2:
|
||||
if (A && A.left) {
|
||||
if (this._balanceFactor(A.left) <= 0) {
|
||||
|
|
|
@ -101,14 +101,13 @@ export class BinaryTreeNode<
|
|||
*/
|
||||
|
||||
export class BinaryTree<
|
||||
K = any,
|
||||
V = any,
|
||||
N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>,
|
||||
TREE extends BinaryTree<K, V, N, TREE> = BinaryTree<K, V, N, BinaryTreeNested<K, V, N>>
|
||||
>
|
||||
K = any,
|
||||
V = any,
|
||||
N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>,
|
||||
TREE extends BinaryTree<K, V, N, TREE> = BinaryTree<K, V, N, BinaryTreeNested<K, V, N>>
|
||||
>
|
||||
extends IterableEntryBase<K, V | undefined>
|
||||
implements IBinaryTree<K, V, N, TREE>
|
||||
{
|
||||
implements IBinaryTree<K, V, N, TREE> {
|
||||
iterationType = IterationType.ITERATIVE;
|
||||
|
||||
/**
|
||||
|
@ -197,7 +196,7 @@ export class BinaryTree<
|
|||
}
|
||||
} else if (this.isNode(keyOrNodeOrEntry)) {
|
||||
node = keyOrNodeOrEntry;
|
||||
} else if (this.isNotNodeInstance(keyOrNodeOrEntry)) {
|
||||
} else if (!this.isNode(keyOrNodeOrEntry)) {
|
||||
node = this.createNode(keyOrNodeOrEntry, value);
|
||||
} else {
|
||||
return;
|
||||
|
@ -293,16 +292,6 @@ export class BinaryTree<
|
|||
return this.isRealNode(node) || node === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "isNotNodeInstance" checks if a potential key is a K.
|
||||
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
||||
* data type.
|
||||
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
||||
*/
|
||||
isNotNodeInstance(potentialKey: KeyOrNodeOrEntry<K, V, N>): potentialKey is K {
|
||||
return !(potentialKey instanceof BinaryTreeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity O(log n) - O(n)
|
||||
* Space Complexity O(1)
|
||||
|
@ -1029,7 +1018,7 @@ export class BinaryTree<
|
|||
*
|
||||
* The function `getPathToRoot` returns an array of nodes from a given node to the root of a tree
|
||||
* structure, with the option to reverse the order of the nodes.
|
||||
* @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
|
||||
* @param {K | N | null | undefined} beginNode - The `beginRoot` parameter represents the
|
||||
* starting node from which you want to find the path to the root. It can be of type `K`, `N`,
|
||||
* `null`, or `undefined`.
|
||||
* @param [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the
|
||||
|
@ -1037,20 +1026,20 @@ export class BinaryTree<
|
|||
* reversed before returning it. If `isReverse` is set to `false`, the path will be returned as is
|
||||
* @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
|
||||
*/
|
||||
getPathToRoot(beginRoot: KeyOrNodeOrEntry<K, V, N>, isReverse = true): N[] {
|
||||
getPathToRoot(beginNode: KeyOrNodeOrEntry<K, V, N>, isReverse = true): N[] {
|
||||
// TODO to support get path through passing key
|
||||
const result: N[] = [];
|
||||
beginRoot = this.ensureNode(beginRoot);
|
||||
beginNode = this.ensureNode(beginNode);
|
||||
|
||||
if (!beginRoot) return result;
|
||||
if (!beginNode) return result;
|
||||
|
||||
while (beginRoot.parent) {
|
||||
while (beginNode.parent) {
|
||||
// Array.push + Array.reverse is more efficient than Array.unshift
|
||||
// TODO may consider using Deque, so far this is not the performance bottleneck
|
||||
result.push(beginRoot);
|
||||
beginRoot = beginRoot.parent;
|
||||
result.push(beginNode);
|
||||
beginNode = beginNode.parent;
|
||||
}
|
||||
result.push(beginRoot);
|
||||
result.push(beginNode);
|
||||
return isReverse ? result.reverse() : result;
|
||||
}
|
||||
|
||||
|
@ -1203,99 +1192,94 @@ export class BinaryTree<
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Time complexity: O(n)
|
||||
* Space complexity: O(log n)
|
||||
*/
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[];
|
||||
|
||||
/**
|
||||
* Time complexity: O(n)
|
||||
* Space complexity: O(log n)
|
||||
*
|
||||
* The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
|
||||
* node, either recursively or iteratively.
|
||||
* @param {C} callback - The `callback` parameter is a function that will be called for each node in
|
||||
* the subtree traversal. It takes a single parameter, which is the current node being traversed, and
|
||||
* returns a value of any type.
|
||||
* @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
|
||||
* starting node or key from which the subtree traversal should begin. It can be of type `K`,
|
||||
* `N`, `null`, or `undefined`. If not provided, the `root` property of the current object is used as
|
||||
* the default value.
|
||||
* @param iterationType - The `iterationType` parameter determines the type of traversal to be
|
||||
* performed on the subtree. It can have two possible values:
|
||||
* @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
|
||||
* whether to include null values in the traversal. If `includeNull` is set to `true`, the
|
||||
* traversal will include null values, otherwise it will skip them.
|
||||
* @returns The function `subTreeTraverse` returns an array of values that are the result of invoking
|
||||
* the `callback` function on each node in the subtree. The type of the array nodes is determined
|
||||
* by the return type of the `callback` function.
|
||||
*/
|
||||
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[] {
|
||||
beginRoot = this.ensureNode(beginRoot);
|
||||
|
||||
const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
|
||||
if (!beginRoot) return ans;
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const _traverse = (cur: N | null | undefined) => {
|
||||
if (cur !== undefined) {
|
||||
ans.push(callback(cur));
|
||||
if (includeNull) {
|
||||
cur && this.isNodeOrNull(cur.left) && _traverse(cur.left);
|
||||
cur && this.isNodeOrNull(cur.right) && _traverse(cur.right);
|
||||
} else {
|
||||
cur && cur.left && _traverse(cur.left);
|
||||
cur && cur.right && _traverse(cur.right);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_traverse(beginRoot);
|
||||
} else {
|
||||
const stack: (N | null | undefined)[] = [beginRoot];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const cur = stack.pop();
|
||||
if (cur !== undefined) {
|
||||
ans.push(callback(cur));
|
||||
if (includeNull) {
|
||||
cur && this.isNodeOrNull(cur.right) && stack.push(cur.right);
|
||||
cur && this.isNodeOrNull(cur.left) && stack.push(cur.left);
|
||||
} else {
|
||||
cur && cur.right && stack.push(cur.right);
|
||||
cur && cur.left && stack.push(cur.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// /**
|
||||
// * Time complexity: O(n)
|
||||
// * Space complexity: O(log n)
|
||||
// */
|
||||
//
|
||||
// subTreeTraverse<C extends BTNCallback<N>>(
|
||||
// callback?: C,
|
||||
// beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
// iterationType?: IterationType,
|
||||
// includeNull?: false
|
||||
// ): ReturnType<C>[];
|
||||
//
|
||||
// subTreeTraverse<C extends BTNCallback<N | null>>(
|
||||
// callback?: C,
|
||||
// beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
// iterationType?: IterationType,
|
||||
// includeNull?: true
|
||||
// ): ReturnType<C>[];
|
||||
//
|
||||
// /**
|
||||
// * Time complexity: O(n)
|
||||
// * Space complexity: O(log n)
|
||||
// *
|
||||
// * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
|
||||
// * node, either recursively or iteratively.
|
||||
// * @param {C} callback - The `callback` parameter is a function that will be called for each node in
|
||||
// * the subtree traversal. It takes a single parameter, which is the current node being traversed, and
|
||||
// * returns a value of any type.
|
||||
// * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
|
||||
// * starting node or key from which the subtree traversal should begin. It can be of type `K`,
|
||||
// * `N`, `null`, or `undefined`. If not provided, the `root` property of the current object is used as
|
||||
// * the default value.
|
||||
// * @param iterationType - The `iterationType` parameter determines the type of traversal to be
|
||||
// * performed on the subtree. It can have two possible values:
|
||||
// * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
|
||||
// * whether to include null values in the traversal. If `includeNull` is set to `true`, the
|
||||
// * traversal will include null values, otherwise it will skip them.
|
||||
// * @returns The function `subTreeTraverse` returns an array of values that are the result of invoking
|
||||
// * the `callback` function on each node in the subtree. The type of the array nodes is determined
|
||||
// * by the return type of the `callback` function.
|
||||
// */
|
||||
// subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
|
||||
// callback: C = this._defaultOneParamCallback as C,
|
||||
// beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
// iterationType = this.iterationType,
|
||||
// includeNull = false
|
||||
// ): ReturnType<C>[] {
|
||||
// console.warn('subTreeTraverse is unnecessary, since the dfs method can substitute it.');
|
||||
//
|
||||
// beginRoot = this.ensureNode(beginRoot);
|
||||
//
|
||||
// const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
|
||||
// if (!beginRoot) return ans;
|
||||
//
|
||||
// if (iterationType === IterationType.RECURSIVE) {
|
||||
// const _traverse = (cur: N | null | undefined) => {
|
||||
// if (cur !== undefined) {
|
||||
// ans.push(callback(cur));
|
||||
// if (includeNull) {
|
||||
// cur && this.isNodeOrNull(cur.left) && _traverse(cur.left);
|
||||
// cur && this.isNodeOrNull(cur.right) && _traverse(cur.right);
|
||||
// } else {
|
||||
// cur && cur.left && _traverse(cur.left);
|
||||
// cur && cur.right && _traverse(cur.right);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// _traverse(beginRoot);
|
||||
// } else {
|
||||
// const stack: (N | null | undefined)[] = [beginRoot];
|
||||
//
|
||||
// while (stack.length > 0) {
|
||||
// const cur = stack.pop();
|
||||
// if (cur !== undefined) {
|
||||
// ans.push(callback(cur));
|
||||
// if (includeNull) {
|
||||
// cur && this.isNodeOrNull(cur.right) && stack.push(cur.right);
|
||||
// cur && this.isNodeOrNull(cur.left) && stack.push(cur.left);
|
||||
// } else {
|
||||
// cur && cur.right && stack.push(cur.right);
|
||||
// cur && cur.left && stack.push(cur.left);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return ans;
|
||||
// }
|
||||
|
||||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
|
@ -1305,15 +1289,7 @@ export class BinaryTree<
|
|||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
||||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
dfs<C extends BTNCallback<N | null | undefined>>(
|
||||
dfs<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
|
@ -1451,14 +1427,7 @@ export class BinaryTree<
|
|||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
||||
bfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
bfs<C extends BTNCallback<N | null | undefined>>(
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
|
@ -1486,7 +1455,7 @@ export class BinaryTree<
|
|||
* @returns an array of values that are the result of invoking the callback function on each node in
|
||||
* the breadth-first traversal of a binary tree.
|
||||
*/
|
||||
bfs<C extends BTNCallback<N | null | undefined>>(
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType = this.iterationType,
|
||||
|
@ -1552,14 +1521,7 @@ export class BinaryTree<
|
|||
includeNull?: false
|
||||
): ReturnType<C>[][];
|
||||
|
||||
listLevels<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[][];
|
||||
|
||||
listLevels<C extends BTNCallback<N | null | undefined>>(
|
||||
listLevels<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
beginRoot?: KeyOrNodeOrEntry<K, V, N>,
|
||||
iterationType?: IterationType,
|
||||
|
@ -1587,7 +1549,7 @@ export class BinaryTree<
|
|||
* be excluded
|
||||
* @returns The function `listLevels` returns a two-dimensional array of type `ReturnType<C>[][]`.
|
||||
*/
|
||||
listLevels<C extends BTNCallback<N | null | undefined>>(
|
||||
listLevels<C extends BTNCallback<N | null>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType = this.iterationType,
|
||||
|
@ -1598,7 +1560,7 @@ export class BinaryTree<
|
|||
if (!beginRoot) return levelsNodes;
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const _recursive = (node: N | null | undefined, level: number) => {
|
||||
const _recursive = (node: N | null, level: number) => {
|
||||
if (!levelsNodes[level]) levelsNodes[level] = [];
|
||||
levelsNodes[level].push(callback(node));
|
||||
if (includeNull) {
|
||||
|
@ -1612,7 +1574,7 @@ export class BinaryTree<
|
|||
|
||||
_recursive(beginRoot, 0);
|
||||
} else {
|
||||
const stack: [N | null | undefined, number][] = [[beginRoot, 0]];
|
||||
const stack: [N | null, number][] = [[beginRoot, 0]];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const head = stack.pop()!;
|
||||
|
@ -1923,7 +1885,7 @@ export class BinaryTree<
|
|||
display(beginRoot);
|
||||
}
|
||||
|
||||
protected *_getIterator(node = this.root): IterableIterator<[K, V | undefined]> {
|
||||
protected* _getIterator(node = this.root): IterableIterator<[K, V | undefined]> {
|
||||
if (!node) return;
|
||||
|
||||
if (this.iterationType === IterationType.ITERATIVE) {
|
||||
|
|
|
@ -13,7 +13,7 @@ import type {
|
|||
BTNodePureExemplar,
|
||||
KeyOrNodeOrEntry
|
||||
} from '../../types';
|
||||
import { BSTVariant, CP, IterationType } from '../../types';
|
||||
import { BSTVariant, CP, DFSOrderPattern, IterationType } from '../../types';
|
||||
import { BinaryTree, BinaryTreeNode } from './binary-tree';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
import { Queue } from '../queue';
|
||||
|
@ -83,14 +83,13 @@ export class BSTNode<K = any, V = any, N extends BSTNode<K, V, N> = BSTNodeNeste
|
|||
* 7. No Auto-Balancing: Standard BSTs don't automatically balance themselves.
|
||||
*/
|
||||
export class BST<
|
||||
K = any,
|
||||
V = any,
|
||||
N extends BSTNode<K, V, N> = BSTNode<K, V, BSTNodeNested<K, V>>,
|
||||
TREE extends BST<K, V, N, TREE> = BST<K, V, N, BSTNested<K, V, N>>
|
||||
>
|
||||
K = any,
|
||||
V = any,
|
||||
N extends BSTNode<K, V, N> = BSTNode<K, V, BSTNodeNested<K, V>>,
|
||||
TREE extends BST<K, V, N, TREE> = BST<K, V, N, BSTNested<K, V, N>>
|
||||
>
|
||||
extends BinaryTree<K, V, N, TREE>
|
||||
implements IBinaryTree<K, V, N, TREE>
|
||||
{
|
||||
implements IBinaryTree<K, V, N, TREE> {
|
||||
/**
|
||||
* This is the constructor function for a binary search tree class in TypeScript, which initializes
|
||||
* the tree with optional keysOrNodesOrEntries and options.
|
||||
|
@ -172,7 +171,7 @@ export class BST<
|
|||
} else {
|
||||
node = this.createNode(key, value);
|
||||
}
|
||||
} else if (this.isNotNodeInstance(keyOrNodeOrEntry)) {
|
||||
} else if (!this.isNode(keyOrNodeOrEntry)) {
|
||||
node = this.createNode(keyOrNodeOrEntry, value);
|
||||
} else {
|
||||
return;
|
||||
|
@ -213,16 +212,6 @@ export class BST<
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "isNotNodeInstance" checks if a potential key is a K.
|
||||
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
||||
* data type.
|
||||
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
||||
*/
|
||||
override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry<K, V, N>): potentialKey is K {
|
||||
return !(potentialKey instanceof BSTNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if an keyOrNodeOrEntry is an instance of BSTNode.
|
||||
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry<K, V, N>`.
|
||||
|
@ -408,43 +397,6 @@ export class BST<
|
|||
return inserted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(n)
|
||||
* Adding each element individually in a balanced tree. Additional space is required for the sorted array.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(n)
|
||||
*
|
||||
* The `lastKey` function returns the key of the rightmost node in a binary tree, or the key of the
|
||||
* leftmost node if the comparison result is greater than.
|
||||
* @param {K | N | undefined} beginRoot - The `beginRoot` parameter is optional and can be of
|
||||
* type `K`, `N`, or `undefined`. It represents the starting point for finding the last key in
|
||||
* the binary tree. If not provided, it defaults to the root of the binary tree (`this.root`).
|
||||
* @returns the key of the rightmost node in the binary tree if the comparison result is less than,
|
||||
* the key of the leftmost node if the comparison result is greater than, and the key of the
|
||||
* rightmost node otherwise. If no node is found, it returns 0.
|
||||
*/
|
||||
lastKey(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root): K | undefined {
|
||||
let current = this.ensureNode(beginRoot);
|
||||
if (!current) return undefined;
|
||||
|
||||
if (this._variant === BSTVariant.STANDARD) {
|
||||
// For BSTVariant.MIN, find the rightmost node
|
||||
while (current.right !== undefined) {
|
||||
current = current.right;
|
||||
}
|
||||
} else {
|
||||
// For BSTVariant.MAX, find the leftmost node
|
||||
while (current.left !== undefined) {
|
||||
current = current.left;
|
||||
}
|
||||
}
|
||||
return current.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(log n)
|
||||
* Space Complexity: O(1)
|
||||
|
@ -574,6 +526,133 @@ export class BST<
|
|||
return ans;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * The function overrides the subTreeTraverse method and returns the result of calling the super
|
||||
// * method with the provided arguments.
|
||||
// * @param {C} callback - The `callback` parameter is a function that will be called for each node in
|
||||
// * the subtree traversal. It should accept a single parameter of type `N`, which represents a node in
|
||||
// * the tree. The return type of the callback function can be any type.
|
||||
// * @param beginRoot - The `beginRoot` parameter is the starting point for traversing the subtree. It
|
||||
// * can be either a key, a node, or an entry.
|
||||
// * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
|
||||
// * be performed during the traversal of the subtree. It can have one of the following values:
|
||||
// * @returns The method is returning an array of the return type of the callback function.
|
||||
// */
|
||||
// override subTreeTraverse<C extends BTNCallback<N>>(
|
||||
// callback: C = this._defaultOneParamCallback as C,
|
||||
// beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
// iterationType = this.iterationType
|
||||
// ): ReturnType<C>[] {
|
||||
// return super.subTreeTraverse(callback, beginRoot, iterationType, false);
|
||||
// }
|
||||
|
||||
/**
|
||||
* The function overrides the depth-first search method and returns an array of the return types of
|
||||
* the callback function.
|
||||
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
||||
* during the depth-first search traversal. It is an optional parameter and if not provided, a
|
||||
* default callback function will be used.
|
||||
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter specifies the order in which the
|
||||
* nodes are visited during the depth-first search. It can have one of the following values:
|
||||
* @param beginRoot - The `beginRoot` parameter is used to specify the starting point for the
|
||||
* Depth-First Search (DFS) traversal. It can be either a key, a node, or an entry in the tree. If no
|
||||
* value is provided, the DFS traversal will start from the root of the tree.
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter specifies the type of
|
||||
* iteration to be used during the Depth-First Search (DFS) traversal. It can have one of the
|
||||
* following values:
|
||||
* @returns The method is returning an array of the return type of the callback function.
|
||||
*/
|
||||
override dfs<C extends BTNCallback<N>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
pattern: DFSOrderPattern = 'in',
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType: IterationType = IterationType.ITERATIVE
|
||||
): ReturnType<C>[] {
|
||||
return super.dfs(callback, pattern, beginRoot, iterationType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function overrides the breadth-first search method and returns an array of the return types of
|
||||
* the callback function.
|
||||
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
||||
* visited during the breadth-first search traversal. It is an optional parameter and if not
|
||||
* provided, a default callback function will be used.
|
||||
* @param beginRoot - The `beginRoot` parameter is the starting point for the breadth-first search
|
||||
* traversal. It can be either a key, a node, or an entry in the tree. If not specified, the root of
|
||||
* the tree is used as the starting point.
|
||||
* @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
|
||||
* be performed during the breadth-first search (BFS) traversal. It determines the order in which the
|
||||
* nodes are visited.
|
||||
* @returns The method is returning an array of the return type of the callback function.
|
||||
*/
|
||||
override bfs<C extends BTNCallback<N>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType = this.iterationType
|
||||
): ReturnType<C>[] {
|
||||
return super.bfs(callback, beginRoot, iterationType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function overrides the listLevels method and returns an array of arrays containing the return
|
||||
* type of the callback function for each level of the tree.
|
||||
* @param {C} callback - The `callback` parameter is a generic type `C` that extends
|
||||
* `BTNCallback<N>`. It represents a callback function that will be called for each node in the tree
|
||||
* during the level listing process.
|
||||
* @param beginRoot - The `beginRoot` parameter is used to specify the starting point for listing the
|
||||
* levels of a binary tree. It can be either a key, a node, or an entry in the binary tree. If not
|
||||
* provided, the root of the binary tree is used as the starting point.
|
||||
* @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
|
||||
* be performed on the tree. It determines the order in which the nodes are visited during the
|
||||
* iteration.
|
||||
* @returns The method is returning a two-dimensional array of the return type of the callback
|
||||
* function.
|
||||
*/
|
||||
override listLevels<C extends BTNCallback<N>>(
|
||||
callback: C = this._defaultOneParamCallback as C,
|
||||
beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
|
||||
iterationType = this.iterationType
|
||||
): ReturnType<C>[][] {
|
||||
return super.listLevels(callback, beginRoot, iterationType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(n)
|
||||
* Adding each element individually in a balanced tree. Additional space is required for the sorted array.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(n)
|
||||
*
|
||||
* The `lastKey` function returns the key of the rightmost node in a binary tree, or the key of the
|
||||
* leftmost node if the comparison result is greater than.
|
||||
* @param {K | N | undefined} beginRoot - The `beginRoot` parameter is optional and can be of
|
||||
* type `K`, `N`, or `undefined`. It represents the starting point for finding the last key in
|
||||
* the binary tree. If not provided, it defaults to the root of the binary tree (`this.root`).
|
||||
* @returns the key of the rightmost node in the binary tree if the comparison result is less than,
|
||||
* the key of the leftmost node if the comparison result is greater than, and the key of the
|
||||
* rightmost node otherwise. If no node is found, it returns 0.
|
||||
*/
|
||||
lastKey(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root): K | undefined {
|
||||
let current = this.ensureNode(beginRoot);
|
||||
if (!current) return undefined;
|
||||
|
||||
if (this._variant === BSTVariant.STANDARD) {
|
||||
// For BSTVariant.MIN, find the rightmost node
|
||||
while (current.right !== undefined) {
|
||||
current = current.right;
|
||||
}
|
||||
} else {
|
||||
// For BSTVariant.MAX, find the leftmost node
|
||||
while (current.left !== undefined) {
|
||||
current = current.left;
|
||||
}
|
||||
}
|
||||
return current.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(log n)
|
||||
* Space Complexity: O(log n)
|
||||
|
|
|
@ -41,14 +41,13 @@ export class RedBlackTreeNode<
|
|||
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
|
||||
*/
|
||||
export class RedBlackTree<
|
||||
K = any,
|
||||
V = any,
|
||||
N extends RedBlackTreeNode<K, V, N> = RedBlackTreeNode<K, V, RedBlackTreeNodeNested<K, V>>,
|
||||
TREE extends RedBlackTree<K, V, N, TREE> = RedBlackTree<K, V, N, RedBlackTreeNested<K, V, N>>
|
||||
>
|
||||
K = any,
|
||||
V = any,
|
||||
N extends RedBlackTreeNode<K, V, N> = RedBlackTreeNode<K, V, RedBlackTreeNodeNested<K, V>>,
|
||||
TREE extends RedBlackTree<K, V, N, TREE> = RedBlackTree<K, V, N, RedBlackTreeNested<K, V, N>>
|
||||
>
|
||||
extends BST<K, V, N, TREE>
|
||||
implements IBinaryTree<K, V, N, TREE>
|
||||
{
|
||||
implements IBinaryTree<K, V, N, TREE> {
|
||||
Sentinel: N = new RedBlackTreeNode<K, V>(NaN as K) as unknown as N;
|
||||
|
||||
/**
|
||||
|
@ -133,7 +132,7 @@ export class RedBlackTree<
|
|||
} else {
|
||||
node = this.createNode(key, value, RBTNColor.RED);
|
||||
}
|
||||
} else if (this.isNotNodeInstance(keyOrNodeOrEntry)) {
|
||||
} else if (!this.isNode(keyOrNodeOrEntry)) {
|
||||
node = this.createNode(keyOrNodeOrEntry, value, RBTNColor.RED);
|
||||
} else {
|
||||
return;
|
||||
|
@ -161,16 +160,6 @@ export class RedBlackTree<
|
|||
return node instanceof RedBlackTreeNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "isNotNodeInstance" checks if a potential key is a K.
|
||||
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
||||
* data type.
|
||||
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
||||
*/
|
||||
override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry<K, V, N>): potentialKey is K {
|
||||
return !(potentialKey instanceof RedBlackTreeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(log n)
|
||||
* Space Complexity: O(1)
|
||||
|
|
|
@ -45,14 +45,13 @@ export class TreeMultimapNode<
|
|||
* The only distinction between a TreeMultimap and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
|
||||
*/
|
||||
export class TreeMultimap<
|
||||
K = any,
|
||||
V = any,
|
||||
N extends TreeMultimapNode<K, V, N> = TreeMultimapNode<K, V, TreeMultimapNodeNested<K, V>>,
|
||||
TREE extends TreeMultimap<K, V, N, TREE> = TreeMultimap<K, V, N, TreeMultimapNested<K, V, N>>
|
||||
>
|
||||
K = any,
|
||||
V = any,
|
||||
N extends TreeMultimapNode<K, V, N> = TreeMultimapNode<K, V, TreeMultimapNodeNested<K, V>>,
|
||||
TREE extends TreeMultimap<K, V, N, TREE> = TreeMultimap<K, V, N, TreeMultimapNested<K, V, N>>
|
||||
>
|
||||
extends AVLTree<K, V, N, TREE>
|
||||
implements IBinaryTree<K, V, N, TREE>
|
||||
{
|
||||
implements IBinaryTree<K, V, N, TREE> {
|
||||
constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, N>> = [], options?: TreeMultimapOptions<K>) {
|
||||
super([], options);
|
||||
if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
|
||||
|
@ -63,7 +62,7 @@ export class TreeMultimap<
|
|||
// TODO the _count is not accurate after nodes count modified
|
||||
get count(): number {
|
||||
let sum = 0;
|
||||
this.subTreeTraverse(node => (sum += node.count));
|
||||
this.dfs(node => (sum += node.count));
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
@ -112,7 +111,7 @@ export class TreeMultimap<
|
|||
} else {
|
||||
node = this.createNode(key, value, count);
|
||||
}
|
||||
} else if (this.isNotNodeInstance(keyOrNodeOrEntry)) {
|
||||
} else if (!this.isNode(keyOrNodeOrEntry)) {
|
||||
node = this.createNode(keyOrNodeOrEntry, value, count);
|
||||
} else {
|
||||
return;
|
||||
|
@ -130,16 +129,6 @@ export class TreeMultimap<
|
|||
return keyOrNodeOrEntry instanceof TreeMultimapNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "isNotNodeInstance" checks if a potential key is a K.
|
||||
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
||||
* data type.
|
||||
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
||||
*/
|
||||
override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry<K, V, N>): potentialKey is K {
|
||||
return !(potentialKey instanceof TreeMultimapNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(log n)
|
||||
* Space Complexity: O(1)
|
||||
|
|
|
@ -61,14 +61,13 @@ export abstract class AbstractEdge<E = any> {
|
|||
}
|
||||
|
||||
export abstract class AbstractGraph<
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends AbstractVertex<V> = AbstractVertex<V>,
|
||||
EO extends AbstractEdge<E> = AbstractEdge<E>
|
||||
>
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends AbstractVertex<V> = AbstractVertex<V>,
|
||||
EO extends AbstractEdge<E> = AbstractEdge<E>
|
||||
>
|
||||
extends IterableEntryBase<VertexKey, V | undefined>
|
||||
implements IGraph<V, E, VO, EO>
|
||||
{
|
||||
implements IGraph<V, E, VO, EO> {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
@ -611,14 +610,14 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
getMinDist &&
|
||||
distMap.forEach((d, v) => {
|
||||
if (v !== srcVertex) {
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
if (genPaths) minDest = v;
|
||||
}
|
||||
distMap.forEach((d, v) => {
|
||||
if (v !== srcVertex) {
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
if (genPaths) minDest = v;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
genPaths && getPaths(minDest);
|
||||
|
||||
|
@ -1273,7 +1272,7 @@ export abstract class AbstractGraph<
|
|||
return mapped;
|
||||
}
|
||||
|
||||
protected *_getIterator(): IterableIterator<[VertexKey, V | undefined]> {
|
||||
protected* _getIterator(): IterableIterator<[VertexKey, V | undefined]> {
|
||||
for (const vertex of this._vertexMap.values()) {
|
||||
yield [vertex.key, vertex.value];
|
||||
}
|
||||
|
|
|
@ -46,14 +46,13 @@ export class DirectedEdge<E = any> extends AbstractEdge<E> {
|
|||
}
|
||||
|
||||
export class DirectedGraph<
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends DirectedVertex<V> = DirectedVertex<V>,
|
||||
EO extends DirectedEdge<E> = DirectedEdge<E>
|
||||
>
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends DirectedVertex<V> = DirectedVertex<V>,
|
||||
EO extends DirectedEdge<E> = DirectedEdge<E>
|
||||
>
|
||||
extends AbstractGraph<V, E, VO, EO>
|
||||
implements IGraph<V, E, VO, EO>
|
||||
{
|
||||
implements IGraph<V, E, VO, EO> {
|
||||
/**
|
||||
* The constructor function initializes an instance of a class.
|
||||
*/
|
||||
|
|
|
@ -43,14 +43,13 @@ export class UndirectedEdge<E = number> extends AbstractEdge<E> {
|
|||
}
|
||||
|
||||
export class UndirectedGraph<
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends UndirectedVertex<V> = UndirectedVertex<V>,
|
||||
EO extends UndirectedEdge<E> = UndirectedEdge<E>
|
||||
>
|
||||
V = any,
|
||||
E = any,
|
||||
VO extends UndirectedVertex<V> = UndirectedVertex<V>,
|
||||
EO extends UndirectedEdge<E> = UndirectedEdge<E>
|
||||
>
|
||||
extends AbstractGraph<V, E, VO, EO>
|
||||
implements IGraph<V, E, VO, EO>
|
||||
{
|
||||
implements IGraph<V, E, VO, EO> {
|
||||
/**
|
||||
* The constructor initializes a new Map object to store edgeMap.
|
||||
*/
|
||||
|
|
|
@ -24,24 +24,6 @@ import { isWeakKey, rangeCheck } from '../../utils';
|
|||
export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
|
||||
protected _store: { [key: string]: HashMapStoreItem<K, V> } = {};
|
||||
protected _objMap: Map<object, V> = new Map();
|
||||
protected _toEntryFn: (rawElement: R) => [K, V] = (rawElement: R) => {
|
||||
if (this.isEntry(rawElement)) {
|
||||
// TODO, For performance optimization, it may be necessary to only inspect the first element traversed.
|
||||
return rawElement;
|
||||
} else {
|
||||
throw new Error(
|
||||
"If the provided rawCollection does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
get toEntryFn() {
|
||||
return this._toEntryFn;
|
||||
}
|
||||
|
||||
isEntry(rawElement: any): rawElement is [K, V] {
|
||||
return Array.isArray(rawElement) && rawElement.length === 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor function initializes a HashMap object with an optional initial collection and
|
||||
|
@ -66,12 +48,31 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|||
}
|
||||
}
|
||||
|
||||
protected _toEntryFn: (rawElement: R) => [K, V] = (rawElement: R) => {
|
||||
if (this.isEntry(rawElement)) {
|
||||
// TODO, For performance optimization, it may be necessary to only inspect the first element traversed.
|
||||
return rawElement;
|
||||
} else {
|
||||
throw new Error(
|
||||
"If the provided rawCollection does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
get toEntryFn() {
|
||||
return this._toEntryFn;
|
||||
}
|
||||
|
||||
protected _size = 0;
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
isEntry(rawElement: any): rawElement is [K, V] {
|
||||
return Array.isArray(rawElement) && rawElement.length === 2;
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.size === 0;
|
||||
}
|
||||
|
@ -248,7 +249,7 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|||
* The function returns an iterator that yields key-value pairs from both an object store and an
|
||||
* object map.
|
||||
*/
|
||||
protected *_getIterator(): IterableIterator<[K, V]> {
|
||||
protected* _getIterator(): IterableIterator<[K, V]> {
|
||||
for (const node of Object.values(this._store)) {
|
||||
yield [node.key, node.value] as [K, V];
|
||||
}
|
||||
|
@ -347,7 +348,7 @@ export class LinkedHashMap<K = any, V = any> extends IterableEntryBase<K, V> {
|
|||
/**
|
||||
* The `begin()` function in TypeScript iterates over a linked list and yields key-value pairs.
|
||||
*/
|
||||
*begin() {
|
||||
* begin() {
|
||||
let node = this._head;
|
||||
while (node !== this._sentinel) {
|
||||
yield [node.key, node.value];
|
||||
|
@ -359,7 +360,7 @@ export class LinkedHashMap<K = any, V = any> extends IterableEntryBase<K, V> {
|
|||
* The function `reverseBegin()` iterates over a linked list in reverse order, yielding each node's
|
||||
* key and value.
|
||||
*/
|
||||
*reverseBegin() {
|
||||
* reverseBegin() {
|
||||
let node = this._tail;
|
||||
while (node !== this._sentinel) {
|
||||
yield [node.key, node.value];
|
||||
|
@ -660,7 +661,7 @@ export class LinkedHashMap<K = any, V = any> extends IterableEntryBase<K, V> {
|
|||
*
|
||||
* The above function is an iterator that yields key-value pairs from a linked list.
|
||||
*/
|
||||
protected *_getIterator() {
|
||||
protected* _getIterator() {
|
||||
let node = this._head;
|
||||
while (node !== this._sentinel) {
|
||||
yield [node.key, node.value] as [K, V];
|
||||
|
|
|
@ -391,7 +391,7 @@ export class Heap<E = any> extends IterableElementBase<E> {
|
|||
return mappedHeap;
|
||||
}
|
||||
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
for (const element of this.elements) {
|
||||
yield element;
|
||||
}
|
||||
|
|
|
@ -808,7 +808,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
|
|||
/**
|
||||
* The function returns an iterator that iterates over the values of a linked list.
|
||||
*/
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
let current = this.head;
|
||||
|
||||
while (current) {
|
||||
|
|
|
@ -741,7 +741,7 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
|
|||
return mappedList;
|
||||
}
|
||||
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
let current = this.head;
|
||||
|
||||
while (current) {
|
||||
|
|
|
@ -232,7 +232,7 @@ export class Deque<E> extends IterableElementBase<E> {
|
|||
/**
|
||||
* The below function is a generator that yields elements from a collection one by one.
|
||||
*/
|
||||
*begin(): Generator<E> {
|
||||
* begin(): Generator<E> {
|
||||
let index = 0;
|
||||
while (index < this.size) {
|
||||
yield this.getAt(index);
|
||||
|
@ -244,7 +244,7 @@ export class Deque<E> extends IterableElementBase<E> {
|
|||
* The function `reverseBegin()` is a generator that yields elements in reverse order starting from
|
||||
* the last element.
|
||||
*/
|
||||
*reverseBegin(): Generator<E> {
|
||||
* reverseBegin(): Generator<E> {
|
||||
let index = this.size - 1;
|
||||
while (index >= 0) {
|
||||
yield this.getAt(index);
|
||||
|
@ -735,7 +735,7 @@ export class Deque<E> extends IterableElementBase<E> {
|
|||
* The above function is an implementation of the iterator protocol in TypeScript, allowing the
|
||||
* object to be iterated over using a for...of loop.
|
||||
*/
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
for (let i = 0; i < this.size; ++i) {
|
||||
yield this.getAt(i);
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ export class Queue<E = any> extends IterableElementBase<E> {
|
|||
* Space Complexity: O(n)
|
||||
*/
|
||||
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
for (const item of this.elements) {
|
||||
yield item;
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ export class Stack<E = any> extends IterableElementBase<E> {
|
|||
* Custom iterator for the Stack class.
|
||||
* @returns An iterator object.
|
||||
*/
|
||||
protected *_getIterator(): IterableIterator<E> {
|
||||
protected* _getIterator(): IterableIterator<E> {
|
||||
for (let i = 0; i < this.elements.length; i++) {
|
||||
yield this.elements[i];
|
||||
}
|
||||
|
|
|
@ -410,7 +410,7 @@ export class Trie extends IterableElementBase<string> {
|
|||
return newTrie;
|
||||
}
|
||||
|
||||
protected *_getIterator(): IterableIterator<string> {
|
||||
protected* _getIterator(): IterableIterator<string> {
|
||||
function* _dfs(node: TrieNode, path: string): IterableIterator<string> {
|
||||
if (node.isEnd) {
|
||||
yield path;
|
||||
|
|
|
@ -2,12 +2,12 @@ export type VertexKey = string | number;
|
|||
|
||||
export type DijkstraResult<V> =
|
||||
| {
|
||||
distMap: Map<V, number>;
|
||||
distPaths?: Map<V, V[]>;
|
||||
preMap: Map<V, V | undefined>;
|
||||
seen: Set<V>;
|
||||
paths: V[][];
|
||||
minDist: number;
|
||||
minPath: V[];
|
||||
}
|
||||
distMap: Map<V, number>;
|
||||
distPaths?: Map<V, V[]>;
|
||||
preMap: Map<V, V | undefined>;
|
||||
seen: Set<V>;
|
||||
paths: V[][];
|
||||
minDist: number;
|
||||
minPath: V[];
|
||||
}
|
||||
| undefined;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<meta charset='UTF-8'>
|
||||
<title>CDN Test</title>
|
||||
<!-- <script src="../../dist/umd/data-structure-typed.min.js"></script>-->
|
||||
<script src="../../dist/umd/data-structure-typed.js"></script>
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>-->
|
||||
<script src="../../dist/umd/data-structure-typed.js"></script>
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>-->
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.42.2/dist/umd/data-structure-typed.min.js'></script>-->
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.43.3/dist/umd/data-structure-typed.min.js'></script>-->
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.44.0/dist/umd/data-structure-typed.min.js'></script>-->
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Deque } from '../../../../src';
|
||||
import { Deque as CDeque } from 'js-sdsl';
|
||||
import * as Benchmark from 'benchmark';
|
||||
import { magnitude } from '../../../utils';
|
||||
import { getRandomInt, magnitude } from '../../../utils';
|
||||
import { isCompetitor } from '../../../config';
|
||||
|
||||
export const suite = new Benchmark.Suite();
|
||||
const { MILLION, HUNDRED_THOUSAND } = magnitude;
|
||||
const { MILLION, HUNDRED_THOUSAND, TEN_THOUSAND } = magnitude;
|
||||
|
||||
suite.add(`${MILLION.toLocaleString()} push`, () => {
|
||||
const deque = new Deque<number>();
|
||||
|
@ -20,6 +20,12 @@ if (isCompetitor) {
|
|||
}
|
||||
|
||||
suite
|
||||
.add(`${TEN_THOUSAND.toLocaleString()} push & delete`, () => {
|
||||
const _deque = new Deque<number>();
|
||||
|
||||
for (let i = 0; i < TEN_THOUSAND; i++) _deque.push(i);
|
||||
for (let i = 0; i < TEN_THOUSAND; i++) _deque.delete(getRandomInt(0, TEN_THOUSAND - 1));
|
||||
})
|
||||
.add(`${MILLION.toLocaleString()} push & pop`, () => {
|
||||
const _deque = new Deque<number>();
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ describe('AVL Tree Test', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), node15);
|
||||
node15 && tree.dfs(node => (subTreeSum += node.key), 'pre', node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -132,7 +132,7 @@ describe('AVL Tree Test recursively', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), node15);
|
||||
node15 && tree.dfs(node => (subTreeSum += node.key), 'pre', node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
|
|
@ -238,16 +238,45 @@ describe('BinaryTree', () => {
|
|||
expect(tree.getNodes(tree.getNodeByKey(2), undefined, false, tree.root)).toEqual([tree.getNodeByKey(2)]);
|
||||
});
|
||||
|
||||
it('should subTreeTraverse', () => {
|
||||
// it('should subTreeTraverse', () => {
|
||||
// tree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
||||
// expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE)).toEqual([6, 3, 7]);
|
||||
// expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE, false)).toEqual([6, 3, 7]);
|
||||
// expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 3, 7]);
|
||||
// expect(
|
||||
// tree.subTreeTraverse(node => (node ? node.key : null), tree.getNode(6), IterationType.ITERATIVE, true)
|
||||
// ).toEqual([6, 3, 7, null]);
|
||||
// expect(
|
||||
// tree.subTreeTraverse(node => (node ? node.key : node), tree.getNode(6), IterationType.ITERATIVE, true)
|
||||
// ).toEqual([6, 3, 7, null]);
|
||||
// expect(
|
||||
// tree.subTreeTraverse(node => (node ? node.key : null), tree.getNode(6), IterationType.RECURSIVE, true)
|
||||
// ).toEqual([6, 3, 7, null]);
|
||||
// });
|
||||
|
||||
it('should sub tree traverse', () => {
|
||||
tree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
||||
expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE)).toEqual([6, 3, 7]);
|
||||
expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 3, 7]);
|
||||
expect(
|
||||
tree.subTreeTraverse(node => (node ? node.key : null), tree.getNode(6), IterationType.ITERATIVE, true)
|
||||
).toEqual([6, 3, 7, null]);
|
||||
expect(
|
||||
tree.subTreeTraverse(node => (node ? node.key : null), tree.getNode(6), IterationType.RECURSIVE, true)
|
||||
).toEqual([6, 3, 7, null]);
|
||||
expect(tree.dfs(node => node.key, 'pre', tree.getNode(6), IterationType.ITERATIVE)).toEqual([6, 3, 7]);
|
||||
expect(tree.dfs(node => node.key, 'pre', tree.getNode(6), IterationType.ITERATIVE, false)).toEqual([6, 3, 7]);
|
||||
expect(tree.dfs(node => node.key, 'pre', tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 3, 7]);
|
||||
expect(tree.dfs(node => (node ? node.key : null), 'pre', tree.getNode(6), IterationType.ITERATIVE, true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
null
|
||||
]);
|
||||
expect(tree.dfs(node => (node ? node.key : node), 'pre', tree.getNode(6), IterationType.ITERATIVE, true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
null
|
||||
]);
|
||||
expect(tree.dfs(node => (node ? node.key : null), 'pre', tree.getNode(6), IterationType.RECURSIVE, true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
null
|
||||
]);
|
||||
});
|
||||
|
||||
it('should clear the tree', () => {
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('BST operations test', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15);
|
||||
node15 && bst.dfs(node => (subTreeSum += node.key), 'pre', 15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -257,7 +257,7 @@ describe('BST operations test', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15);
|
||||
node15 && objBST.dfs(node => (subTreeSum += node.key), 'pre', node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -444,7 +444,7 @@ describe('BST operations test recursively', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15);
|
||||
node15 && bst.dfs(node => (subTreeSum += node.key), 'pre', 15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -645,7 +645,7 @@ describe('BST operations test recursively', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15);
|
||||
node15 && objBST.dfs(node => (subTreeSum += node.key), 'pre', node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -868,14 +868,10 @@ describe('BST Performance test', function () {
|
|||
it('should subTreeTraverse, null should be ignored', () => {
|
||||
const bst = new BST();
|
||||
bst.addMany([4, 2, 6, 1, 3, 5, 7]);
|
||||
expect(bst.subTreeTraverse(node => node.key, bst.getNode(6), IterationType.ITERATIVE)).toEqual([6, 5, 7]);
|
||||
expect(bst.subTreeTraverse(node => node.key, bst.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
|
||||
expect(bst.subTreeTraverse(node => node?.key ?? undefined, bst.getNode(6), IterationType.ITERATIVE, true)).toEqual([
|
||||
6, 5, 7
|
||||
]);
|
||||
expect(bst.subTreeTraverse(node => node?.key ?? undefined, bst.getNode(6), IterationType.RECURSIVE, true)).toEqual([
|
||||
6, 5, 7
|
||||
]);
|
||||
expect(bst.dfs(node => node.key, 'pre', bst.getNode(6), IterationType.ITERATIVE)).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node.key, 'pre', bst.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'pre', bst.getNode(6), IterationType.ITERATIVE)).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'pre', bst.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ describe('TreeMultimap operations test1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(15);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (subTreeSum += node.key), 15);
|
||||
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
|
||||
expect(subTreeSum).toBe(31);
|
||||
let lesserSum = 0;
|
||||
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
|
||||
|
@ -104,7 +104,7 @@ describe('TreeMultimap operations test1', () => {
|
|||
|
||||
expect(node15 instanceof TreeMultimapNode);
|
||||
if (node15 instanceof TreeMultimapNode) {
|
||||
const subTreeAdd = treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (node.count += 1), 15);
|
||||
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = treeMultimap.getNode(11);
|
||||
|
@ -350,7 +350,7 @@ describe('TreeMultimap operations test recursively1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(15);
|
||||
|
||||
let subTreeSum = 0;
|
||||
node15 && treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (subTreeSum += node.key), 15);
|
||||
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
|
||||
expect(subTreeSum).toBe(31);
|
||||
let lesserSum = 0;
|
||||
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
|
||||
|
@ -358,7 +358,7 @@ describe('TreeMultimap operations test recursively1', () => {
|
|||
|
||||
expect(node15 instanceof TreeMultimapNode);
|
||||
if (node15 instanceof TreeMultimapNode) {
|
||||
const subTreeAdd = treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (node.count += 1), 15);
|
||||
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = treeMultimap.getNode(11);
|
||||
|
|
|
@ -85,7 +85,8 @@ class MyGraph<
|
|||
describe('AbstractGraph Operation Test', () => {
|
||||
const myGraph: MyGraph<number, string> = new MyGraph<number, string>();
|
||||
|
||||
beforeEach(() => {});
|
||||
beforeEach(() => {
|
||||
});
|
||||
it('should edge cases', function () {
|
||||
myGraph.addVertex('A', 1);
|
||||
myGraph.addVertex('B', 2);
|
||||
|
|
|
@ -110,6 +110,8 @@ describe('HashMap Test2', () => {
|
|||
|
||||
test('Inheritability test', () => {
|
||||
class ExtendedHashMap<K, V> extends HashMap<K, V> {
|
||||
someOtherParam?: string;
|
||||
|
||||
constructor(
|
||||
elements: Iterable<[K, V]> = [],
|
||||
options?: {
|
||||
|
@ -118,8 +120,8 @@ describe('HashMap Test2', () => {
|
|||
}
|
||||
) {
|
||||
const { someOtherParam, ...restOptions } = options || {};
|
||||
// do something with someOtherParam
|
||||
super(elements, restOptions);
|
||||
this.someOtherParam = someOtherParam;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,8 @@ describe('Deque - Complex Operations', () => {
|
|||
expect([...deque]).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
test('shrinkToFit should reduce the memory footprint', () => {});
|
||||
test('shrinkToFit should reduce the memory footprint', () => {
|
||||
});
|
||||
});
|
||||
describe('Deque - Utility Operations', () => {
|
||||
let deque: Deque<number>;
|
||||
|
|
Loading…
Reference in a new issue