feat: Implement forEach, filter, map, reduce, and [Symbol.iterator] methods for all binary tree data structures

This commit is contained in:
Revone 2023-11-22 17:18:37 +08:00
parent 01b969edca
commit a41e222481
19 changed files with 430 additions and 99 deletions

View file

@ -29,7 +29,7 @@ Now you can use this library in Node.js and browser environments in CommonJS(req
### npm
```bash
npm i data-structure-typed
npm i --save data-structure-typed
```
### yarn

View file

@ -6,8 +6,8 @@
* @license MIT License
*/
import { BST, BSTNode } from './bst';
import type { AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey } from '../../types';
import { BTNCallback } from '../../types';
import type { AVLTreeNested, AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey } from '../../types';
import { BTNCallback, IterationType } from '../../types';
import { IBinaryTree } from '../../interfaces';
export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNested<V>> extends BSTNode<V, N> {
@ -19,9 +19,12 @@ export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNeste
}
}
export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N> {
export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>, TREE extends AVLTree<V, N, TREE> = AVLTree<V, N, AVLTreeNested<V, N>>>
extends BST<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
override options: AVLTreeOptions;
/**
* This is a constructor function for an AVL tree data structure in TypeScript.
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
@ -30,6 +33,11 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
*/
constructor(options?: AVLTreeOptions) {
super(options);
if (options) {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
}
}
/**
@ -45,6 +53,10 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
return new AVLTreeNode<V, N>(key, value) as N;
}
override createTree(options?: AVLTreeOptions) {
return new AVLTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.

View file

@ -8,6 +8,7 @@
import type { BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey } from '../../types';
import {
BinaryTreeNested,
BinaryTreePrintOptions,
BiTreeDeleteResult,
DFSOrderPattern,
@ -114,9 +115,10 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
* Represents a binary tree data structure.
* @template N - The type of the binary tree's nodes.
*/
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
implements IBinaryTree<V, N> {
iterationType: IterationType = IterationType.ITERATIVE;
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>, TREE extends BinaryTree<V, N, TREE> = BinaryTree<V, N, BinaryTreeNested<V, N>>>
implements IBinaryTree<V, N, TREE> {
options: BinaryTreeOptions;
/**
* Creates a new instance of BinaryTree.
@ -124,9 +126,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
constructor(options?: BinaryTreeOptions) {
if (options) {
const { iterationType = IterationType.ITERATIVE } = options;
this.iterationType = iterationType;
this.options = { iterationType: IterationType.ITERATIVE, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE };
}
this._size = 0;
}
@ -158,6 +162,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return new BinaryTreeNode<V, N>(key, value) as N;
}
createTree(options?: BinaryTreeOptions): TREE {
return new BinaryTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
@ -404,7 +412,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* values:
* @returns the height of the binary tree.
*/
getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.options.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
@ -453,7 +461,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* to calculate the minimum height of a binary tree. It can have two possible values:
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
*/
getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.options.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
@ -575,7 +583,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
callback: C = this._defaultOneParamCallback as C,
onlyOne = false,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N[] {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -664,7 +672,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: ReturnType<C> | null | undefined,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): boolean {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -723,7 +731,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: ReturnType<C> | null | undefined,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N | null | undefined {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -842,7 +850,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: ReturnType<C> | null | undefined,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): V | undefined {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -923,7 +931,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getLeftMost(
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N | null | undefined {
beginRoot = this.ensureNotKey(beginRoot);
@ -969,7 +977,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getRightMost(
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N | null | undefined {
// TODO support get right most by passing key in
beginRoot = this.ensureNotKey(beginRoot);
@ -1010,7 +1018,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* possible values:
* @returns a boolean value.
*/
isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.options.iterationType): boolean {
// TODO there is a bug
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return true;
@ -1057,7 +1065,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* expected to be
* @returns a boolean value.
*/
isBST(iterationType = this.iterationType): boolean {
isBST(iterationType = this.options.iterationType): boolean {
if (this.root === null) return true;
return this.isSubtreeBST(this.root, iterationType);
}
@ -1104,7 +1112,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @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 or not to include null values in the traversal. If `includeNull` is set to `true`, the
* 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 elements is determined
@ -1113,7 +1121,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
iterationType = this.options.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1383,7 +1391,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param iterationType - The `iterationType` parameter determines the type of iteration to be
* performed during the breadth-first search (BFS). It can have two possible values:
* @param [includeNull=false] - The `includeNull` parameter is a boolean flag that determines whether
* or not to include null values in the breadth-first search traversal. If `includeNull` is set to
* to include null values in the breadth-first search traversal. If `includeNull` is set to
* `true`, null values will be included in the traversal, otherwise they will be skipped.
* @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.
@ -1391,7 +1399,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
bfs<C extends BTNCallback<N | null | undefined>>(
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
iterationType = this.options.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1484,7 +1492,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param iterationType - The `iterationType` parameter determines the type of iteration to be
* performed on the tree. It can have two possible values:
* @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
* whether or not to include null values in the resulting levels. If `includeNull` is set to `true`,
* whether to include null values in the resulting levels. If `includeNull` is set to `true`,
* null values will be included in the levels. If `includeNull` is set to `false`, null values will
* be excluded
* @returns The function `listLevels` returns a two-dimensional array of type `ReturnType<C>[][]`.
@ -1492,7 +1500,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
listLevels<C extends BTNCallback<N | null | undefined>>(
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
iterationType = this.options.iterationType,
includeNull = false
): ReturnType<C>[][] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1692,6 +1700,48 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
forEach(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => void): void {
for (const entry of this) {
callback(entry, this);
}
}
filter(predicate: (entry: [BTNKey, V | undefined], tree: typeof this) => boolean) {
const newTree = this.createTree();
for (const [key, value] of this) {
if (predicate([key, value], this)) {
newTree.add(key, value);
}
}
return newTree;
}
// TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
// map<NV>(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => NV) {
// const newTree = this.createTree();
// for (const [key, value] of this) {
// newTree.add(key, callback([key, value], this));
// }
// return newTree;
// }
map(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => V) {
const newTree = this.createTree();
for (const [key, value] of this) {
newTree.add(key, callback([key, value], this));
}
return newTree;
}
reduce<T>(callback: (accumulator: T, entry: [BTNKey, V | undefined], tree: typeof this) => T, initialValue: T): T {
let accumulator = initialValue;
for (const [key, value] of this) {
accumulator = callback(accumulator, [key, value], this);
}
return accumulator;
}
/**
* The above function is an iterator for a binary tree that can be used to traverse the tree in
* either an iterative or recursive manner.
@ -1701,32 +1751,32 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
* binary tree nodes in a specific order.
*/
* [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
if (!node) {
return;
}
* [Symbol.iterator](node = this.root): Generator<[BTNKey, V | undefined], void, undefined> {
if (!node) return;
if (this.iterationType === IterationType.ITERATIVE) {
if (this.options.iterationType === IterationType.ITERATIVE) {
const stack: (N | null | undefined)[] = [];
let current: N | null | undefined = node;
while (current || stack.length > 0) {
while (current) {
while (current && !isNaN(current.key)) {
stack.push(current);
current = current.left;
}
current = stack.pop();
if (current) yield current.key;
if (current) current = current.right;
if (current && !isNaN(current.key)) {
yield [current.key, current.value];
current = current.right;
}
}
} else {
if (node.left) {
if (node.left && !isNaN(node.key)) {
yield* this[Symbol.iterator](node.left);
}
yield node.key;
if (node.right) {
yield [node.key, node.value];
if (node.right && !isNaN(node.key)) {
yield* this[Symbol.iterator](node.right);
}
}

View file

@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { BSTComparator, BSTNodeNested, BSTOptions, BTNCallback, BTNKey } from '../../types';
import type { BSTNested, BSTNodeNested, BSTOptions, BTNCallback, BTNKey } from '../../types';
import { CP, IterationType } from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
import { IBinaryTree } from '../../interfaces';
@ -62,9 +62,12 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
}
}
export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>>
extends BinaryTree<V, N>
implements IBinaryTree<V, N> {
export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>, TREE extends BST<V, N, TREE> = BST<V, N, BSTNested<V, N>>>
extends BinaryTree<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
override options: BSTOptions;
/**
* The constructor function initializes a binary search tree with an optional comparator function.
* @param {BSTOptions} [options] - An optional object that contains additional configuration options
@ -72,13 +75,12 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
*/
constructor(options?: BSTOptions) {
super(options);
this._root = undefined;
if (options !== undefined) {
const { comparator } = options;
if (comparator !== undefined) {
this._comparator = comparator;
}
if (options) {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
}
this._root = undefined;
}
protected override _root?: N;
@ -102,6 +104,10 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return new BSTNode<V, N>(key, value) as N;
}
override createTree(options?: BSTOptions): TREE {
return new BST<V, N, TREE>({ ...this.options, ...options }) as TREE;
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
* Space Complexity: O(1) - Constant space is used.
@ -215,7 +221,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
keysOrNodes: (BTNKey | N | undefined)[],
data?: (V | undefined)[],
isBalanceAdd = true,
iterationType = this.iterationType
iterationType = this.options.iterationType
): (N | undefined)[] {
// TODO this addMany function is inefficient, it should be optimized
function hasNoUndefined(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
@ -310,7 +316,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* 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: BTNKey | N | undefined = this.root, iterationType = this.iterationType): BTNKey {
lastKey(beginRoot: BTNKey | N | undefined = this.root, iterationType = this.options.iterationType): BTNKey {
if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0;
else return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
@ -406,7 +412,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
callback: C = this._defaultOneParamCallback as C,
onlyOne = false,
beginRoot: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N[] {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
@ -487,7 +493,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
callback: C = this._defaultOneParamCallback as C,
lesserOrGreater: CP = CP.lt,
targetNode: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): ReturnType<C>[] {
targetNode = this.ensureNotKey(targetNode);
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -550,7 +556,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* values:
* @returns The function `perfectlyBalance` returns a boolean value.
*/
perfectlyBalance(iterationType = this.iterationType): boolean {
perfectlyBalance(iterationType = this.options.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
this.clear();
@ -602,7 +608,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* to check if the AVL tree is balanced. It can have two possible values:
* @returns a boolean value.
*/
isAVLBalanced(iterationType = this.iterationType): boolean {
isAVLBalanced(iterationType = this.options.iterationType): boolean {
if (!this.root) return true;
let balanced = true;
@ -646,8 +652,6 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return balanced;
}
protected _comparator: BSTComparator = (a, b) => a - b;
protected _setRoot(v: N | undefined) {
if (v) {
v.parent = undefined;
@ -664,7 +668,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* than), CP.lt (less than), or CP.eq (equal).
*/
protected _compare(a: BTNKey, b: BTNKey): CP {
const compared = this._comparator(a, b);
const compared = this.options.comparator!(a, b);
if (compared > 0) return CP.gt;
else if (compared < 0) return CP.lt;
else return CP.eq;

View file

@ -13,6 +13,7 @@ import {
IterationType,
RBTNColor,
RBTreeOptions,
RedBlackTreeNested,
RedBlackTreeNodeNested
} from '../../types';
import { BST, BSTNode } from './bst';
@ -38,10 +39,11 @@ export class RedBlackTreeNode<V = any, N extends RedBlackTreeNode<V, N> = RedBla
* 4. Red nodes must have black children.
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
*/
export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNode<V, RedBlackTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N> {
export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNode<V, RedBlackTreeNodeNested<V>>, TREE extends RedBlackTree<V, N, TREE> = RedBlackTree<V, N, RedBlackTreeNested<V, N>>>
extends BST<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
Sentinel: N = new RedBlackTreeNode<V>(NaN) as unknown as N;
override options: RBTreeOptions;
/**
* The constructor function initializes a Red-Black Tree with an optional set of options.
@ -50,6 +52,11 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
*/
constructor(options?: RBTreeOptions) {
super(options);
if (options) {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
}
this._root = this.Sentinel;
}
@ -65,6 +72,14 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
return this._size;
}
override createNode(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK): N {
return new RedBlackTreeNode<V, N>(key, value, color) as N;
}
override createTree(options?: RBTreeOptions): TREE {
return new RedBlackTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
@ -139,10 +154,6 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
this._size++;
}
override createNode(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK): N {
return new RedBlackTreeNode<V, N>(key, value, color) as N;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
@ -279,7 +290,7 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
identifier: ReturnType<C> | undefined,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
iterationType = this.options.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
beginRoot = this.ensureNotKey(beginRoot);

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import type { BTNKey, TreeMultimapNodeNested, TreeMultimapOptions } from '../../types';
import { BiTreeDeleteResult, BTNCallback, CP, FamilyPosition, IterationType } from '../../types';
import { BiTreeDeleteResult, BTNCallback, CP, FamilyPosition, IterationType, TreeMultimapNested } from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
@ -35,17 +35,26 @@ 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<V = any, N extends TreeMultimapNode<V, N> = TreeMultimapNode<V, TreeMultimapNodeNested<V>>>
extends AVLTree<V, N>
implements IBinaryTree<V, N> {
export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultimapNode<V, TreeMultimapNodeNested<V>>,
TREE extends TreeMultimap<V, N, TREE> = TreeMultimap<V, N, TreeMultimapNested<V, N>>>
extends AVLTree<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
override options: TreeMultimapOptions;
/**
* The constructor function for a TreeMultimap class in TypeScript, which extends another class and sets an option to
* merge duplicated values.
* @param {TreeMultimapOptions} [options] - An optional object that contains additional configuration options for the
* TreeMultimap.
*/
constructor(options?: TreeMultimapOptions) {
constructor(options: TreeMultimapOptions = { iterationType: IterationType.ITERATIVE }) {
super(options);
if (options) {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
}
}
private _count = 0;
@ -67,6 +76,10 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
return new TreeMultimapNode(key, value, count) as N;
}
override createTree(options?: TreeMultimapOptions): TREE {
return new TreeMultimap<V, N, TREE>({ ...this.options, ...options }) as TREE;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
@ -210,7 +223,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* values:
* @returns a boolean value.
*/
override perfectlyBalance(iterationType = this.iterationType): boolean {
override perfectlyBalance(iterationType = this.options.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
if (sorted.length < 1) return false;

View file

@ -1,7 +1,7 @@
import { BinaryTreeNode } from '../data-structures';
import { BinaryTreeNodeNested, BiTreeDeleteResult, BTNCallback, BTNKey } from '../types';
import { BinaryTree, BinaryTreeNode } from '../data-structures';
import { BinaryTreeNested, BinaryTreeNodeNested, BiTreeDeleteResult, BTNCallback, BTNKey } from '../types';
export interface IBinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNodeNested<V>> {
export interface IBinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNodeNested<V>, TREE extends BinaryTree<V, N, TREE> = BinaryTreeNested<V, N>> {
createNode(key: BTNKey, value?: N['value']): N;
add(keyOrNode: BTNKey | N | null, value?: N['value']): N | null | undefined;

View file

@ -20,4 +20,4 @@ export interface IterableWithLength<T> extends Iterable<T> {
export type IterableWithSizeOrLength<T> = IterableWithSize<T> | IterableWithLength<T>
export type BinaryTreePrintOptions = {isShowUndefined?: boolean, isShowNull?: boolean, isShowRedBlackNIL?: boolean}
export type BinaryTreePrintOptions = { isShowUndefined?: boolean, isShowNull?: boolean, isShowRedBlackNIL?: boolean }

View file

@ -1,5 +1,9 @@
import { AVLTreeNode } from '../../../data-structures';
import { AVLTree, AVLTreeNode } from '../../../data-structures';
import { BSTOptions } from './bst';
export type AVLTreeNodeNested<T> = AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, AVLTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type AVLTreeNested<T, N extends AVLTreeNode<T, N>> = AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, AVLTree<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type AVLTreeOptions = BSTOptions & {};

View file

@ -1,4 +1,4 @@
import { BinaryTreeNode } from '../../../data-structures';
import { BinaryTree, BinaryTreeNode } from '../../../data-structures';
/**
* Enum representing different loop types.
@ -28,6 +28,8 @@ export type BiTreeDeleteResult<N> = { deleted: N | null | undefined; needBalance
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeNested<T, N extends BinaryTreeNode<T, N>> = BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, BinaryTree<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeOptions = { iterationType?: IterationType }
export type NodeDisplayLayout = [string[], number, number, number];

View file

@ -1,4 +1,4 @@
import { BSTNode } from '../../../data-structures';
import { BST, BSTNode } from '../../../data-structures';
import type { BinaryTreeOptions, BTNKey } from './binary-tree';
export type BSTComparator = (a: BTNKey, b: BTNKey) => number;
@ -6,6 +6,8 @@ export type BSTComparator = (a: BTNKey, b: BTNKey) => number;
// prettier-ignore
export type BSTNodeNested<T> = BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BSTNested<T, N extends BSTNode<T, N>> = BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, BST<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BSTOptions = BinaryTreeOptions & {
comparator?: BSTComparator,
}

View file

@ -1,8 +1,10 @@
import { RedBlackTreeNode } from '../../../data-structures';
import { RedBlackTree, RedBlackTreeNode } from '../../../data-structures';
import { BSTOptions } from "./bst";
export enum RBTNColor { RED = 1, BLACK = 0}
export type RedBlackTreeNodeNested<T> = RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RedBlackTreeNested<T, N extends RedBlackTreeNode<T, N>> = RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, RedBlackTree<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RBTreeOptions = BSTOptions & {};

View file

@ -1,6 +1,8 @@
import { TreeMultimapNode } from '../../../data-structures';
import { TreeMultimap, TreeMultimapNode } from '../../../data-structures';
import { AVLTreeOptions } from './avl-tree';
export type TreeMultimapNodeNested<T> = TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultimapNested<T, N extends TreeMultimapNode<T, N>> = TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultimapOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeByKey'> & {}

View file

@ -3,8 +3,8 @@
<head>
<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="../../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>-->
@ -38,7 +38,7 @@
last = queue.dequeue();
}
console.log((performance.now() - startTime).toFixed(2) ,`Queue ${n.toLocaleString()} dequeue `);
console.log((performance.now() - startTime).toFixed(2), `Queue ${n.toLocaleString()} dequeue `);
} catch (e) {
console.error(e);
@ -69,7 +69,7 @@
tree.addMany([1, 6, 9, 8, 5, 2, 3, 4, 7])
tree.add(10);
console.log(tree.isPerfectlyBalanced(), `tree.isPerfectlyBalanced()`);
tree.print(undefined, {isShowUndefined: true});
tree.print(undefined, { isShowUndefined: true });
const node3 = tree.getNode(3);
if (node3) node3.right = tree.createNode(1);
@ -79,7 +79,7 @@
tree.clear();
tree.addMany([1, null, 2, null, 3, null, 4, null, 5, null, 6, null]);
console.log(tree.isPerfectlyBalanced(), `tree.isPerfectlyBalanced()`);
tree.print(undefined, {isShowNull: true});
tree.print(undefined, { isShowNull: true });
} catch (e) {
console.error(e);
}
@ -95,12 +95,12 @@
for (let i = 0; i < n; i++) {
rbTree.add(i, i);
}
console.log(( performance.now() - tS).toFixed(2), `RedBlackTree ${n.toLocaleString()} add`);
console.log((performance.now() - tS).toFixed(2), `RedBlackTree ${n.toLocaleString()} add`);
console.log(`rbTree.size`, rbTree.size);
for (let i = 0; i < n - 20; i++) {
rbTree.delete(i)
}
rbTree.print(rbTree.root,{isShowRedBlackNIL: true});
rbTree.print(rbTree.root, { isShowRedBlackNIL: true });
const cS = performance.now();
for (let i = 1; i < 100000; i++) {
cRBTree.setElement(i, i);
@ -125,7 +125,7 @@
for (let i = 0; i < n; i++) {
pq.pop();
}
console.log(( performance.now() - tS).toFixed(2), `PriorityQueue ${n.toLocaleString()} add`);
console.log((performance.now() - tS).toFixed(2), `PriorityQueue ${n.toLocaleString()} add`);
console.log(pq.size, `pq.size`);
const cS = performance.now();
const cpq = new CPriorityQueue();

View file

@ -41,4 +41,11 @@ suite
}
});
suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & iterator`, () => {
rbTree.clear();
for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]);
const entries = [...rbTree];
return entries.length === HUNDRED_THOUSAND
});
export { suite };

View file

@ -1,4 +1,4 @@
import { AVLTree, AVLTreeNode, CP, IterationType } from '../../../../src';
import { AVLTree, AVLTreeNode, BinaryTreeNode, BSTNode, CP, IterationType } from '../../../../src';
describe('AVL Tree Test', () => {
it('should perform various operations on a AVL Tree', () => {
@ -286,3 +286,59 @@ describe('AVLTree', () => {
});
});
});
describe('AVLTree iterative methods test', () => {
let avl: AVLTree<string>;
beforeEach(() => {
avl = new AVLTree();
avl.add(1, 'a');
avl.add(2, 'b');
avl.add(3, 'c');
});
test('The node obtained by get Node should match the node type', () => {
const node3 = avl.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(AVLTreeNode);
});
test('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
avl.forEach((entry) => {
mockCallback(entry);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0][0]).toEqual([1, 'a']);
expect(mockCallback.mock.calls[1][0]).toEqual([2, 'b']);
expect(mockCallback.mock.calls[2][0]).toEqual([3, 'c']);
});
test('filter should return a new tree with filtered elements', () => {
const filteredTree = avl.filter(([key]) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([[2, 'b'], [3, 'c']]);
});
test('map should return a new tree with modified elements', () => {
const mappedTree = avl.map(([key]) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([[1, '2'], [2, '4'], [3, '6']]);
});
test('reduce should accumulate values', () => {
const sum = avl.reduce((acc, [key]) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of avl) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]);
});
});

View file

@ -189,9 +189,9 @@ describe('BinaryTree', () => {
tree.add(4);
tree.add(2);
expect(tree.getHeight()).toBe(1);
tree.iterationType = IterationType.RECURSIVE;
tree.options.iterationType = IterationType.RECURSIVE;
expect(tree.getHeight()).toBe(1);
tree.iterationType = IterationType.ITERATIVE;
tree.options.iterationType = IterationType.ITERATIVE;
tree.add(6);
tree.add(1);
@ -541,11 +541,11 @@ describe('BinaryTree', () => {
tree.add(3, 'B');
tree.add(7, 'C');
tree.iterationType = IterationType.ITERATIVE;
expect([...tree]).toEqual([3, 5, 7]);
tree.iterationType = IterationType.RECURSIVE;
expect([...tree]).toEqual([3, 5, 7]);
tree.iterationType = IterationType.ITERATIVE;
tree.options.iterationType = IterationType.ITERATIVE;
expect([...tree]).toEqual([[3, "B"], [5, "A"], [7, "C"]]);
tree.options.iterationType = IterationType.RECURSIVE;
expect([...tree]).toEqual([[3, "B"], [5, "A"], [7, "C"]]);
tree.options.iterationType = IterationType.ITERATIVE;
const result = tree.morris();
expect(result).toEqual([3, 5, 7]);
@ -564,3 +564,58 @@ describe('BinaryTree', () => {
expect(tree.getHeight()).toBe(-1);
});
});
describe('BinaryTree iterative methods test', () => {
let binaryTree: BinaryTree<string>;
beforeEach(() => {
binaryTree = new BinaryTree();
binaryTree.add(1, 'a');
binaryTree.add(2, 'b');
binaryTree.add(3, 'c');
});
test('The node obtained by get Node should match the node type', () => {
const node3 = binaryTree.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
});
test('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
binaryTree.forEach((entry) => {
mockCallback(entry);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0][0]).toEqual([2, 'b']);
expect(mockCallback.mock.calls[1][0]).toEqual([1, 'a']);
expect(mockCallback.mock.calls[2][0]).toEqual([3, 'c']);
});
test('filter should return a new tree with filtered elements', () => {
const filteredTree = binaryTree.filter(([key]) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([[3, 'c'], [2, 'b']]);
});
test('map should return a new tree with modified elements', () => {
const mappedTree = binaryTree.map(([key]) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([[1, '2'], [2, '4'], [3, '6']]);
});
test('reduce should accumulate values', () => {
const sum = binaryTree.reduce((acc, [key]) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of binaryTree) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([[2, 'b'], [1, 'a'], [3, 'c']]);
});
});

View file

@ -1,4 +1,4 @@
import { BST, BSTNode, CP, IterationType } from '../../../../src';
import { BinaryTreeNode, BST, BSTNode, CP, IterationType } from '../../../../src';
import { isDebugTest } from '../../../config';
const isDebug = isDebugTest;
@ -851,3 +851,58 @@ describe('BST Performance test', function () {
]);
});
});
describe('BST iterative methods test', () => {
let bst: BST<string>;
beforeEach(() => {
bst = new BST();
bst.add(1, 'a');
bst.add(2, 'b');
bst.add(3, 'c');
});
test('The node obtained by get Node should match the node type', () => {
const node3 = bst.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
});
test('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
bst.forEach((entry) => {
mockCallback(entry);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0][0]).toEqual([1, 'a']);
expect(mockCallback.mock.calls[1][0]).toEqual([2, 'b']);
expect(mockCallback.mock.calls[2][0]).toEqual([3, 'c']);
});
test('filter should return a new tree with filtered elements', () => {
const filteredTree = bst.filter(([key]) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([[2, 'b'], [3, 'c']]);
});
test('map should return a new tree with modified elements', () => {
const mappedTree = bst.map(([key]) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([[1, '2'], [2, '4'], [3, '6']]);
});
test('reduce should accumulate values', () => {
const sum = bst.reduce((acc, [key]) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of bst) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]);
});
});

View file

@ -1,4 +1,4 @@
import { IterationType, RBTNColor, RedBlackTree, RedBlackTreeNode } from '../../../../src';
import { BinaryTreeNode, BSTNode, IterationType, RBTNColor, RedBlackTree, RedBlackTreeNode } from '../../../../src';
import { getRandomInt, getRandomIntArray, magnitude } from '../../../utils';
import { isDebugTest } from '../../../config';
import { OrderedMap } from 'js-sdsl';
@ -490,7 +490,7 @@ describe('RedBlackTree', () => {
it('duplicates', () => {
tree.addMany([9, 8, 7, 8, 8, 8, 2, 3, 6, 5, 5, 4]);
tree.print();
isDebug && tree.print();
expect(tree.size).toBe(8);
expect(tree.isBST()).toBe(true);
@ -505,3 +505,59 @@ describe('RedBlackTree', () => {
expect(tree.isAVLBalanced()).toBe(false);
})
});
describe('RedBlackTree iterative methods test', () => {
let rbTree: RedBlackTree<string>;
beforeEach(() => {
rbTree = new RedBlackTree();
rbTree.add(1, 'a');
rbTree.add(2, 'b');
rbTree.add(3, 'c');
});
test('The node obtained by get Node should match the node type', () => {
const node3 = rbTree.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(RedBlackTreeNode);
});
test('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
rbTree.forEach((entry) => {
mockCallback(entry);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0][0]).toEqual([1, 'a']);
expect(mockCallback.mock.calls[1][0]).toEqual([2, 'b']);
expect(mockCallback.mock.calls[2][0]).toEqual([3, 'c']);
});
test('filter should return a new tree with filtered elements', () => {
const filteredTree = rbTree.filter(([key]) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([[2, 'b'], [3, 'c']]);
});
test('map should return a new tree with modified elements', () => {
const mappedTree = rbTree.map(([key]) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([[1, '2'], [2, '4'], [3, '6']]);
});
test('reduce should accumulate values', () => {
const sum = rbTree.reduce((acc, [key]) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of rbTree) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]);
});
});