feat: Add an 'elements' parameter to the constructors of all binary tree data structures to accept Iterable types.

This commit is contained in:
Revone 2023-11-23 21:43:45 +08:00
parent 8f9eb82bfd
commit 4930f87bcd
17 changed files with 372 additions and 237 deletions

View file

@ -7,7 +7,7 @@
*/
import { BST, BSTNode } from './bst';
import type { AVLTreeNested, AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey } from '../../types';
import { BTNCallback, IterationType } from '../../types';
import { BTNCallback, IterableEntriesOrKeys } from '../../types';
import { IBinaryTree } from '../../interfaces';
export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNested<V>> extends BSTNode<V, N> {
@ -23,21 +23,15 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
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
* constructor of the AVLTree class. It allows you to customize the behavior of the AVL tree by providing different
* options.
*/
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 };
}
constructor(elements?: IterableEntriesOrKeys<V>, options?: Partial<AVLTreeOptions>) {
super([], options);
if (elements) this.init(elements);
}
/**
@ -54,14 +48,12 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
}
override createTree(options?: AVLTreeOptions): TREE {
return new AVLTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
return new AVLTree<V, N, TREE>([], {
iterationType: this.iterationType,
comparator: this.comparator, ...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.
*/
/**
* 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.
@ -82,7 +74,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete method of the superclass (BST) has logarithmic time complexity.
* 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.
*/
@ -115,6 +107,24 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
return deletedResults;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete 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.
*/
init(elements: IterableEntriesOrKeys<V>): void {
if (elements) {
for (const entryOrKey of elements) {
if (Array.isArray(entryOrKey)) {
const [key, value] = entryOrKey;
this.add(key, value);
} else {
this.add(entryOrKey);
}
}
}
}
/**
* The `_swap` function swaps the key, value, and height properties between two nodes in a binary
* tree.

View file

@ -13,6 +13,7 @@ import {
BiTreeDeleteResult,
DFSOrderPattern,
FamilyPosition,
IterableEntriesOrKeys,
IterationType,
NodeDisplayLayout
} from '../../types';
@ -118,20 +119,24 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
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;
iterationType = IterationType.ITERATIVE
/**
* Creates a new instance of BinaryTree.
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
*/
constructor(options?: BinaryTreeOptions) {
constructor(elements?: IterableEntriesOrKeys<V>, options?: Partial<BinaryTreeOptions>) {
if (options) {
this.options = { iterationType: IterationType.ITERATIVE, ...options }
} else {
this.options = { iterationType: IterationType.ITERATIVE };
const { iterationType } = options;
if (iterationType) {
this.iterationType = iterationType;
}
}
this._size = 0;
if (elements) this.init(elements);
}
protected _root?: N | null;
@ -162,16 +167,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;
createTree(options?: Partial<BinaryTreeOptions>): TREE {
return new BinaryTree<V, N, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
* Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
@ -228,8 +227,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
/**
* Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
* Time Complexity: O(n)
* Space Complexity: O(1)
* Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
*/
/**
@ -284,17 +284,17 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return keysOrNodes.length === this.addMany(keysOrNodes, values).length;
}
/**
* Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
* Space Complexity: O(1)
*/
delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BiTreeDeleteResult<N>[];
delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BiTreeDeleteResult<N>[];
delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BiTreeDeleteResult<N>[];
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
@ -394,8 +394,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
* Best Case - O(log n) (when using recursive iterationType), Worst Case - O(n) (when using iterative iterationType)
* Space Complexity: O(1)
*/
/**
@ -412,7 +411,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.options.iterationType): number {
getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
@ -461,7 +460,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.options.iterationType): number {
getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
@ -507,6 +506,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
* Best Case - O(log n) (when using recursive iterationType), Worst Case - O(n) (when using iterative iterationType)
*/
/**
@ -524,6 +524,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
getNodes<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
@ -548,11 +553,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType?: IterationType
): N[];
/**
* Time Complexity: O(n)
* Space Complexity: O(log n).
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(log n).
@ -583,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.options.iterationType
iterationType = this.iterationType
): N[] {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -622,6 +622,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(log n).
*/
has<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
@ -643,11 +648,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType?: IterationType
): boolean;
/**
* Time Complexity: O(n)
* Space Complexity: O(log n).
*/
/**
* Time Complexity: O(n)
*
@ -672,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.options.iterationType
iterationType = this.iterationType
): boolean {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -680,6 +680,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(log n).
*/
getNode<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
@ -701,11 +706,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType?: IterationType
): N | null | undefined;
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
@ -731,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.options.iterationType
iterationType = this.iterationType
): N | null | undefined {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -783,6 +783,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
}
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node
* key, otherwise it returns the key itself.
@ -819,11 +824,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType?: IterationType
): V | undefined;
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
@ -850,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.options.iterationType
iterationType = this.iterationType
): V | undefined {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
@ -858,6 +858,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
/**
* Clear the binary tree, removing all nodes.
*/
@ -874,11 +879,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.size === 0;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
@ -912,7 +912,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* Space Complexity: O(log n)
*/
/**
@ -931,7 +931,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getLeftMost(
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.options.iterationType
iterationType = this.iterationType
): N | null | undefined {
beginRoot = this.ensureNotKey(beginRoot);
@ -977,7 +977,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getRightMost(
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.options.iterationType
iterationType = this.iterationType
): N | null | undefined {
// TODO support get right most by passing key in
beginRoot = this.ensureNotKey(beginRoot);
@ -1002,7 +1002,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
/**
* Time Complexity: O(n)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
@ -1018,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.options.iterationType): boolean {
isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
// TODO there is a bug
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return true;
@ -1065,11 +1065,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* expected to be
* @returns a boolean value.
*/
isBST(iterationType = this.options.iterationType): boolean {
isBST(iterationType = this.iterationType): boolean {
if (this.root === null) return true;
return this.isSubtreeBST(this.root, iterationType);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/
subTreeTraverse<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: BTNKey | N | null | undefined,
@ -1091,11 +1096,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
includeNull?: true
): ReturnType<C>[];
/**
* Time complexity: O(n)
* Space complexity: O(log n)
*/
/**
* Time complexity: O(n)
* Space complexity: O(log n)
@ -1121,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.options.iterationType,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1164,6 +1164,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
/**
* Time complexity: O(n)
* Space complexity: O(log n)
*/
/**
* The function checks if a given node is a real node by verifying if it is an instance of
* BinaryTreeNode and its key is not NaN.
@ -1226,11 +1231,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
includeNull?: true
): ReturnType<C>[];
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
/**
* Time complexity: O(n)
* Space complexity: O(n)
@ -1349,6 +1349,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
bfs<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: BTNKey | N | null | undefined,
@ -1370,11 +1375,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
includeNull?: true
): ReturnType<C>[];
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
/**
* Time complexity: O(n)
* Space complexity: O(n)
@ -1399,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.options.iterationType,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1450,6 +1450,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
listLevels<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: BTNKey | N | null | undefined,
@ -1471,11 +1476,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
includeNull?: true
): ReturnType<C>[][];
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
/**
* Time complexity: O(n)
* Space complexity: O(n)
@ -1500,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.options.iterationType,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[][] {
beginRoot = this.ensureNotKey(beginRoot);
@ -1544,6 +1544,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return levelsNodes;
}
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
getPredecessor(node: N): N;
/**
@ -1591,11 +1596,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return y;
}
/**
* Time complexity: O(n)
* Space complexity: O(1)
*/
/**
* Time complexity: O(n)
* Space complexity: O(1)
@ -1700,6 +1700,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
/**
* Time complexity: O(n)
* Space complexity: O(1)
*/
/**
* The `forEach` function iterates over each entry in a tree and calls a callback function with the
* entry and the tree as arguments.
@ -1730,15 +1735,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
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: this) => NV) {
// const newTree = this.createTree();
// for (const [key, value] of this) {
// newTree.add(key, callback([key, value], this));
// }
// return newTree;
// }
/**
* The `map` function creates a new tree by applying a callback function to each entry in the current
* tree.
@ -1753,6 +1749,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
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: this) => NV) {
// const newTree = this.createTree();
// for (const [key, value] of this) {
// newTree.add(key, callback([key, value], this));
// }
// return newTree;
// }
/**
* The `reduce` function iterates over the entries of a tree and applies a callback function to each
* entry, accumulating a single value.
@ -1773,7 +1778,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
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.
@ -1786,7 +1790,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* [Symbol.iterator](node = this.root): Generator<[BTNKey, V | undefined], void, undefined> {
if (!node) return;
if (this.options.iterationType === IterationType.ITERATIVE) {
if (this.iterationType === IterationType.ITERATIVE) {
const stack: (N | null | undefined)[] = [];
let current: N | null | undefined = node;
@ -1843,6 +1847,19 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
display(beginRoot);
}
init(elements: IterableEntriesOrKeys<V>): void {
if (elements) {
for (const entryOrKey of elements) {
if (Array.isArray(entryOrKey)) {
const [key, value] = entryOrKey;
this.add(key, value);
} else {
this.add(entryOrKey);
}
}
}
}
protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];

View file

@ -5,8 +5,8 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { BSTNested, BSTNodeNested, BSTOptions, BTNCallback, BTNKey } from '../../types';
import { CP, IterationType } from '../../types';
import type { BSTNested, BSTNodeNested, BSTOptions, BTNCallback, BTNKey, Comparator } from '../../types';
import { CP, IterableEntriesOrKeys, IterationType } from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
import { IBinaryTree } from '../../interfaces';
import { Queue } from '../queue';
@ -66,21 +66,23 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
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
* for the binary search tree.
*/
constructor(options?: BSTOptions) {
super(options);
constructor(elements?: IterableEntriesOrKeys<V>, options?: Partial<BSTOptions>) {
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 };
const { comparator } = options;
if (comparator) {
this.comparator = comparator;
}
}
this._root = undefined;
if (elements) this.init(elements);
}
protected override _root?: N;
@ -92,6 +94,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return this._root;
}
comparator: Comparator<BTNKey> = (a, b) => a - b
/**
* The function creates a new binary search tree node with the given key and value.
* @param {BTNKey} key - The key parameter is the key value that will be associated with
@ -104,15 +108,13 @@ 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;
override createTree(options?: Partial<BSTOptions>): TREE {
return new BST<V, N, TREE>([], {
iterationType: this.iterationType,
comparator: this.comparator, ...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.
*/
/**
* 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.
@ -193,8 +195,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
/**
* Time Complexity: O(n log n) - Adding each element individually in a balanced tree.
* Space Complexity: O(n) - Additional space is required for the sorted array.
* 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.
*/
/**
@ -221,7 +223,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.options.iterationType
iterationType = this.iterationType
): (N | undefined)[] {
// TODO this addMany function is inefficient, it should be optimized
function hasNoUndefined(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
@ -297,8 +299,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree.
* Space Complexity: O(1) - Constant space is used.
* Time Complexity: O(n log n) - Adding each element individually in a balanced tree.
* Space Complexity: O(n) - Additional space is required for the sorted array.
*/
/**
@ -316,7 +318,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.options.iterationType): BTNKey {
lastKey(beginRoot: BTNKey | N | undefined = this.root, iterationType = this.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;
@ -324,7 +326,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
/**
* Time Complexity: O(log n) - Average case for a balanced tree.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
* Space Complexity: O(1) - Constant space is used.
*/
/**
@ -366,6 +368,11 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
*/
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a node key,
* otherwise it returns the key itself.
@ -379,11 +386,6 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
*/
/**
* Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
@ -412,7 +414,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.options.iterationType
iterationType = this.iterationType
): N[] {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
@ -493,7 +495,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.options.iterationType
iterationType = this.iterationType
): ReturnType<C>[] {
targetNode = this.ensureNotKey(targetNode);
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -531,18 +533,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
/**
* Balancing Adjustment:
* Perfectly Balanced Binary Tree: Since the balance of a perfectly balanced binary tree is already fixed, no additional balancing adjustment is needed. Any insertion or deletion operation will disrupt the perfect balance, often requiring a complete reconstruction of the tree.
* AVL Tree: After insertion or deletion operations, an AVL tree performs rotation adjustments based on the balance factor of nodes to restore the tree's balance. These rotations can be left rotations, right rotations, left-right rotations, or right-left rotations, performed as needed.
*
* Use Cases and Efficiency:
* Perfectly Balanced Binary Tree: Perfectly balanced binary trees are typically used in specific scenarios such as complete binary heaps in heap sort or certain types of Huffman trees. However, they are not suitable for dynamic operations requiring frequent insertions and deletions, as these operations often necessitate full tree reconstruction.
* AVL Tree: AVL trees are well-suited for scenarios involving frequent searching, insertion, and deletion operations. Through rotation adjustments, AVL trees maintain their balance, ensuring average and worst-case time complexity of O(log n).
*/
/**
* Time Complexity: O(n) - Building a balanced tree from a sorted array.
* Space Complexity: O(n) - Additional space is required for the sorted array.
* Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
*/
/**
@ -556,7 +548,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.options.iterationType): boolean {
perfectlyBalance(iterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
this.clear();
@ -595,8 +587,18 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
/**
* Time Complexity: O(n) - Visiting each node once.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
* Balancing Adjustment:
* Perfectly Balanced Binary Tree: Since the balance of a perfectly balanced binary tree is already fixed, no additional balancing adjustment is needed. Any insertion or deletion operation will disrupt the perfect balance, often requiring a complete reconstruction of the tree.
* AVL Tree: After insertion or deletion operations, an AVL tree performs rotation adjustments based on the balance factor of nodes to restore the tree's balance. These rotations can be left rotations, right rotations, left-right rotations, or right-left rotations, performed as needed.
*
* Use Cases and Efficiency:
* Perfectly Balanced Binary Tree: Perfectly balanced binary trees are typically used in specific scenarios such as complete binary heaps in heap sort or certain types of Huffman trees. However, they are not suitable for dynamic operations requiring frequent insertions and deletions, as these operations often necessitate full tree reconstruction.
* AVL Tree: AVL trees are well-suited for scenarios involving frequent searching, insertion, and deletion operations. Through rotation adjustments, AVL trees maintain their balance, ensuring average and worst-case time complexity of O(log n).
*/
/**
* Time Complexity: O(n) - Building a balanced tree from a sorted array.
* Space Complexity: O(n) - Additional space is required for the sorted array.
*/
/**
@ -608,7 +610,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.options.iterationType): boolean {
isAVLBalanced(iterationType = this.iterationType): boolean {
if (!this.root) return true;
let balanced = true;
@ -652,6 +654,24 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return balanced;
}
/**
* Time Complexity: O(n) - Visiting each node once.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
*/
init(elements: IterableEntriesOrKeys<V>): void {
if (elements) {
for (const entryOrKey of elements) {
if (Array.isArray(entryOrKey)) {
const [key, value] = entryOrKey;
this.add(key, value);
} else {
this.add(entryOrKey);
}
}
}
}
protected _setRoot(v: N | undefined) {
if (v) {
v.parent = undefined;
@ -668,7 +688,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.options.comparator!(a, b);
const compared = this.comparator(a, b);
if (compared > 0) return CP.gt;
else if (compared < 0) return CP.lt;
else return CP.eq;

View file

@ -10,6 +10,7 @@ import {
BiTreeDeleteResult,
BTNCallback,
BTNKey,
IterableEntriesOrKeys,
IterationType,
RBTNColor,
RBTreeOptions,
@ -43,21 +44,18 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
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.
* @param {RBTreeOptions} [options] - The `options` parameter is an optional object that can be
* passed to the constructor. It is used to configure the RBTree object with specific options.
*/
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 };
}
constructor(elements?: IterableEntriesOrKeys<V>, options?: Partial<RBTreeOptions>) {
super([], options);
this._root = this.Sentinel;
if (elements) this.init(elements);
}
protected _root: N;
@ -77,14 +75,12 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
}
override createTree(options?: RBTreeOptions): TREE {
return new RedBlackTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
return new RedBlackTree<V, N, TREE>([], {
iterationType: this.iterationType,
comparator: this.comparator, ...options
}) as TREE;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
@ -235,6 +231,11 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
return ans;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
override isRealNode(node: N | undefined): node is N {
return node !== this.Sentinel && node !== undefined;
}
@ -260,11 +261,6 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
iterationType?: IterationType
): N | undefined;
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
@ -290,7 +286,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.options.iterationType
iterationType = this.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
beginRoot = this.ensureNotKey(beginRoot);
@ -351,11 +347,29 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
return y!;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
override clear() {
this._root = this.Sentinel;
this._size = 0;
}
init(elements: IterableEntriesOrKeys<V>): void {
if (elements) {
for (const entryOrKey of elements) {
if (Array.isArray(entryOrKey)) {
const [key, value] = entryOrKey;
this.add(key, value);
} else {
this.add(entryOrKey);
}
}
}
}
protected override _setRoot(v: N) {
if (v) {
v.parent = undefined;

View file

@ -6,7 +6,15 @@
* @license MIT License
*/
import type { BTNKey, TreeMultimapNodeNested, TreeMultimapOptions } from '../../types';
import { BiTreeDeleteResult, BTNCallback, CP, FamilyPosition, IterationType, TreeMultimapNested } from '../../types';
import {
BiTreeDeleteResult,
BTNCallback,
CP,
FamilyPosition,
IterableEntriesOrKeys,
IterationType,
TreeMultimapNested
} from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
@ -40,21 +48,15 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
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 = { 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 };
}
constructor(elements?: IterableEntriesOrKeys<V>, options?: Partial<TreeMultimapOptions>) {
super([], options);
if (elements) this.init(elements);
}
private _count = 0;
@ -77,14 +79,12 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
override createTree(options?: TreeMultimapOptions): TREE {
return new TreeMultimap<V, N, TREE>({ ...this.options, ...options }) as TREE;
return new TreeMultimap<V, N, TREE>([], {
iterationType: this.iterationType,
comparator: this.comparator, ...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.
*/
/**
* 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.
@ -169,8 +169,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* Time Complexity: O(1) - constant time, as it performs basic pointer assignments.
* Space Complexity: O(1) - constant space, as it only uses a constant amount of memory.
* 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.
*/
/**
@ -208,8 +208,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* Time Complexity: O(k log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
* Time Complexity: O(1) - constant time, as it performs basic pointer assignments.
* Space Complexity: O(1) - constant space, as it only uses a constant amount of memory.
*/
/**
@ -223,7 +223,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* values:
* @returns a boolean value.
*/
override perfectlyBalance(iterationType = this.options.iterationType): boolean {
override perfectlyBalance(iterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
if (sorted.length < 1) return false;
@ -262,8 +262,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* Time Complexity: O(n log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node.
* Space Complexity: O(n) - linear space, as it creates an array to store the sorted nodes.
* Time Complexity: O(k log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
@ -346,8 +346,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete 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.
* Time Complexity: O(n log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node.
* Space Complexity: O(n) - linear space, as it creates an array to store the sorted nodes.
*/
/**
@ -358,6 +358,24 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
this._count = 0;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete 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.
*/
init(elements: IterableEntriesOrKeys<V>): void {
if (elements) {
for (const entryOrKey of elements) {
if (Array.isArray(entryOrKey)) {
const [key, value] = entryOrKey;
this.add(key, value);
} else {
this.add(entryOrKey);
}
}
}
}
/**
* Time Complexity: O(1) - constant time, as it performs basic pointer assignments.
* Space Complexity: O(1) - constant space, as it only uses a constant amount of memory.

View file

@ -1,9 +1,21 @@
import { BinaryTree, BinaryTreeNode } from '../data-structures';
import { BinaryTreeNested, BinaryTreeNodeNested, BiTreeDeleteResult, BTNCallback, BTNKey } from '../types';
import {
BinaryTreeNested,
BinaryTreeNodeNested,
BinaryTreeOptions,
BiTreeDeleteResult,
BTNCallback,
BTNKey,
IterableEntriesOrKeys
} from '../types';
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;
createTree(options?: Partial<BinaryTreeOptions>): TREE;
init(elements: IterableEntriesOrKeys<V>): void;
add(keyOrNode: BTNKey | N | null, value?: N['value']): N | null | undefined;
delete<C extends BTNCallback<N>>(identifier: ReturnType<C> | null, callback: C): BiTreeDeleteResult<N>[];

View file

@ -1,3 +1,5 @@
import { BTNKey } from "./data-structures";
export type Comparator<T> = (a: T, b: T) => number;
export type DFSOrderPattern = 'pre' | 'in' | 'post';
@ -20,4 +22,6 @@ 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 }
export type IterableEntriesOrKeys<T> = Iterable<[BTNKey, T | undefined] | BTNKey>

View file

@ -30,6 +30,6 @@ export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, Binary
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 BinaryTreeOptions = { iterationType: IterationType }
export type NodeDisplayLayout = [string[], number, number, number];

View file

@ -1,7 +1,6 @@
import { BST, BSTNode } from '../../../data-structures';
import type { BinaryTreeOptions, BTNKey } from './binary-tree';
export type BSTComparator = (a: BTNKey, b: BTNKey) => number;
import { Comparator } from "../../common";
// 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>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@ -9,5 +8,5 @@ export type BSTNodeNested<T> = BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNo
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,
comparator: Comparator<BTNKey>
}

View file

@ -23,7 +23,7 @@ const arrHundredThousand = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSA
suite
.add(`SRC PQ ${TEN_THOUSAND.toLocaleString()} add`, () => {
const pq = new SRCPriorityQueue<number>({ comparator: (a, b) => b - a });
const pq = new SRCPriorityQueue<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i);
})
.add(`CJS PQ ${TEN_THOUSAND.toLocaleString()} add`, () => {
@ -47,7 +47,7 @@ if (isCompetitor) {
suite
.add(`SRC PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => {
const pq = new SRCPriorityQueue<number>({ comparator: (a, b) => b - a });
const pq = new SRCPriorityQueue<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i);
for (let i = 0; i < TEN_THOUSAND; i++) pq.pop();

View file

@ -7,7 +7,7 @@ const { HUNDRED_THOUSAND, TEN_THOUSAND } = magnitude;
suite
.add(`${HUNDRED_THOUSAND.toLocaleString()} add & pop`, () => {
const heap = new Heap<number>({ comparator: (a, b) => b - a });
const heap = new Heap<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) {
heap.add(i);
@ -18,7 +18,7 @@ suite
}
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add & dfs`, () => {
const heap = new Heap<number>({ comparator: (a, b) => b - a });
const heap = new Heap<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) {
heap.add(i);

View file

@ -8,7 +8,7 @@ const suite = new Benchmark.Suite();
const { HUNDRED_THOUSAND } = magnitude;
suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & pop`, () => {
const pq = new PriorityQueue<number>({ comparator: (a, b) => b - a });
const pq = new PriorityQueue<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) {
pq.add(i);

View file

@ -112,7 +112,7 @@ describe('AVL Tree Test', () => {
describe('AVL Tree Test recursively', () => {
it('should perform various operations on a AVL Tree', () => {
const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
const tree = new AVLTree<number>({ iterationType: IterationType.RECURSIVE });
const tree = new AVLTree<number>([], { iterationType: IterationType.RECURSIVE });
for (const i of arr) tree.add(i, i);

View file

@ -189,9 +189,9 @@ describe('BinaryTree', () => {
tree.add(4);
tree.add(2);
expect(tree.getHeight()).toBe(1);
tree.options.iterationType = IterationType.RECURSIVE;
tree.iterationType = IterationType.RECURSIVE;
expect(tree.getHeight()).toBe(1);
tree.options.iterationType = IterationType.ITERATIVE;
tree.iterationType = IterationType.ITERATIVE;
tree.add(6);
tree.add(1);
@ -381,7 +381,7 @@ describe('BinaryTree', () => {
let tree: BinaryTree<string>;
beforeEach(() => {
tree = new BinaryTree<string>({ iterationType: IterationType.RECURSIVE });
tree = new BinaryTree<string>([], { iterationType: IterationType.RECURSIVE });
});
afterEach(() => {
@ -541,11 +541,11 @@ describe('BinaryTree', () => {
tree.add(3, 'B');
tree.add(7, 'C');
tree.options.iterationType = IterationType.ITERATIVE;
tree.iterationType = IterationType.ITERATIVE;
expect([...tree]).toEqual([[3, "B"], [5, "A"], [7, "C"]]);
tree.options.iterationType = IterationType.RECURSIVE;
tree.iterationType = IterationType.RECURSIVE;
expect([...tree]).toEqual([[3, "B"], [5, "A"], [7, "C"]]);
tree.options.iterationType = IterationType.ITERATIVE;
tree.iterationType = IterationType.ITERATIVE;
const result = tree.morris();
expect(result).toEqual([3, 5, 7]);

View file

@ -395,7 +395,7 @@ describe('BST operations test', () => {
describe('BST operations test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST({ iterationType: IterationType.RECURSIVE });
const bst = new BST([], { iterationType: IterationType.RECURSIVE });
expect(bst).toBeInstanceOf(BST);
bst.add(11, 11);
bst.add(3, 3);

View file

@ -245,7 +245,7 @@ describe('TreeMultimap operations test', () => {
describe('TreeMultimap operations test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const treeMultimap = new TreeMultimap({ iterationType: IterationType.RECURSIVE });
const treeMultimap = new TreeMultimap([], { iterationType: IterationType.RECURSIVE });
expect(treeMultimap instanceof TreeMultimap);
treeMultimap.add(11, 11);

View file

@ -1,4 +1,7 @@
import {
AVLTree,
BinaryTree,
BST,
Deque,
DoublyLinkedList,
MaxHeap,
@ -6,54 +9,92 @@ import {
MinHeap,
MinPriorityQueue,
Queue,
RedBlackTree,
SinglyLinkedList,
Stack
Stack,
TreeMultimap
} from '../../src';
import { isDebugTest } from "../config";
const isDebug = isDebugTest;
const orgArr: number[] = [6, 1, 2, 7, 5, 3, 4, 9, 8];
const entries: [number, number][] = [[6, 6], [1, 1], [2, 2], [7, 7], [5, 5], [3, 3], [4, 4], [9, 9], [8, 8]];
describe('conversions', () => {
it('Array to Queue', () => {
const q = new Queue<number>(orgArr);
q.print();
isDebug && q.print();
})
it('Array to Deque', () => {
const dq = new Deque<number>(orgArr);
dq.print();
isDebug && dq.print();
})
it('Array to SinglyLinkedList', () => {
const sl = new SinglyLinkedList<number>(orgArr);
sl.print();
isDebug && sl.print();
})
it('Array to DoublyLinkedList', () => {
const dl = new DoublyLinkedList<number>(orgArr);
dl.print();
isDebug && dl.print();
})
it('Array to Stack', () => {
const stack = new Stack<number>(orgArr);
stack.print();
isDebug && stack.print();
})
it('Array to MinHeap', () => {
const minHeap = new MinHeap<number>(orgArr);
minHeap.print();
isDebug && minHeap.print();
})
it('Array to MaxHeap', () => {
const maxHeap = new MaxHeap<number>(orgArr);
maxHeap.print();
isDebug && maxHeap.print();
})
it('Array to MinPriorityQueue', () => {
const minPQ = new MinPriorityQueue<number>(orgArr);
minPQ.print();
isDebug && minPQ.print();
})
it('Array to MaxPriorityQueue', () => {
const maxPQ = new MaxPriorityQueue<number>(orgArr);
maxPQ.print();
isDebug && maxPQ.print();
})
})
it('Entry Array to BinaryTree', () => {
const biTree = new BinaryTree<number>(entries);
isDebug && biTree.print();
})
it('Entry Array to BST', () => {
const bst = new BST<number>(orgArr);
expect(bst.size).toBe(9)
isDebug && bst.print();
})
it('Entry Array to RedBlackTree', () => {
const rbTree = new RedBlackTree<number>(orgArr);
expect(rbTree.size).toBe(9)
isDebug && rbTree.print();
})
it('Entry Array to AVLTree', () => {
const avl = new AVLTree<number>(orgArr);
expect(avl.size).toBe(9)
isDebug && avl.print();
})
it('Entry Array to TreeMultimap', () => {
const treeMulti = new TreeMultimap<number>(orgArr);
expect(treeMulti.size).toBe(9)
isDebug && treeMulti.print();
})
})