mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2025-01-18 11:14:05 +00:00
style: Utilize the built-in _dfs method across all binary tree data structures to optimize the search method.
feat: The search and rangeSearch methods in binary trees now default to in-order traversal for producing ordered results. docs: Add sample code for AVLTree. Explicitly document method parameter types for all binary tree data structures.
This commit is contained in:
parent
b759eecf59
commit
a008a33a30
|
@ -9,15 +9,15 @@ import type {
|
|||
AVLTreeCounterOptions,
|
||||
BinaryTreeDeleteResult,
|
||||
BSTNOptKeyOrNode,
|
||||
BTNRep,
|
||||
EntryCallback,
|
||||
IterationType,
|
||||
OptNodeOrNull
|
||||
IterationType
|
||||
} from '../../types';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
import { AVLTree, AVLTreeNode } from './avl-tree';
|
||||
|
||||
export class AVLTreeCounterNode<K = any, V = any> extends AVLTreeNode<K, V> {
|
||||
override parent?: AVLTreeCounterNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* The constructor function initializes a BinaryTreeNode object with a key, value, and count.
|
||||
* @param {K} key - The `key` parameter is of type `K` and represents the unique identifier
|
||||
|
@ -33,28 +33,26 @@ export class AVLTreeCounterNode<K = any, V = any> extends AVLTreeNode<K, V> {
|
|||
this.count = count;
|
||||
}
|
||||
|
||||
override parent?: AVLTreeCounterNode<K, V> = undefined;
|
||||
override _left?: AVLTreeCounterNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<AVLTreeCounterNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<AVLTreeCounterNode<K, V>> {
|
||||
override get left(): AVLTreeCounterNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<AVLTreeCounterNode<K, V>>) {
|
||||
override set left(v: AVLTreeCounterNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<AVLTreeCounterNode<K, V>> = undefined;
|
||||
override _right?: AVLTreeCounterNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<AVLTreeCounterNode<K, V>> {
|
||||
override get right(): AVLTreeCounterNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<AVLTreeCounterNode<K, V>>) {
|
||||
override set right(v: AVLTreeCounterNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -78,7 +76,9 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
* `compareValues` functions to define custom comparison logic for keys and values, respectively.
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, AVLTreeCounterNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: AVLTreeCounterOptions<K, V, R>
|
||||
) {
|
||||
super([], options);
|
||||
|
@ -145,12 +145,14 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
|
||||
/**
|
||||
* The function checks if the input is an instance of AVLTreeCounterNode.
|
||||
* @param {BTNRep<K, V, AVLTreeCounterNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, AVLTreeCounterNode<K, V>>`.
|
||||
* @param {K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
||||
* an instance of the `AVLTreeCounterNode` class.
|
||||
*/
|
||||
override isNode(keyNodeOrEntry: BTNRep<K, V, AVLTreeCounterNode<K, V>>): keyNodeOrEntry is AVLTreeCounterNode<K, V> {
|
||||
override isNode(
|
||||
keyNodeOrEntry: K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): keyNodeOrEntry is AVLTreeCounterNode<K, V> {
|
||||
return keyNodeOrEntry instanceof AVLTreeCounterNode;
|
||||
}
|
||||
|
||||
|
@ -160,9 +162,9 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
*
|
||||
* The function overrides the add method of a TypeScript class to add a new node to a data structure
|
||||
* and update the count.
|
||||
* @param {BTNRep<K, V, AVLTreeCounterNode<K, V>>} keyNodeOrEntry - The
|
||||
* @param {K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The
|
||||
* `keyNodeOrEntry` parameter can accept a value of type `R`, which can be any type. It
|
||||
* can also accept a value of type `BTNRep<K, V, AVLTreeCounterNode<K, V>>`, which represents a key, node,
|
||||
* can also accept a value of type `K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`, which represents a key, node,
|
||||
* entry, or raw element
|
||||
* @param {V} [value] - The `value` parameter represents the value associated with the key in the
|
||||
* data structure. It is an optional parameter, so it can be omitted if not needed.
|
||||
|
@ -171,7 +173,11 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
* be added once. However, you can specify a different value for `count` if you want to add
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V, AVLTreeCounterNode<K, V>>, value?: V, count = 1): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V,
|
||||
count = 1
|
||||
): boolean {
|
||||
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value, count);
|
||||
if (newNode === undefined) return false;
|
||||
|
||||
|
@ -189,7 +195,7 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
*
|
||||
* The function overrides the delete method in a binary tree data structure, handling deletion of
|
||||
* nodes and maintaining balance in the tree.
|
||||
* @param {BTNRep<K, V, AVLTreeCounterNode<K, V>>} keyNodeOrEntry - The `predicate`
|
||||
* @param {K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The `predicate`
|
||||
* parameter in the `delete` method is used to specify the condition for deleting a node from the
|
||||
* binary tree. It can be a key, node, or entry that determines which
|
||||
* node(s) should be deleted.
|
||||
|
@ -203,7 +209,7 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
* deleted node and whether balancing is needed in the tree.
|
||||
*/
|
||||
override delete(
|
||||
keyNodeOrEntry: BTNRep<K, V, AVLTreeCounterNode<K, V>>,
|
||||
keyNodeOrEntry: K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
ignoreCount = false
|
||||
): BinaryTreeDeleteResult<AVLTreeCounterNode<K, V>>[] {
|
||||
const deletedResult: BinaryTreeDeleteResult<AVLTreeCounterNode<K, V>>[] = [];
|
||||
|
@ -276,6 +282,7 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
/**
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(log n)
|
||||
*
|
||||
* The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search
|
||||
* tree using either a recursive or iterative approach.
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
|
||||
|
@ -374,8 +381,8 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
/**
|
||||
* The function `keyValueNodeEntryRawToNodeAndValue` converts a key, value, entry, or raw element into
|
||||
* a node object.
|
||||
* @param {BTNRep<K, V, AVLTreeCounterNode<K, V>>} keyNodeOrEntry - The
|
||||
* `keyNodeOrEntry` parameter can be of type `R` or `BTNRep<K, V, AVLTreeCounterNode<K, V>>`.
|
||||
* @param {K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The
|
||||
* `keyNodeOrEntry` parameter can be of type `R` or `K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @param {V} [value] - The `value` parameter is an optional value that can be passed to the
|
||||
* `override` function. It represents the value associated with the key in the data structure. If no
|
||||
* value is provided, it will default to `undefined`.
|
||||
|
@ -384,7 +391,7 @@ export class AVLTreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR
|
|||
* @returns either a AVLTreeCounterNode<K, V> object or undefined.
|
||||
*/
|
||||
protected override _keyValueNodeOrEntryToNodeAndValue(
|
||||
keyNodeOrEntry: BTNRep<K, V, AVLTreeCounterNode<K, V>>,
|
||||
keyNodeOrEntry: K | AVLTreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V,
|
||||
count = 1
|
||||
): [AVLTreeCounterNode<K, V> | undefined, V | undefined] {
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import { AVLTreeMultiMapOptions, BTNOptKeyOrNull, BTNRep, OptNodeOrNull } from '../../types';
|
||||
import { AVLTreeMultiMapOptions, BTNOptKeyOrNull } from '../../types';
|
||||
import { AVLTree, AVLTreeNode } from './avl-tree';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
|
||||
export class AVLTreeMultiMapNode<K = any, V = any> extends AVLTreeNode<K, V[]> {
|
||||
override parent?: AVLTreeMultiMapNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* This TypeScript constructor initializes an object with a key of type K and an array of values of
|
||||
* type V.
|
||||
|
@ -23,28 +25,26 @@ export class AVLTreeMultiMapNode<K = any, V = any> extends AVLTreeNode<K, V[]> {
|
|||
super(key, value);
|
||||
}
|
||||
|
||||
override parent?: AVLTreeMultiMapNode<K, V> = undefined;
|
||||
override _left?: AVLTreeMultiMapNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<AVLTreeMultiMapNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<AVLTreeMultiMapNode<K, V>> {
|
||||
override get left(): AVLTreeMultiMapNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<AVLTreeMultiMapNode<K, V>>) {
|
||||
override set left(v: AVLTreeMultiMapNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<AVLTreeMultiMapNode<K, V>> = undefined;
|
||||
override _right?: AVLTreeMultiMapNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<AVLTreeMultiMapNode<K, V>> {
|
||||
override get right(): AVLTreeMultiMapNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<AVLTreeMultiMapNode<K, V>>) {
|
||||
override set right(v: AVLTreeMultiMapNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -71,7 +71,9 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
* additional options for configuring the AVLTreeMultiMap instance.
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V[], AVLTreeMultiMapNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: AVLTreeMultiMapOptions<K, V[], R>
|
||||
) {
|
||||
super([], { ...options, isMapMode: true });
|
||||
|
@ -117,7 +119,9 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
return new AVLTreeMultiMapNode<K, V>(key, []);
|
||||
}
|
||||
|
||||
override add(node: BTNRep<K, V[], AVLTreeMultiMapNode<K, V>>): boolean;
|
||||
override add(
|
||||
node: K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined
|
||||
): boolean;
|
||||
|
||||
override add(key: K, value: V): boolean;
|
||||
|
||||
|
@ -127,7 +131,7 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
*
|
||||
* The function `add` in TypeScript overrides the superclass method to add key-value pairs to an AVL
|
||||
* tree multi-map.
|
||||
* @param {BTNRep<K, V[], AVLTreeMultiMapNode<K, V>> | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param {K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `override add` method can be either a key-value pair entry or just a key. If it
|
||||
* is a key-value pair entry, it will be in the format `[key, values]`, where `key` is the key and
|
||||
* `values`
|
||||
|
@ -137,7 +141,10 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
* @returns The `override add` method is returning a boolean value, which indicates whether the
|
||||
* addition operation was successful or not.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V[], AVLTreeMultiMapNode<K, V>> | K, value?: V): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | K,
|
||||
value?: V
|
||||
): boolean {
|
||||
if (this.isRealNode(keyNodeOrEntry)) return super.add(keyNodeOrEntry);
|
||||
|
||||
const _commonAdd = (key?: BTNOptKeyOrNull<K>, values?: V[]) => {
|
||||
|
@ -180,7 +187,7 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
*
|
||||
* The function `deleteValue` removes a specific value from a key in an AVLTreeMultiMap data
|
||||
* structure and deletes the entire node if no values are left for that key.
|
||||
* @param {BTNRep<K, V[], AVLTreeMultiMapNode<K, V>> | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param {K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `deleteValue` function can be either a `BTNRep` object representing a key-value
|
||||
* pair in the AVLTreeMultiMapNode, or just the key itself.
|
||||
* @param {V} value - The `value` parameter in the `deleteValue` function represents the specific
|
||||
|
@ -191,7 +198,10 @@ export class AVLTreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, M
|
|||
* `value` was successfully deleted from the array of values associated with the `keyNodeOrEntry`. If
|
||||
* the value was not found in the array, it returns `false`.
|
||||
*/
|
||||
deleteValue(keyNodeOrEntry: BTNRep<K, V[], AVLTreeMultiMapNode<K, V>> | K, value: V): boolean {
|
||||
deleteValue(
|
||||
keyNodeOrEntry: K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | K,
|
||||
value: V
|
||||
): boolean {
|
||||
const values = this.get(keyNodeOrEntry);
|
||||
if (Array.isArray(values)) {
|
||||
const index = values.indexOf(value);
|
||||
|
|
|
@ -6,17 +6,12 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
import { BST, BSTNode } from './bst';
|
||||
import type {
|
||||
AVLTreeOptions,
|
||||
BinaryTreeDeleteResult,
|
||||
BSTNOptKeyOrNode,
|
||||
BTNRep,
|
||||
EntryCallback,
|
||||
OptNodeOrNull
|
||||
} from '../../types';
|
||||
import type { AVLTreeOptions, BinaryTreeDeleteResult, BSTNOptKeyOrNode, EntryCallback } from '../../types';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
|
||||
export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
||||
override parent?: AVLTreeNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* This TypeScript constructor function initializes an instance with a key and an optional value.
|
||||
* @param {K} key - The `key` parameter is typically used to uniquely identify an object or element
|
||||
|
@ -30,28 +25,26 @@ export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|||
super(key, value);
|
||||
}
|
||||
|
||||
override parent?: AVLTreeNode<K, V> = undefined;
|
||||
override _left?: AVLTreeNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<AVLTreeNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<AVLTreeNode<K, V>> {
|
||||
override get left(): AVLTreeNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<AVLTreeNode<K, V>>) {
|
||||
override set left(v: AVLTreeNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<AVLTreeNode<K, V>> = undefined;
|
||||
override _right?: AVLTreeNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<AVLTreeNode<K, V>> {
|
||||
override get right(): AVLTreeNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<AVLTreeNode<K, V>>) {
|
||||
override set right(v: AVLTreeNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -76,7 +69,8 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
* This TypeScript constructor initializes an AVLTree with keys, nodes, entries, or raw data provided
|
||||
* in an iterable format.
|
||||
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
||||
* iterable that can contain either `BTNRep<K, V, AVLTreeNode<K, V>>` objects or `R` objects. It is
|
||||
* iterable that can contain either `
|
||||
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` objects or `R` objects. It is
|
||||
* used to initialize the AVLTree with key-value pairs or raw data entries. If provided
|
||||
* @param [options] - The `options` parameter in the constructor is of type `AVLTreeOptions<K, V,
|
||||
* R>`. It is an optional parameter that allows you to specify additional options for configuring the
|
||||
|
@ -84,7 +78,9 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
* other configuration settings specific
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, AVLTreeNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: AVLTreeOptions<K, V, R>
|
||||
) {
|
||||
super([], options);
|
||||
|
@ -133,12 +129,15 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
* Space Complexity: O(1)
|
||||
*
|
||||
* The function checks if the input is an instance of AVLTreeNode.
|
||||
* @param {BTNRep<K, V, AVLTreeNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, AVLTreeNode<K, V>>`.
|
||||
* @param {K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `
|
||||
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
||||
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
||||
* an instance of the `AVLTreeNode` class.
|
||||
*/
|
||||
override isNode(keyNodeOrEntry: BTNRep<K, V, AVLTreeNode<K, V>>): keyNodeOrEntry is AVLTreeNode<K, V> {
|
||||
override isNode(
|
||||
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): keyNodeOrEntry is AVLTreeNode<K, V> {
|
||||
return keyNodeOrEntry instanceof AVLTreeNode;
|
||||
}
|
||||
|
||||
|
@ -148,13 +147,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
*
|
||||
* The function overrides the add method of a class and inserts a key-value pair into a data
|
||||
* structure, then balances the path.
|
||||
* @param {BTNRep<K, V, AVLTreeNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept values of type `R`, `BTNRep<K, V, AVLTreeNode<K, V>>`
|
||||
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept values of type `R`, `
|
||||
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `
|
||||
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
|
||||
* the key or node being added to the data structure.
|
||||
* @returns The method is returning a boolean value.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V, AVLTreeNode<K, V>>, value?: V): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V
|
||||
): boolean {
|
||||
if (keyNodeOrEntry === null) return false;
|
||||
const inserted = super.add(keyNodeOrEntry, value);
|
||||
if (inserted) this._balancePath(keyNodeOrEntry);
|
||||
|
@ -167,14 +170,16 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
*
|
||||
* The function overrides the delete method in a TypeScript class, performs deletion, and then
|
||||
* balances the tree if necessary.
|
||||
* @param {BTNRep<K, V, AVLTreeNode<K, V>>} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `override delete` method can be one of the following types:
|
||||
* @returns The `delete` method is being overridden in this code snippet. It first calls the `delete`
|
||||
* method from the superclass (presumably a parent class) with the provided `predicate`, which could
|
||||
* be a key, node, entry, or a custom predicate. The result of this deletion operation is stored in
|
||||
* `deletedResults`, which is an array of `BinaryTreeDeleteResult` objects.
|
||||
*/
|
||||
override delete(keyNodeOrEntry: BTNRep<K, V, AVLTreeNode<K, V>>): BinaryTreeDeleteResult<AVLTreeNode<K, V>>[] {
|
||||
override delete(
|
||||
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): BinaryTreeDeleteResult<AVLTreeNode<K, V>>[] {
|
||||
const deletedResults = super.delete(keyNodeOrEntry);
|
||||
for (const { needBalanced } of deletedResults) {
|
||||
if (needBalanced) {
|
||||
|
@ -487,10 +492,11 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|||
*
|
||||
* The `_balancePath` function is used to update the heights of nodes and perform rotation operations
|
||||
* to restore balance in an AVL tree after inserting a node.
|
||||
* @param {BTNRep<K, V, AVLTreeNode<K, V>>} node - The `node` parameter can be of type `R` or
|
||||
* `BTNRep<K, V, AVLTreeNode<K, V>>`.
|
||||
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } node - The `node` parameter can be of type `R` or
|
||||
* `
|
||||
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
||||
*/
|
||||
protected _balancePath(node: BTNRep<K, V, AVLTreeNode<K, V>>): void {
|
||||
protected _balancePath(node: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined): void {
|
||||
node = this.ensureNode(node);
|
||||
const path = this.getPathToRoot(node, node => node, false); // first O(log n) + O(log n)
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,8 +17,7 @@ import type {
|
|||
IterationType,
|
||||
NodeCallback,
|
||||
NodePredicate,
|
||||
OptNode,
|
||||
OptNodeOrNull
|
||||
OptNode
|
||||
} from '../../types';
|
||||
import { BinaryTree, BinaryTreeNode } from './binary-tree';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
|
@ -27,6 +26,8 @@ import { isComparable } from '../../utils';
|
|||
import { Range } from '../../common';
|
||||
|
||||
export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
|
||||
override parent?: BSTNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* This TypeScript constructor function initializes an instance with a key and an optional value.
|
||||
* @param {K} key - The `key` parameter is typically used to uniquely identify an object or element
|
||||
|
@ -40,28 +41,26 @@ export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
|
|||
super(key, value);
|
||||
}
|
||||
|
||||
override parent?: BSTNode<K, V> = undefined;
|
||||
override _left?: BSTNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<BSTNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<BSTNode<K, V>> {
|
||||
override get left(): BSTNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<BSTNode<K, V>>) {
|
||||
override set left(v: BSTNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<BSTNode<K, V>> = undefined;
|
||||
override _right?: BSTNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<BSTNode<K, V>> {
|
||||
override get right(): BSTNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<BSTNode<K, V>>) {
|
||||
override set right(v: BSTNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -142,12 +141,17 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* This TypeScript constructor initializes a binary search tree with optional options and adds
|
||||
* elements if provided.
|
||||
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
||||
* iterable that can contain elements of type `BTNRep<K, V, BSTNode<K, V>>` or `R`. It is used to
|
||||
* iterable that can contain elements of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It is used to
|
||||
* initialize the binary search tree with keys, nodes, entries, or raw data.
|
||||
* @param [options] - The `options` parameter is an optional object that can contain the following
|
||||
* properties:
|
||||
*/
|
||||
constructor(keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, BSTNode<K, V>> | R> = [], options?: BSTOptions<K, V, R>) {
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: BSTOptions<K, V, R>
|
||||
) {
|
||||
super([], options);
|
||||
|
||||
if (options) {
|
||||
|
@ -243,7 +247,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
*
|
||||
* The function ensures the existence of a node in a data structure and returns it, or undefined if
|
||||
* it doesn't exist.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept a value of type `R`, which represents the key, node,
|
||||
* entry, or raw element that needs to be ensured in the tree.
|
||||
* @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional
|
||||
|
@ -253,7 +257,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* not be ensured.
|
||||
*/
|
||||
override ensureNode(
|
||||
keyNodeOrEntry: BTNRep<K, V, BSTNode<K, V>>,
|
||||
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): OptNode<BSTNode<K, V>> {
|
||||
return super.ensureNode(keyNodeOrEntry, iterationType) ?? undefined;
|
||||
|
@ -264,12 +268,14 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* Space Complexity: O(1)
|
||||
*
|
||||
* The function checks if the input is an instance of the BSTNode class.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, BSTNode<K, V>>`.
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
||||
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
||||
* an instance of the `BSTNode` class.
|
||||
*/
|
||||
override isNode(keyNodeOrEntry: BTNRep<K, V, BSTNode<K, V>>): keyNodeOrEntry is BSTNode<K, V> {
|
||||
override isNode(
|
||||
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): keyNodeOrEntry is BSTNode<K, V> {
|
||||
return keyNodeOrEntry instanceof BSTNode;
|
||||
}
|
||||
|
||||
|
@ -293,13 +299,16 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* Space Complexity: O(log n)
|
||||
*
|
||||
* The `add` function in TypeScript adds a new node to a binary search tree based on the key value.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept a value of type `R` or `BTNRep<K, V, BSTNode<K, V>>`.
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept a value of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
||||
* @param {V} [value] - The `value` parameter is an optional value that can be associated with the
|
||||
* key in the binary search tree. If provided, it will be stored in the node along with the key.
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V, BSTNode<K, V>>, value?: V): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V
|
||||
): boolean {
|
||||
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
||||
if (newNode === undefined) return false;
|
||||
|
||||
|
@ -383,7 +392,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
}
|
||||
|
||||
const realBTNExemplars: {
|
||||
key: R | BTNRep<K, V, BSTNode<K, V>>;
|
||||
key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
|
||||
value: V | undefined;
|
||||
orgIndex: number;
|
||||
}[] = [];
|
||||
|
@ -394,7 +403,11 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
i++;
|
||||
}
|
||||
|
||||
let sorted: { key: R | BTNRep<K, V, BSTNode<K, V>>; value: V | undefined; orgIndex: number }[] = [];
|
||||
let sorted: {
|
||||
key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
|
||||
value: V | undefined;
|
||||
orgIndex: number;
|
||||
}[] = [];
|
||||
|
||||
sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
|
||||
let keyA: K | undefined | null, keyB: K | undefined | null;
|
||||
|
@ -418,7 +431,13 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
return 0;
|
||||
});
|
||||
|
||||
const _dfs = (arr: { key: R | BTNRep<K, V, BSTNode<K, V>>; value: V | undefined; orgIndex: number }[]) => {
|
||||
const _dfs = (
|
||||
arr: {
|
||||
key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
|
||||
value: V | undefined;
|
||||
orgIndex: number;
|
||||
}[]
|
||||
) => {
|
||||
if (arr.length === 0) return;
|
||||
|
||||
const mid = Math.floor((arr.length - 1) / 2);
|
||||
|
@ -473,7 +492,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
*
|
||||
* The function `search` in TypeScript overrides the search behavior in a binary tree structure based
|
||||
* on specified criteria.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>> | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The
|
||||
* `keyNodeEntryOrPredicate` parameter in the `override search` method can accept one of the
|
||||
* following types:
|
||||
* @param [onlyOne=false] - The `onlyOne` parameter is a boolean flag that determines whether the
|
||||
|
@ -481,9 +500,9 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* search will return as soon as a matching node is found. If `onlyOne` is set to `false`, the
|
||||
* @param {C} callback - The `callback` parameter in the `override search` function is a function
|
||||
* that will be called on each node that matches the search criteria. It is of type `C`, which
|
||||
* extends `NodeCallback<BSTNode<K, V>>`. The callback function should accept a node of type `BSTNode<K, V>` as its
|
||||
* extends `NodeCallback<BSTNode<K, V> | null>`. The callback function should accept a node of type `BSTNode<K, V>` as its
|
||||
* argument and
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} startNode - The `startNode` parameter in the `override search`
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `override search`
|
||||
* method represents the node from which the search operation will begin. It is the starting point
|
||||
* for searching within the tree data structure. The method ensures that the `startNode` is a valid
|
||||
* node before proceeding with the search operation. If the `
|
||||
|
@ -496,10 +515,17 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* collected in an array and returned as the output of the method.
|
||||
*/
|
||||
override search<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
keyNodeEntryOrPredicate: BTNRep<K, V, BSTNode<K, V>> | NodePredicate<BSTNode<K, V>> | Range<K>,
|
||||
keyNodeEntryOrPredicate:
|
||||
| K
|
||||
| BSTNode<K, V>
|
||||
| [K | null | undefined, V | undefined]
|
||||
| null
|
||||
| undefined
|
||||
| NodePredicate<BSTNode<K, V>>
|
||||
| Range<K>,
|
||||
onlyOne = false,
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
startNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): ReturnType<C>[] {
|
||||
if (keyNodeEntryOrPredicate === undefined) return [];
|
||||
|
@ -511,21 +537,32 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
const isRange = this.isRange(keyNodeEntryOrPredicate);
|
||||
// Set predicate based on parameter type
|
||||
if (isRange) {
|
||||
predicate = node => keyNodeEntryOrPredicate.isInRange(node.key, this._comparator);
|
||||
predicate = node => {
|
||||
if (!node) return false;
|
||||
return keyNodeEntryOrPredicate.isInRange(node.key, this._comparator);
|
||||
};
|
||||
} else {
|
||||
predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
|
||||
}
|
||||
const isToLeftByRange = (cur: BSTNode<K, V>) => {
|
||||
const shouldVisitLeft = (cur: BSTNode<K, V> | null | undefined) => {
|
||||
if (!cur) return false;
|
||||
if (!this.isRealNode(cur.left)) return false;
|
||||
if (isRange) {
|
||||
const range = keyNodeEntryOrPredicate;
|
||||
const leftS = this.isReverse ? range.high : range.low;
|
||||
const leftI = this.isReverse ? range.includeHigh : range.includeLow;
|
||||
return (leftI && this._compare(cur.key, leftS) >= 0) || (!leftI && this._compare(cur.key, leftS) > 0);
|
||||
}
|
||||
return false;
|
||||
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
||||
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
||||
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) > 0;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const isToRightByRange = (cur: BSTNode<K, V>) => {
|
||||
const shouldVisitRight = (cur: BSTNode<K, V> | null | undefined) => {
|
||||
if (!cur) return false;
|
||||
if (!this.isRealNode(cur.right)) return false;
|
||||
if (isRange) {
|
||||
const range = keyNodeEntryOrPredicate;
|
||||
const rightS = this.isReverse ? range.low : range.high;
|
||||
|
@ -533,79 +570,27 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
|
||||
return (rightI && this._compare(cur.key, rightS) <= 0) || (!rightI && this._compare(cur.key, rightS) < 0);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const ans: ReturnType<C>[] = [];
|
||||
if (iterationType === 'RECURSIVE') {
|
||||
const dfs = (cur: BSTNode<K, V>) => {
|
||||
if (predicate(cur)) {
|
||||
ans.push(callback(cur));
|
||||
if (onlyOne) return;
|
||||
}
|
||||
|
||||
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
|
||||
|
||||
if (isRange) {
|
||||
if (this.isRealNode(cur.left) && isToLeftByRange(cur)) dfs(cur.left);
|
||||
if (this.isRealNode(cur.right) && isToRightByRange(cur)) dfs(cur.right);
|
||||
} else if (!this._isPredicate(keyNodeEntryOrPredicate)) {
|
||||
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
||||
if (
|
||||
this.isRealNode(cur.left) &&
|
||||
benchmarkKey !== null &&
|
||||
benchmarkKey !== undefined &&
|
||||
this._compare(cur.key, benchmarkKey) > 0
|
||||
)
|
||||
dfs(cur.left);
|
||||
if (
|
||||
this.isRealNode(cur.right) &&
|
||||
benchmarkKey !== null &&
|
||||
benchmarkKey !== undefined &&
|
||||
this._compare(cur.key, benchmarkKey) < 0
|
||||
)
|
||||
dfs(cur.right);
|
||||
} else {
|
||||
if (this.isRealNode(cur.left)) dfs(cur.left);
|
||||
if (this.isRealNode(cur.right)) dfs(cur.right);
|
||||
}
|
||||
};
|
||||
|
||||
dfs(startNode);
|
||||
} else {
|
||||
const stack = [startNode];
|
||||
while (stack.length > 0) {
|
||||
const cur = stack.pop()!;
|
||||
if (predicate(cur)) {
|
||||
ans.push(callback(cur));
|
||||
if (onlyOne) return ans;
|
||||
}
|
||||
if (isRange) {
|
||||
if (this.isRealNode(cur.left) && isToLeftByRange(cur)) stack.push(cur.left);
|
||||
if (this.isRealNode(cur.right) && isToRightByRange(cur)) stack.push(cur.right);
|
||||
} else if (!this._isPredicate(keyNodeEntryOrPredicate)) {
|
||||
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
||||
if (
|
||||
this.isRealNode(cur.right) &&
|
||||
benchmarkKey !== null &&
|
||||
benchmarkKey !== undefined &&
|
||||
this._compare(cur.key, benchmarkKey) < 0
|
||||
)
|
||||
stack.push(cur.right);
|
||||
if (
|
||||
this.isRealNode(cur.left) &&
|
||||
benchmarkKey !== null &&
|
||||
benchmarkKey !== undefined &&
|
||||
this._compare(cur.key, benchmarkKey) > 0
|
||||
)
|
||||
stack.push(cur.left);
|
||||
} else {
|
||||
if (this.isRealNode(cur.right)) stack.push(cur.right);
|
||||
if (this.isRealNode(cur.left)) stack.push(cur.left);
|
||||
}
|
||||
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
||||
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
||||
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) < 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ans;
|
||||
return true;
|
||||
};
|
||||
return super._dfs(
|
||||
callback,
|
||||
'IN',
|
||||
onlyOne,
|
||||
startNode,
|
||||
iterationType,
|
||||
false,
|
||||
shouldVisitLeft,
|
||||
shouldVisitRight,
|
||||
() => true,
|
||||
cur => {
|
||||
if (cur) return predicate(cur);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -617,9 +602,9 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* either a `Range` object or an array of two elements representing the range boundaries.
|
||||
* @param {C} callback - The `callback` parameter in the `rangeSearch` function is a callback
|
||||
* function that is used to process each node that is found within the specified range during the
|
||||
* search operation. It is of type `NodeCallback<BSTNode<K, V>>`, where `BSTNode<K, V>` is the type of nodes in the
|
||||
* search operation. It is of type `NodeCallback<BSTNode<K, V> | null>`, where `BSTNode<K, V>` is the type of nodes in the
|
||||
* data structure.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} startNode - The `startNode` parameter in the `rangeSearch`
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `rangeSearch`
|
||||
* function represents the node from which the search for nodes within the specified range will
|
||||
* begin. It is the starting point for the range search operation.
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter in the `rangeSearch` function
|
||||
|
@ -632,7 +617,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
rangeSearch<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
range: Range<K> | [K, K],
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
startNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
) {
|
||||
const searchRange: Range<K> = range instanceof Range ? range : new Range(range[0], range[1]);
|
||||
|
@ -644,8 +629,8 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* Space Complexity: O(log n)
|
||||
*
|
||||
* This function retrieves a node based on a given keyNodeEntryOrPredicate within a binary search tree structure.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>> | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate`
|
||||
* parameter can be of type `BTNRep<K, V, BSTNode<K, V>>`, `R`, or `NodePredicate<BSTNode<K, V>>`.
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate`
|
||||
* parameter can be of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `R`, or `NodePredicate<BSTNode<K, V>>`.
|
||||
* @param {BSTNOptKeyOrNode<K, BSTNode<K, V>>} startNode - The `startNode` parameter in the `getNode` method
|
||||
* is used to specify the starting point for searching nodes in the binary search tree. If no
|
||||
* specific starting point is provided, the default value is set to `this._root`, which is the root
|
||||
|
@ -660,7 +645,13 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* returns the first node found or `undefined` if no node is found.
|
||||
*/
|
||||
override getNode(
|
||||
keyNodeEntryOrPredicate: BTNRep<K, V, BSTNode<K, V>> | NodePredicate<BSTNode<K, V>>,
|
||||
keyNodeEntryOrPredicate:
|
||||
| K
|
||||
| BSTNode<K, V>
|
||||
| [K | null | undefined, V | undefined]
|
||||
| null
|
||||
| undefined
|
||||
| NodePredicate<BSTNode<K, V>>,
|
||||
startNode: BSTNOptKeyOrNode<K, BSTNode<K, V>> = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): OptNode<BSTNode<K, V>> {
|
||||
|
@ -671,29 +662,36 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* Time complexity: O(n)
|
||||
* Space complexity: O(n)
|
||||
*
|
||||
* The function overrides the depth-first search method and returns an array of the return types of
|
||||
* the callback function.
|
||||
* The function `dfs` in TypeScript overrides the base class method with default parameters and
|
||||
* returns the result of the super class `dfs` method.
|
||||
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
||||
* during the depth-first search traversal. It is an optional parameter and defaults to
|
||||
* `this._DEFAULT_NODE_CALLBACK`. The type `C` represents the type of the callback function.
|
||||
* @param {DFSOrderPattern} [pattern=IN] - The "pattern" parameter in the code snippet refers to the
|
||||
* order in which the Depth-First Search (DFS) algorithm visits the nodes in a tree or graph. It can
|
||||
* take one of the following values:
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} startNode - The `startNode` parameter is the starting
|
||||
* point for the depth-first search traversal. It can be either a root node, a key-value pair, or a
|
||||
* node entry. If not specified, the default value is the root of the tree.
|
||||
* @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter specifies the
|
||||
* type of iteration to be used during the Depth-First Search (DFS) traversal. It can have one of the
|
||||
* following values:
|
||||
* @returns The method is returning an array of the return type of the callback function.
|
||||
* visited during the Depth-First Search traversal. It is a generic type `C` that extends the
|
||||
* `NodeCallback` interface for `BSTNode<K, V>`. The default value for `callback` is `this._
|
||||
* @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `override dfs` method
|
||||
* specifies the order in which the Depth-First Search (DFS) traversal should be performed on the
|
||||
* Binary Search Tree (BST). The possible values for the `pattern` parameter are:
|
||||
* @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `override dfs` method is a
|
||||
* boolean flag that indicates whether you want to stop the depth-first search traversal after
|
||||
* finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set
|
||||
* to `true`, the traversal will stop after finding
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} startNode -
|
||||
* The `startNode` parameter in the `override dfs` method can be one of the following types:
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter in the `override dfs` method
|
||||
* specifies the type of iteration to be performed during the Depth-First Search (DFS) traversal of a
|
||||
* Binary Search Tree (BST). It is used to determine the order in which nodes are visited during the
|
||||
* traversal. The possible values for `
|
||||
* @returns The `override` function is returning the result of calling the `dfs` method from the
|
||||
* superclass, with the provided arguments `callback`, `pattern`, `onlyOne`, `startNode`, and
|
||||
* `iterationType`. The return type is an array of the return type of the callback function `C`.
|
||||
*/
|
||||
override dfs<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
pattern: DFSOrderPattern = 'IN',
|
||||
startNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
onlyOne: boolean = false,
|
||||
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): ReturnType<C>[] {
|
||||
return super.dfs(callback, pattern, startNode, iterationType);
|
||||
return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -705,7 +703,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
||||
* visited during the breadth-first search. It should take a single argument, which is the current
|
||||
* node being visited, and it can return a value of any type.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} startNode - The `startNode` parameter is the starting
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
||||
* point for the breadth-first search. It can be either a root node, a key-value pair, or an entry
|
||||
* object. If no value is provided, the default value is the root of the tree.
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
|
||||
|
@ -715,7 +713,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
*/
|
||||
override bfs<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
startNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): ReturnType<C>[] {
|
||||
return super.bfs(callback, startNode, iterationType, false);
|
||||
|
@ -728,9 +726,9 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* The function overrides the listLevels method from the superclass and returns an array of arrays
|
||||
* containing the results of the callback function applied to each level of the tree.
|
||||
* @param {C} callback - The `callback` parameter is a generic type `C` that extends
|
||||
* `NodeCallback<BSTNode<K, V>>`. It represents a callback function that will be called for each node in the
|
||||
* `NodeCallback<BSTNode<K, V> | null>`. It represents a callback function that will be called for each node in the
|
||||
* tree during the iteration process.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} startNode - The `startNode` parameter is the starting
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
||||
* point for listing the levels of the binary tree. It can be either a root node of the tree, a
|
||||
* key-value pair representing a node in the tree, or a key representing a node in the tree. If no
|
||||
* value is provided, the root of
|
||||
|
@ -741,7 +739,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
*/
|
||||
override listLevels<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
startNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): ReturnType<C>[][] {
|
||||
return super.listLevels(callback, startNode, iterationType, false);
|
||||
|
@ -759,7 +757,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to
|
||||
* traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1,
|
||||
* 0, or 1, where:
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} targetNode - The `targetNode` parameter is the node in
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } targetNode - The `targetNode` parameter is the node in
|
||||
* the binary tree that you want to start traversing from. It can be specified either by providing
|
||||
* the key of the node, the node itself, or an entry containing the key and value of the node. If no
|
||||
* `targetNode` is provided,
|
||||
|
@ -771,7 +769,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
lesserOrGreaterTraverse<C extends NodeCallback<BSTNode<K, V>>>(
|
||||
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
||||
lesserOrGreater: CP = -1,
|
||||
targetNode: BTNRep<K, V, BSTNode<K, V>> = this._root,
|
||||
targetNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
||||
iterationType: IterationType = this.iterationType
|
||||
): ReturnType<C>[] {
|
||||
const targetNodeEnsured = this.ensureNode(targetNode);
|
||||
|
@ -831,8 +829,8 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
if (l > r) return;
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
if (this._isMapMode) this.add(midNode.key);
|
||||
else this.add([midNode.key, midNode.value]);
|
||||
if (this._isMapMode && midNode !== null) this.add(midNode.key);
|
||||
else if (midNode !== null) this.add([midNode.key, midNode.value]);
|
||||
buildBalanceBST(l, m - 1);
|
||||
buildBalanceBST(m + 1, r);
|
||||
};
|
||||
|
@ -848,8 +846,8 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
if (l <= r) {
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
if (this._isMapMode) this.add(midNode.key);
|
||||
else this.add([midNode.key, midNode.value]);
|
||||
if (this._isMapMode && midNode !== null) this.add(midNode.key);
|
||||
else if (midNode !== null) this.add([midNode.key, midNode.value]);
|
||||
stack.push([m + 1, r]);
|
||||
stack.push([l, m - 1]);
|
||||
}
|
||||
|
@ -877,7 +875,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
let balanced = true;
|
||||
|
||||
if (iterationType === 'RECURSIVE') {
|
||||
const _height = (cur: OptNodeOrNull<BSTNode<K, V>>): number => {
|
||||
const _height = (cur: BSTNode<K, V> | null | undefined): number => {
|
||||
if (!cur) return 0;
|
||||
const leftHeight = _height(cur.left),
|
||||
rightHeight = _height(cur.right);
|
||||
|
@ -966,15 +964,15 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|||
* Space Complexity: O(1)
|
||||
*
|
||||
* The function overrides a method and converts a key, value pair or entry or raw element to a node.
|
||||
* @param {BTNRep<K, V, BSTNode<K, V>>} keyNodeOrEntry - A variable that can be of
|
||||
* type R or BTNRep<K, V, BSTNode<K, V>>. It represents either a key, a node, an entry, or a raw
|
||||
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - A variable that can be of
|
||||
* type R or K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined . It represents either a key, a node, an entry, or a raw
|
||||
* element.
|
||||
* @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
|
||||
* value associated with a key in a key-value pair.
|
||||
* @returns either a BSTNode<K, V> object or undefined.
|
||||
*/
|
||||
protected override _keyValueNodeOrEntryToNodeAndValue(
|
||||
keyNodeOrEntry: BTNRep<K, V, BSTNode<K, V>>,
|
||||
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V
|
||||
): [OptNode<BSTNode<K, V>>, V | undefined] {
|
||||
const [node, entryValue] = super._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
||||
|
|
|
@ -1,17 +1,10 @@
|
|||
import type {
|
||||
BinaryTreeDeleteResult,
|
||||
BTNRep,
|
||||
CRUD,
|
||||
EntryCallback,
|
||||
OptNode,
|
||||
OptNodeOrNull,
|
||||
RBTNColor,
|
||||
RedBlackTreeOptions
|
||||
} from '../../types';
|
||||
import type { BinaryTreeDeleteResult, CRUD, EntryCallback, OptNode, RBTNColor, RedBlackTreeOptions } from '../../types';
|
||||
import { BST, BSTNode } from './bst';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
|
||||
export class RedBlackTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
||||
override parent?: RedBlackTreeNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* The constructor initializes a node with a key, value, and color for a Red-Black Tree.
|
||||
* @param {K} key - The `key` parameter is a key of type `K` that is used to identify the node in a
|
||||
|
@ -27,28 +20,26 @@ export class RedBlackTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|||
this._color = color;
|
||||
}
|
||||
|
||||
override parent?: RedBlackTreeNode<K, V> = undefined;
|
||||
override _left?: RedBlackTreeNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<RedBlackTreeNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<RedBlackTreeNode<K, V>> {
|
||||
override get left(): RedBlackTreeNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<RedBlackTreeNode<K, V>>) {
|
||||
override set left(v: RedBlackTreeNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<RedBlackTreeNode<K, V>> = undefined;
|
||||
override _right?: RedBlackTreeNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<RedBlackTreeNode<K, V>> {
|
||||
override get right(): RedBlackTreeNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<RedBlackTreeNode<K, V>>) {
|
||||
override set right(v: RedBlackTreeNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -117,7 +108,7 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* This TypeScript constructor initializes a Red-Black Tree with optional keys, nodes, entries, or
|
||||
* raw data.
|
||||
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
||||
* iterable that can contain either `BTNRep<K, V, RedBlackTreeNode<K, V>>` objects or `R` objects. It
|
||||
* iterable that can contain either `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined` objects or `R` objects. It
|
||||
* is used to initialize the Red-Black Tree with keys, nodes, entries, or
|
||||
* @param [options] - The `options` parameter in the constructor is of type `RedBlackTreeOptions<K,
|
||||
* V, R>`. It is an optional parameter that allows you to specify additional options for the
|
||||
|
@ -125,7 +116,9 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* any other parameters that are specific to
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, RedBlackTreeNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: RedBlackTreeOptions<K, V, R>
|
||||
) {
|
||||
super([], options);
|
||||
|
@ -188,12 +181,14 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* Space Complexity: O(1)
|
||||
*
|
||||
* The function checks if the input is an instance of the RedBlackTreeNode class.
|
||||
* @param {BTNRep<K, V, RedBlackTreeNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, RedBlackTreeNode<K, V>>`.
|
||||
* @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
||||
* an instance of the `RedBlackTreeNode` class.
|
||||
*/
|
||||
override isNode(keyNodeOrEntry: BTNRep<K, V, RedBlackTreeNode<K, V>>): keyNodeOrEntry is RedBlackTreeNode<K, V> {
|
||||
override isNode(
|
||||
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): keyNodeOrEntry is RedBlackTreeNode<K, V> {
|
||||
return keyNodeOrEntry instanceof RedBlackTreeNode;
|
||||
}
|
||||
|
||||
|
@ -215,8 +210,8 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function adds a new node to a binary search tree and returns true if the node was successfully
|
||||
* added.
|
||||
* @param {BTNRep<K, V, RedBlackTreeNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept a value of type `R` or `BTNRep<K, V, RedBlackTreeNode<K, V>>`.
|
||||
* @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can accept a value of type `R` or `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
|
||||
* the key in the data structure. It represents the value that you want to add or update in the data
|
||||
* structure.
|
||||
|
@ -224,7 +219,10 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* the method returns true. If the node already exists and its value is updated, the method also
|
||||
* returns true. If the node cannot be added or updated, the method returns false.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V, RedBlackTreeNode<K, V>>, value?: V): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V
|
||||
): boolean {
|
||||
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
||||
if (!this.isRealNode(newNode)) return false;
|
||||
|
||||
|
@ -254,7 +252,7 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function overrides the delete method in a binary tree data structure to remove a node based on
|
||||
* a given predicate and maintain the binary search tree properties.
|
||||
* @param {BTNRep<K, V, RedBlackTreeNode<K, V>>} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `override delete` method is used to specify the condition or key based on which a
|
||||
* node should be deleted from the binary tree. It can be a key, a node, an entry, or a predicate
|
||||
* function that determines which node(s) should be deleted.
|
||||
|
@ -263,7 +261,7 @@ export class RedBlackTree<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* balancing is needed.
|
||||
*/
|
||||
override delete(
|
||||
keyNodeOrEntry: BTNRep<K, V, RedBlackTreeNode<K, V>>
|
||||
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): BinaryTreeDeleteResult<RedBlackTreeNode<K, V>>[] {
|
||||
if (keyNodeOrEntry === null) return [];
|
||||
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
import type {
|
||||
BinaryTreeDeleteResult,
|
||||
BSTNOptKeyOrNode,
|
||||
BTNRep,
|
||||
EntryCallback,
|
||||
IterationType,
|
||||
OptNode,
|
||||
OptNodeOrNull,
|
||||
RBTNColor,
|
||||
TreeCounterOptions
|
||||
} from '../../types';
|
||||
|
@ -20,6 +18,8 @@ import { IBinaryTree } from '../../interfaces';
|
|||
import { RedBlackTree, RedBlackTreeNode } from './red-black-tree';
|
||||
|
||||
export class TreeCounterNode<K = any, V = any> extends RedBlackTreeNode<K, V> {
|
||||
override parent?: TreeCounterNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* The constructor function initializes a Red-Black Tree node with a key, value, count, and color.
|
||||
* @param {K} key - The key parameter represents the key of the node in the Red-Black Tree. It is
|
||||
|
@ -37,28 +37,26 @@ export class TreeCounterNode<K = any, V = any> extends RedBlackTreeNode<K, V> {
|
|||
this.count = count;
|
||||
}
|
||||
|
||||
override parent?: TreeCounterNode<K, V> = undefined;
|
||||
override _left?: TreeCounterNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<TreeCounterNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<TreeCounterNode<K, V>> {
|
||||
override get left(): TreeCounterNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<TreeCounterNode<K, V>>) {
|
||||
override set left(v: TreeCounterNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<TreeCounterNode<K, V>> = undefined;
|
||||
override _right?: TreeCounterNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<TreeCounterNode<K, V>> {
|
||||
override get right(): TreeCounterNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<TreeCounterNode<K, V>>) {
|
||||
override set right(v: TreeCounterNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -83,7 +81,9 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* `compareValues`, which are functions used to compare keys and values respectively.
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, TreeCounterNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: TreeCounterOptions<K, V, R>
|
||||
) {
|
||||
super([], options);
|
||||
|
@ -111,7 +111,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*/
|
||||
getComputedCount(): number {
|
||||
let sum = 0;
|
||||
this.dfs(node => (sum += node.count));
|
||||
this.dfs(node => (sum += node ? node.count : 0));
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
@ -152,12 +152,14 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
|
||||
/**
|
||||
* The function checks if the input is an instance of the TreeCounterNode class.
|
||||
* @param {BTNRep<K, V, TreeCounterNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, TreeCounterNode<K, V>>`.
|
||||
* @param {K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
||||
* an instance of the `TreeCounterNode` class.
|
||||
*/
|
||||
override isNode(keyNodeOrEntry: BTNRep<K, V, TreeCounterNode<K, V>>): keyNodeOrEntry is TreeCounterNode<K, V> {
|
||||
override isNode(
|
||||
keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
||||
): keyNodeOrEntry is TreeCounterNode<K, V> {
|
||||
return keyNodeOrEntry instanceof TreeCounterNode;
|
||||
}
|
||||
|
||||
|
@ -167,7 +169,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function overrides the add method of a class and adds a new node to a data structure, updating
|
||||
* the count and returning a boolean indicating success.
|
||||
* @param {BTNRep<K, V, TreeCounterNode<K, V>>} keyNodeOrEntry - The
|
||||
* @param {K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The
|
||||
* `keyNodeOrEntry` parameter can accept one of the following types:
|
||||
* @param {V} [value] - The `value` parameter represents the value associated with the key in the
|
||||
* data structure. It is an optional parameter, so it can be omitted if not needed.
|
||||
|
@ -177,7 +179,11 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* @returns The method is returning a boolean value. It returns true if the addition of the new node
|
||||
* was successful, and false otherwise.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V, TreeCounterNode<K, V>>, value?: V, count = 1): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V,
|
||||
count = 1
|
||||
): boolean {
|
||||
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value, count);
|
||||
const orgCount = newNode?.count || 0;
|
||||
const isSuccessAdded = super.add(newNode, newValue);
|
||||
|
@ -196,7 +202,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function `delete` in TypeScript overrides the deletion operation in a binary tree data
|
||||
* structure, handling cases where nodes have children and maintaining balance in the tree.
|
||||
* @param {BTNRep<K, V, TreeCounterNode<K, V>>} keyNodeOrEntry - The `predicate`
|
||||
* @param {K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The `predicate`
|
||||
* parameter in the `delete` method is used to specify the condition or key based on which a node
|
||||
* should be deleted from the binary tree. It can be a key, a node, or an entry.
|
||||
* @param [ignoreCount=false] - The `ignoreCount` parameter in the `override delete` method is a
|
||||
|
@ -206,7 +212,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* @returns The `override delete` method returns an array of `BinaryTreeDeleteResult<TreeCounterNode<K, V>>` objects.
|
||||
*/
|
||||
override delete(
|
||||
keyNodeOrEntry: BTNRep<K, V, TreeCounterNode<K, V>>,
|
||||
keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
ignoreCount = false
|
||||
): BinaryTreeDeleteResult<TreeCounterNode<K, V>>[] {
|
||||
if (keyNodeOrEntry === null) return [];
|
||||
|
@ -340,8 +346,8 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
if (l > r) return;
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
|
||||
else this.add(midNode.key, midNode.value, midNode.count);
|
||||
if (this._isMapMode && midNode !== null) this.add(midNode.key, undefined, midNode.count);
|
||||
else if (midNode !== null) this.add(midNode.key, midNode.value, midNode.count);
|
||||
buildBalanceBST(l, m - 1);
|
||||
buildBalanceBST(m + 1, r);
|
||||
};
|
||||
|
@ -357,8 +363,8 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
if (l <= r) {
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
|
||||
else this.add(midNode.key, midNode.value, midNode.count);
|
||||
if (this._isMapMode && midNode !== null) this.add(midNode.key, undefined, midNode.count);
|
||||
else if (midNode !== null) this.add(midNode.key, midNode.value, midNode.count);
|
||||
stack.push([m + 1, r]);
|
||||
stack.push([l, m - 1]);
|
||||
}
|
||||
|
@ -377,7 +383,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*/
|
||||
override clone() {
|
||||
const cloned = this.createTree();
|
||||
this.bfs(node => cloned.add(node.key, undefined, node.count));
|
||||
this.bfs(node => cloned.add(node === null ? null : node.key, undefined, node === null ? 0 : node.count));
|
||||
if (this._isMapMode) cloned._store = this._store;
|
||||
return cloned;
|
||||
}
|
||||
|
@ -413,8 +419,8 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
/**
|
||||
* The function `keyValueNodeEntryRawToNodeAndValue` takes in a key, value, and count and returns a
|
||||
* node based on the input.
|
||||
* @param {BTNRep<K, V, TreeCounterNode<K, V>>} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `BTNRep<K, V, TreeCounterNode<K, V>>`.
|
||||
* @param {K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
|
||||
* `keyNodeOrEntry` can be of type `R` or `K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
|
||||
* @param {V} [value] - The `value` parameter is an optional value that represents the value
|
||||
* associated with the key in the node. It is used when creating a new node or updating the value of
|
||||
* an existing node.
|
||||
|
@ -423,7 +429,7 @@ export class TreeCounter<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* @returns either a TreeCounterNode<K, V> object or undefined.
|
||||
*/
|
||||
protected override _keyValueNodeOrEntryToNodeAndValue(
|
||||
keyNodeOrEntry: BTNRep<K, V, TreeCounterNode<K, V>>,
|
||||
keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
||||
value?: V,
|
||||
count = 1
|
||||
): [TreeCounterNode<K, V> | undefined, V | undefined] {
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import type { BTNOptKeyOrNull, BTNRep, OptNodeOrNull, TreeMultiMapOptions } from '../../types';
|
||||
import type { BTNOptKeyOrNull, TreeMultiMapOptions } from '../../types';
|
||||
import { RedBlackTree, RedBlackTreeNode } from './red-black-tree';
|
||||
import { IBinaryTree } from '../../interfaces';
|
||||
|
||||
export class TreeMultiMapNode<K = any, V = any> extends RedBlackTreeNode<K, V[]> {
|
||||
override parent?: TreeMultiMapNode<K, V> = undefined;
|
||||
|
||||
/**
|
||||
* This TypeScript constructor initializes an object with a key of type K and an array of values of
|
||||
* type V.
|
||||
|
@ -23,28 +25,26 @@ export class TreeMultiMapNode<K = any, V = any> extends RedBlackTreeNode<K, V[]>
|
|||
super(key, value);
|
||||
}
|
||||
|
||||
override parent?: TreeMultiMapNode<K, V> = undefined;
|
||||
override _left?: TreeMultiMapNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override _left?: OptNodeOrNull<TreeMultiMapNode<K, V>> = undefined;
|
||||
|
||||
override get left(): OptNodeOrNull<TreeMultiMapNode<K, V>> {
|
||||
override get left(): TreeMultiMapNode<K, V> | null | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
override set left(v: OptNodeOrNull<TreeMultiMapNode<K, V>>) {
|
||||
override set left(v: TreeMultiMapNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
this._left = v;
|
||||
}
|
||||
|
||||
override _right?: OptNodeOrNull<TreeMultiMapNode<K, V>> = undefined;
|
||||
override _right?: TreeMultiMapNode<K, V> | null | undefined = undefined;
|
||||
|
||||
override get right(): OptNodeOrNull<TreeMultiMapNode<K, V>> {
|
||||
override get right(): TreeMultiMapNode<K, V> | null | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
override set right(v: OptNodeOrNull<TreeMultiMapNode<K, V>>) {
|
||||
override set right(v: TreeMultiMapNode<K, V> | null | undefined) {
|
||||
if (v) {
|
||||
v.parent = this;
|
||||
}
|
||||
|
@ -77,7 +77,9 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* additional options for configuring the TreeMultiMap instance.
|
||||
*/
|
||||
constructor(
|
||||
keysNodesEntriesOrRaws: Iterable<BTNRep<K, V[], TreeMultiMapNode<K, V>> | R> = [],
|
||||
keysNodesEntriesOrRaws: Iterable<
|
||||
K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | R
|
||||
> = [],
|
||||
options?: TreeMultiMapOptions<K, V[], R>
|
||||
) {
|
||||
super([], { ...options, isMapMode: true });
|
||||
|
@ -124,7 +126,7 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
return new TreeMultiMapNode<K, V>(key, []);
|
||||
}
|
||||
|
||||
override add(node: BTNRep<K, V[], TreeMultiMapNode<K, V>>): boolean;
|
||||
override add(node: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined): boolean;
|
||||
|
||||
override add(key: K, value: V): boolean;
|
||||
|
||||
|
@ -134,7 +136,7 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function `add` in TypeScript overrides the superclass method to add key-value pairs to a
|
||||
* TreeMultiMapNode, handling different input types and scenarios.
|
||||
* @param {BTNRep<K, V[], TreeMultiMapNode<K, V>> | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param {K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `override add` method can be either a `BTNRep` object containing a key, an array
|
||||
* of values, and a `TreeMultiMapNode`, or just a key.
|
||||
* @param {V} [value] - The `value` parameter in the `override add` method represents the value that
|
||||
|
@ -143,7 +145,10 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* @returns The `add` method is returning a boolean value, which indicates whether the operation was
|
||||
* successful or not.
|
||||
*/
|
||||
override add(keyNodeOrEntry: BTNRep<K, V[], TreeMultiMapNode<K, V>> | K, value?: V): boolean {
|
||||
override add(
|
||||
keyNodeOrEntry: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined,
|
||||
value?: V
|
||||
): boolean {
|
||||
if (this.isRealNode(keyNodeOrEntry)) return super.add(keyNodeOrEntry);
|
||||
|
||||
const _commonAdd = (key?: BTNOptKeyOrNull<K>, values?: V[]) => {
|
||||
|
@ -186,7 +191,7 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
*
|
||||
* The function `deleteValue` removes a specific value from a key in a TreeMultiMap data structure
|
||||
* and deletes the entire node if no values are left for that key.
|
||||
* @param {BTNRep<K, V[], TreeMultiMapNode<K, V>> | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* @param {K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined} keyNodeOrEntry - The `keyNodeOrEntry`
|
||||
* parameter in the `deleteValue` function can be either a `BTNRep` object containing a key and an
|
||||
* array of values, or just a key itself.
|
||||
* @param {V} value - The `value` parameter in the `deleteValue` function represents the specific
|
||||
|
@ -196,7 +201,10 @@ export class TreeMultiMap<K = any, V = any, R = object, MK = any, MV = any, MR =
|
|||
* @returns The `deleteValue` function returns a boolean value - `true` if the specified `value` was
|
||||
* successfully deleted from the values associated with the `keyNodeOrEntry`, and `false` otherwise.
|
||||
*/
|
||||
deleteValue(keyNodeOrEntry: BTNRep<K, V[], TreeMultiMapNode<K, V>> | K, value: V): boolean {
|
||||
deleteValue(
|
||||
keyNodeOrEntry: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined,
|
||||
value: V
|
||||
): boolean {
|
||||
const values = this.get(keyNodeOrEntry);
|
||||
if (Array.isArray(values)) {
|
||||
const index = values.indexOf(value);
|
||||
|
|
|
@ -91,7 +91,7 @@ describe('AVLTreeCounter operations test1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(15);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlCounter.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) avlCounter.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(31);
|
||||
let lesserSum = 0;
|
||||
avlCounter.lesserOrGreaterTraverse((node: AVLTreeCounterNode<number>) => (lesserSum += node.key), -1, 10);
|
||||
|
@ -99,7 +99,7 @@ describe('AVLTreeCounter operations test1', () => {
|
|||
|
||||
expect(node15 instanceof AVLTreeCounterNode);
|
||||
if (node15 instanceof AVLTreeCounterNode) {
|
||||
const subTreeAdd = avlCounter.dfs(node => (node.count += 1), 'PRE', 15);
|
||||
const subTreeAdd = avlCounter.dfs(node => (node.count += 1), 'PRE', false, 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = avlCounter.getNode(11);
|
||||
|
@ -347,7 +347,7 @@ describe('AVLTreeCounter operations test recursively1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(15);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlCounter.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) avlCounter.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(31);
|
||||
let lesserSum = 0;
|
||||
avlCounter.lesserOrGreaterTraverse((node: AVLTreeCounterNode<number>) => (lesserSum += node.key), -1, 10);
|
||||
|
@ -355,7 +355,7 @@ describe('AVLTreeCounter operations test recursively1', () => {
|
|||
|
||||
expect(node15 instanceof AVLTreeCounterNode);
|
||||
if (node15 instanceof AVLTreeCounterNode) {
|
||||
const subTreeAdd = avlCounter.dfs(node => (node.count += 1), 'PRE', 15);
|
||||
const subTreeAdd = avlCounter.dfs(node => (node.count += 1), 'PRE', false, 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = avlCounter.getNode(11);
|
||||
|
@ -709,7 +709,7 @@ describe('AVLTreeCounter toEntryFn', () => {
|
|||
|
||||
expect(avlCounter.morris(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', false, avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should toEntryFn 2', () => {
|
||||
|
@ -724,7 +724,7 @@ describe('AVLTreeCounter toEntryFn', () => {
|
|||
|
||||
expect(avlCounter.morris(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', false, avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should toEntryFn throw error', () => {
|
||||
|
@ -760,7 +760,7 @@ describe('AVLTreeCounter toEntryFn', () => {
|
|||
|
||||
expect(avlCounter.morris(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(avlCounter.dfs(node => node.key, 'IN', false, avlCounter.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('AVLTreeMultiMap Test', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -176,7 +176,7 @@ describe('AVLTreeMultiMap Test recursively', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -509,7 +509,7 @@ describe('AVLTreeMultiMap not map mode', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -527,7 +527,6 @@ describe('AVLTreeMultiMap not map mode test recursively', () => {
|
|||
const avlTmm = new AVLTreeMultiMap<number>([], { iterationType: 'RECURSIVE' });
|
||||
|
||||
for (const i of arr) avlTmm.add([i, [i]]);
|
||||
|
||||
const node6 = avlTmm.getNode(6);
|
||||
|
||||
expect(node6 && avlTmm.getHeight(node6)).toBe(3);
|
||||
|
@ -544,7 +543,7 @@ describe('AVLTreeMultiMap not map mode test recursively', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { AVLTree, AVLTreeNode, BinaryTreeNode, BSTNode } from '../../../../src';
|
||||
import { AVLTree, AVLTreeNode, BinaryTreeNode, BSTNode, Range } from '../../../../src';
|
||||
|
||||
describe('AVL Tree Test', () => {
|
||||
it('should perform various operations on a AVL Tree', () => {
|
||||
|
@ -24,7 +24,7 @@ describe('AVL Tree Test', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -150,7 +150,7 @@ describe('AVL Tree Test recursively', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -480,7 +480,7 @@ describe('AVL Tree not map mode', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -515,7 +515,7 @@ describe('AVL Tree not map mode test recursively', () => {
|
|||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) avlTree.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -542,3 +542,70 @@ describe('AVLTree iterative methods not map mode', () => {
|
|||
expect(cloned.get(cloned.root?.right?.key)).toBe('c');
|
||||
});
|
||||
});
|
||||
|
||||
describe('classic use', () => {
|
||||
// Test case for finding elements in a given range
|
||||
it('@example Find elements in a range', () => {
|
||||
type Datum = { timestamp: Date; temperature: number };
|
||||
// Fixed dataset of CPU temperature readings
|
||||
const cpuData: Datum[] = [
|
||||
{ timestamp: new Date('2024-12-02T00:00:00'), temperature: 55.1 },
|
||||
{ timestamp: new Date('2024-12-02T00:01:00'), temperature: 56.3 },
|
||||
{ timestamp: new Date('2024-12-02T00:02:00'), temperature: 54.8 },
|
||||
{ timestamp: new Date('2024-12-02T00:03:00'), temperature: 57.2 },
|
||||
{ timestamp: new Date('2024-12-02T00:04:00'), temperature: 58.0 },
|
||||
{ timestamp: new Date('2024-12-02T00:05:00'), temperature: 59.4 },
|
||||
{ timestamp: new Date('2024-12-02T00:06:00'), temperature: 60.1 },
|
||||
{ timestamp: new Date('2024-12-02T00:07:00'), temperature: 61.3 },
|
||||
{ timestamp: new Date('2024-12-02T00:08:00'), temperature: 62.0 },
|
||||
{ timestamp: new Date('2024-12-02T00:09:00'), temperature: 63.5 },
|
||||
{ timestamp: new Date('2024-12-02T00:10:00'), temperature: 64.0 },
|
||||
{ timestamp: new Date('2024-12-02T00:11:00'), temperature: 62.8 },
|
||||
{ timestamp: new Date('2024-12-02T00:12:00'), temperature: 61.5 },
|
||||
{ timestamp: new Date('2024-12-02T00:13:00'), temperature: 60.2 },
|
||||
{ timestamp: new Date('2024-12-02T00:14:00'), temperature: 59.8 },
|
||||
{ timestamp: new Date('2024-12-02T00:15:00'), temperature: 58.6 },
|
||||
{ timestamp: new Date('2024-12-02T00:16:00'), temperature: 57.4 },
|
||||
{ timestamp: new Date('2024-12-02T00:17:00'), temperature: 56.2 },
|
||||
{ timestamp: new Date('2024-12-02T00:18:00'), temperature: 55.7 },
|
||||
{ timestamp: new Date('2024-12-02T00:19:00'), temperature: 54.5 },
|
||||
{ timestamp: new Date('2024-12-02T00:20:00'), temperature: 53.2 },
|
||||
{ timestamp: new Date('2024-12-02T00:21:00'), temperature: 52.8 },
|
||||
{ timestamp: new Date('2024-12-02T00:22:00'), temperature: 51.9 },
|
||||
{ timestamp: new Date('2024-12-02T00:23:00'), temperature: 50.5 },
|
||||
{ timestamp: new Date('2024-12-02T00:24:00'), temperature: 49.8 },
|
||||
{ timestamp: new Date('2024-12-02T00:25:00'), temperature: 48.7 },
|
||||
{ timestamp: new Date('2024-12-02T00:26:00'), temperature: 47.5 },
|
||||
{ timestamp: new Date('2024-12-02T00:27:00'), temperature: 46.3 },
|
||||
{ timestamp: new Date('2024-12-02T00:28:00'), temperature: 45.9 },
|
||||
{ timestamp: new Date('2024-12-02T00:29:00'), temperature: 45.0 }
|
||||
];
|
||||
|
||||
// Create an AVL tree to store CPU temperature data
|
||||
const cpuTemperatureTree = new AVLTree<Date, number, Datum>(cpuData, {
|
||||
toEntryFn: ({ timestamp, temperature }) => [timestamp, temperature]
|
||||
});
|
||||
|
||||
// Query a specific time range (e.g., from 00:05 to 00:15)
|
||||
const rangeStart = new Date('2024-12-02T00:05:00');
|
||||
const rangeEnd = new Date('2024-12-02T00:15:00');
|
||||
const rangeResults = cpuTemperatureTree.rangeSearch([rangeStart, rangeEnd], node => ({
|
||||
minute: node ? node.key.getMinutes() : 0,
|
||||
temperature: cpuTemperatureTree.get(node ? node.key : undefined)
|
||||
}));
|
||||
|
||||
expect(rangeResults).toEqual( [
|
||||
{ minute: 5, temperature: 59.4 },
|
||||
{ minute: 6, temperature: 60.1 },
|
||||
{ minute: 7, temperature: 61.3 },
|
||||
{ minute: 8, temperature: 62 },
|
||||
{ minute: 9, temperature: 63.5 },
|
||||
{ minute: 10, temperature: 64 },
|
||||
{ minute: 11, temperature: 62.8 },
|
||||
{ minute: 12, temperature: 61.5 },
|
||||
{ minute: 13, temperature: 60.2 },
|
||||
{ minute: 14, temperature: 59.8 },
|
||||
{ minute: 15, temperature: 58.6 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -217,20 +217,20 @@ describe('BinaryTree', () => {
|
|||
expect(cloned.root?.right?.key).toBe(6);
|
||||
expect(cloned.root?.right?.left?.key).toBe(3);
|
||||
expect(cloned.root?.right?.right).toBe(null);
|
||||
expect(cloned.dfs(node => node.key, 'PRE', cloned.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
|
||||
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', cloned.getNode(6), 'ITERATIVE', true)).toEqual([
|
||||
expect(cloned.dfs(node => node.key, 'PRE', false, cloned.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
|
||||
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', false, cloned.getNode(6), 'ITERATIVE', true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
null
|
||||
]);
|
||||
expect(cloned.dfs(node => (node ? node.key : node), 'PRE', cloned.getNode(6), 'ITERATIVE', true)).toEqual([
|
||||
expect(cloned.dfs(node => (node ? node.key : node), 'PRE', false, cloned.getNode(6), 'ITERATIVE', true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
null
|
||||
]);
|
||||
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', cloned.getNode(6), 'RECURSIVE', true)).toEqual([
|
||||
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', false, cloned.getNode(6), 'RECURSIVE', true)).toEqual([
|
||||
6,
|
||||
3,
|
||||
7,
|
||||
|
@ -532,11 +532,11 @@ describe('BinaryTree', () => {
|
|||
expect(binTree.dfs()).toEqual([]);
|
||||
expect([...binTree.values()]).toEqual([]);
|
||||
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
||||
expect(binTree.dfs(node => node.key, 'PRE', undefined, 'ITERATIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', undefined, 'ITERATIVE', false)).toEqual([
|
||||
4, 2, 1, 5, 6, 3, 7
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', undefined, 'ITERATIVE', true)).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'PRE', false, undefined, 'ITERATIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'ITERATIVE', false)).toEqual(
|
||||
[4, 2, 1, 5, 6, 3, 7]
|
||||
);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'ITERATIVE', true)).toEqual([
|
||||
4,
|
||||
2,
|
||||
null,
|
||||
|
@ -549,11 +549,11 @@ describe('BinaryTree', () => {
|
|||
null
|
||||
]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'PRE', undefined, 'RECURSIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', undefined, 'RECURSIVE', false)).toEqual([
|
||||
4, 2, 1, 5, 6, 3, 7
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', undefined, 'RECURSIVE', true)).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'PRE', false, undefined, 'RECURSIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'RECURSIVE', false)).toEqual(
|
||||
[4, 2, 1, 5, 6, 3, 7]
|
||||
);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'RECURSIVE', true)).toEqual([
|
||||
4,
|
||||
2,
|
||||
null,
|
||||
|
@ -566,11 +566,11 @@ describe('BinaryTree', () => {
|
|||
null
|
||||
]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'IN', undefined, 'ITERATIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', undefined, 'ITERATIVE', false)).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, undefined, 'ITERATIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'ITERATIVE', false)).toEqual([
|
||||
2, 5, 1, 4, 7, 3, 6
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', undefined, 'ITERATIVE', true)).toEqual([
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'ITERATIVE', true)).toEqual([
|
||||
null,
|
||||
2,
|
||||
5,
|
||||
|
@ -583,11 +583,11 @@ describe('BinaryTree', () => {
|
|||
null
|
||||
]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'IN', undefined, 'RECURSIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', undefined, 'RECURSIVE', false)).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, undefined, 'RECURSIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'RECURSIVE', false)).toEqual([
|
||||
2, 5, 1, 4, 7, 3, 6
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', undefined, 'RECURSIVE', true)).toEqual([
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'RECURSIVE', true)).toEqual([
|
||||
null,
|
||||
2,
|
||||
5,
|
||||
|
@ -600,89 +600,71 @@ describe('BinaryTree', () => {
|
|||
null
|
||||
]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'POST', undefined, 'ITERATIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', undefined, 'ITERATIVE', false)).toEqual([
|
||||
5, 1, 2, 7, 3, 6, 4
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', undefined, 'ITERATIVE', true)).toEqual([
|
||||
null,
|
||||
5,
|
||||
null,
|
||||
1,
|
||||
2,
|
||||
7,
|
||||
3,
|
||||
null,
|
||||
6,
|
||||
4
|
||||
]);
|
||||
expect(binTree.dfs(node => node.key, 'POST', false, undefined, 'ITERATIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'ITERATIVE', false)
|
||||
).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'ITERATIVE', true)).toEqual(
|
||||
[null, 5, null, 1, 2, 7, 3, null, 6, 4]
|
||||
);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'POST', undefined, 'RECURSIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', undefined, 'RECURSIVE', false)).toEqual([
|
||||
5, 1, 2, 7, 3, 6, 4
|
||||
]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', undefined, 'RECURSIVE', true)).toEqual([
|
||||
null,
|
||||
5,
|
||||
null,
|
||||
1,
|
||||
2,
|
||||
7,
|
||||
3,
|
||||
null,
|
||||
6,
|
||||
4
|
||||
]);
|
||||
expect(binTree.dfs(node => node.key, 'POST', false, undefined, 'RECURSIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'RECURSIVE', false)
|
||||
).toEqual([5, 1, 2, 7, 3, 6, 4]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'RECURSIVE', true)).toEqual(
|
||||
[null, 5, null, 1, 2, 7, 3, null, 6, 4]
|
||||
);
|
||||
});
|
||||
|
||||
it('should sub binTree traverse', () => {
|
||||
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
||||
expect(binTree.dfs(node => node.key, 'PRE', binTree.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
|
||||
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', binTree.getNode(6), 'ITERATIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'ITERATIVE', false)
|
||||
).toEqual([6, 3, 7]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', binTree.getNode(6), 'ITERATIVE', true)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'ITERATIVE', true)
|
||||
).toEqual([6, 3, 7, null]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'PRE', binTree.getNode(6), 'RECURSIVE')).toEqual([6, 3, 7]);
|
||||
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.getNode(6), 'RECURSIVE')).toEqual([6, 3, 7]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', binTree.getNode(6), 'RECURSIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'RECURSIVE', false)
|
||||
).toEqual([6, 3, 7]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', binTree.getNode(6), 'RECURSIVE', true)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'RECURSIVE', true)
|
||||
).toEqual([6, 3, 7, null]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', binTree.getNode(6), 'ITERATIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'ITERATIVE', false)
|
||||
).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', binTree.getNode(6), 'ITERATIVE', true)).toEqual(
|
||||
[7, 3, 6, null]
|
||||
);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'ITERATIVE', true)
|
||||
).toEqual([7, 3, 6, null]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', binTree.getNode(6), 'RECURSIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'RECURSIVE', false)
|
||||
).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', binTree.getNode(6), 'RECURSIVE', true)).toEqual(
|
||||
[7, 3, 6, null]
|
||||
);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'RECURSIVE', true)
|
||||
).toEqual([7, 3, 6, null]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'POST', binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => node.key, 'POST', false, binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', binTree.getNode(6), 'ITERATIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'ITERATIVE', false)
|
||||
).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', binTree.getNode(6), 'ITERATIVE', true)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'ITERATIVE', true)
|
||||
).toEqual([7, 3, null, 6]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'POST', binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
|
||||
expect(binTree.dfs(node => node.key, 'POST', false, binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', binTree.getNode(6), 'RECURSIVE', false)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'RECURSIVE', false)
|
||||
).toEqual([7, 3, 6]);
|
||||
expect(
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', binTree.getNode(6), 'RECURSIVE', true)
|
||||
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'RECURSIVE', true)
|
||||
).toEqual([7, 3, null, 6]);
|
||||
});
|
||||
|
||||
|
@ -814,7 +796,7 @@ describe('BinaryTree Morris Traversal', () => {
|
|||
|
||||
expect(result).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should perform pre-order Morris traversal correctly as dfs traversal', () => {
|
||||
|
@ -875,7 +857,7 @@ describe('BinaryTree toEntryFn', () => {
|
|||
|
||||
expect(binTree.morris(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should toEntryFn with initial', () => {
|
||||
|
@ -890,7 +872,7 @@ describe('BinaryTree toEntryFn', () => {
|
|||
|
||||
expect(binTree.morris(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should no toEntryFn', () => {
|
||||
|
@ -905,7 +887,7 @@ describe('BinaryTree toEntryFn', () => {
|
|||
|
||||
expect(binTree.morris(node => node.key, 'IN')).toEqual(data.sort((a, b) => a.obj.id - b.obj.id));
|
||||
expect(binTree.dfs(node => node.key, 'IN')).toEqual(data);
|
||||
expect(binTree.dfs(node => node.key, 'IN', binTree.root, 'RECURSIVE')).toEqual(data);
|
||||
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -953,19 +935,21 @@ describe('BinaryTree traversals', () => {
|
|||
);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'PRE')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]);
|
||||
expect(binTree.dfs(node => node.key, 'PRE', binTree.root, 'RECURSIVE')).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.root, 'RECURSIVE')).toEqual([
|
||||
35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55
|
||||
]);
|
||||
expect(
|
||||
binTree.dfs(node => node, 'PRE', binTree.root, 'ITERATIVE', true).map(node => (node === null ? null : node.key))
|
||||
binTree
|
||||
.dfs(node => node, 'PRE', false, binTree.root, 'ITERATIVE', true)
|
||||
.map(node => (node === null ? null : node.key))
|
||||
).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]);
|
||||
expect(
|
||||
binTree.dfs(node => node, 'PRE', binTree.root, 'RECURSIVE', true).map(node => (node ? node.key : null))
|
||||
binTree.dfs(node => node, 'PRE', false, binTree.root, 'RECURSIVE', true).map(node => (node ? node.key : null))
|
||||
).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]);
|
||||
|
||||
expect(binTree.dfs(node => node.key, 'IN')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]);
|
||||
expect(binTree.dfs(node => node.key, 'POST')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]);
|
||||
expect(binTree.dfs(node => node.key, 'POST', binTree.root, 'RECURSIVE')).toEqual([
|
||||
expect(binTree.dfs(node => node.key, 'POST', false, binTree.root, 'RECURSIVE')).toEqual([
|
||||
16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35
|
||||
]);
|
||||
expect(binTree.bfs(node => node.key, binTree.root, 'RECURSIVE')).toEqual([
|
||||
|
|
|
@ -90,7 +90,7 @@ describe('BST operations test', () => {
|
|||
expect(nodes.map(node => node.key)).toEqual([15]);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -299,7 +299,7 @@ describe('BST operations test', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -492,7 +492,7 @@ describe('BST operations test', () => {
|
|||
|
||||
it('should search in range', () => {
|
||||
const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
|
||||
expect(bst.rangeSearch([4, 12])).toEqual([10, 12, 5, 7]);
|
||||
expect(bst.rangeSearch([4, 12])).toEqual([5, 7, 10, 12]);
|
||||
expect(() => bst.rangeSearch([12, 4])).toThrow('low must be less than or equal to high');
|
||||
expect(bst.rangeSearch([12, 12])).toEqual([12]);
|
||||
});
|
||||
|
@ -535,7 +535,7 @@ describe('BST operations test recursively', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -742,7 +742,7 @@ describe('BST operations test recursively', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', node15);
|
||||
if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
||||
let lesserSum = 0;
|
||||
|
@ -1080,10 +1080,10 @@ describe('BST Performance test', function () {
|
|||
it('should dfs as sub tree traversal, null should be ignored', () => {
|
||||
const bst = new BST();
|
||||
bst.addMany([4, 2, 6, 1, 3, 5, 7]);
|
||||
expect(bst.dfs(node => node.key, 'PRE', bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node.key, 'PRE', bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'PRE', bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'PRE', bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node.key, 'PRE', false, bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node.key, 'PRE', false, bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'PRE', false, bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
|
||||
expect(bst.dfs(node => node?.key ?? undefined, 'PRE', false, bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1565,9 +1565,9 @@ describe('classic use', () => {
|
|||
// Test case for finding elements in a given range
|
||||
it('@example Find elements in a range', () => {
|
||||
const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
|
||||
expect(bst.search(new Range(5, 10))).toEqual([10, 5, 7]);
|
||||
expect(bst.rangeSearch([4, 12], node => node.key.toString())).toEqual(['10', '12', '5', '7']);
|
||||
expect(bst.search(new Range(4, 12, true, false))).toEqual([10, 5, 7]);
|
||||
expect(bst.search(new Range(5, 10))).toEqual([5, 7, 10]);
|
||||
expect(bst.rangeSearch([4, 12], node => node.key.toString())).toEqual(['5', '7', '10', '12']);
|
||||
expect(bst.search(new Range(4, 12, true, false))).toEqual([5, 7, 10]);
|
||||
expect(bst.rangeSearch([15, 20])).toEqual([15, 18]);
|
||||
expect(bst.search(new Range(15, 20, false))).toEqual([18]);
|
||||
});
|
||||
|
|
|
@ -504,11 +504,11 @@ describe('RedBlackTree 2', () => {
|
|||
expect(rbTree.isBST()).toBe(true);
|
||||
expect(rbTree.isBST(rbTree.root, 'RECURSIVE')).toBe(true);
|
||||
|
||||
expect(rbTree.dfs(n => n.key, 'IN', rbTree.root, 'ITERATIVE')).toEqual([
|
||||
expect(rbTree.dfs(n => n.key, 'IN', false, rbTree.root, 'ITERATIVE')).toEqual([
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
|
||||
]);
|
||||
expect(rbTree.dfs(n => n.key, 'IN', rbTree.root, 'RECURSIVE')).toEqual([
|
||||
expect(rbTree.dfs(n => n.key, 'IN', false, rbTree.root, 'RECURSIVE')).toEqual([
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
|
||||
]);
|
||||
|
@ -524,7 +524,7 @@ describe('RedBlackTree 2', () => {
|
|||
|
||||
expect(rbTree.size).toBe(0);
|
||||
expect(rbTree.isBST()).toBe(true);
|
||||
expect(rbTree.dfs(n => n.key, 'IN', rbTree.root, 'ITERATIVE')).toEqual([]);
|
||||
expect(rbTree.dfs(n => n.key, 'IN', false, rbTree.root, 'ITERATIVE')).toEqual([]);
|
||||
|
||||
rbTree.clear();
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
|
@ -838,14 +838,6 @@ describe('real world data', () => {
|
|||
});
|
||||
|
||||
describe('classic use', () => {
|
||||
// Test case for finding elements in a given range
|
||||
it('@example Find elements in a range', () => {
|
||||
const bst = new RedBlackTree<number>([10, 5, 15, 3, 7, 12, 18]);
|
||||
expect(bst.search(new Range(5, 10))).toEqual([5, 10, 7]);
|
||||
expect(bst.search(new Range(4, 12))).toEqual([5, 10, 12, 7]);
|
||||
expect(bst.search(new Range(15, 20))).toEqual([15, 18]);
|
||||
});
|
||||
|
||||
it('@example using Red-Black Tree as a price-based index for stock data', () => {
|
||||
// Define the structure of individual stock records
|
||||
interface StockRecord {
|
||||
|
@ -887,6 +879,6 @@ describe('classic use', () => {
|
|||
[200, 400], // Price range
|
||||
node => priceIndex.get(node)?.symbol // Extract stock symbols for the result
|
||||
);
|
||||
expect(stocksInRange).toEqual(['GOOGL', 'MSFT', 'META']); // Verify stocks in the range
|
||||
expect(stocksInRange).toEqual(['GOOGL', 'META', 'MSFT']); // Verify stocks in the range
|
||||
});
|
||||
});
|
||||
|
|
|
@ -149,7 +149,7 @@ describe('TreeCounter operations test1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(14);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) treeCounter.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) treeCounter.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(45);
|
||||
let lesserSum = 0;
|
||||
treeCounter.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
|
||||
|
@ -157,7 +157,7 @@ describe('TreeCounter operations test1', () => {
|
|||
|
||||
expect(node15 instanceof TreeCounterNode);
|
||||
if (node15 instanceof TreeCounterNode) {
|
||||
const subTreeAdd = treeCounter.dfs(node => (node.count += 1), 'PRE', 15);
|
||||
const subTreeAdd = treeCounter.dfs(node => (node.count += 1), 'PRE', false, 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = treeCounter.getNode(11);
|
||||
|
@ -407,7 +407,7 @@ describe('TreeCounter operations test recursively1', () => {
|
|||
expect(minNodeBySpecificNode?.key).toBe(14);
|
||||
|
||||
let subTreeSum = 0;
|
||||
if (node15) treeCounter.dfs(node => (subTreeSum += node.key), 'PRE', 15);
|
||||
if (node15) treeCounter.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
|
||||
expect(subTreeSum).toBe(45);
|
||||
let lesserSum = 0;
|
||||
expect(treeCounter.has(9)).toBe(true);
|
||||
|
@ -423,7 +423,7 @@ describe('TreeCounter operations test recursively1', () => {
|
|||
|
||||
expect(node15 instanceof TreeCounterNode);
|
||||
if (node15 instanceof TreeCounterNode) {
|
||||
const subTreeAdd = treeCounter.dfs(node => (node.count += 1), 'PRE', 15);
|
||||
const subTreeAdd = treeCounter.dfs(node => (node.count += 1), 'PRE', false, 15);
|
||||
expect(subTreeAdd);
|
||||
}
|
||||
const node11 = treeCounter.getNode(11);
|
||||
|
|
|
@ -519,11 +519,11 @@ describe('TreeMultiMap 2', () => {
|
|||
expect(tmm.isBST()).toBe(true);
|
||||
expect(tmm.isBST(tmm.root, 'RECURSIVE')).toBe(true);
|
||||
|
||||
expect(tmm.dfs(n => n.key, 'IN', tmm.root, 'ITERATIVE')).toEqual([
|
||||
expect(tmm.dfs(n => n.key, 'IN', false, tmm.root, 'ITERATIVE')).toEqual([
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
|
||||
]);
|
||||
expect(tmm.dfs(n => n.key, 'IN', tmm.root, 'RECURSIVE')).toEqual([
|
||||
expect(tmm.dfs(n => n.key, 'IN', false, tmm.root, 'RECURSIVE')).toEqual([
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
|
||||
]);
|
||||
|
@ -539,7 +539,7 @@ describe('TreeMultiMap 2', () => {
|
|||
|
||||
expect(tmm.size).toBe(0);
|
||||
expect(tmm.isBST()).toBe(true);
|
||||
expect(tmm.dfs(n => n.key, 'IN', tmm.root, 'ITERATIVE')).toEqual([]);
|
||||
expect(tmm.dfs(n => n.key, 'IN', false, tmm.root, 'ITERATIVE')).toEqual([]);
|
||||
|
||||
tmm.clear();
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
|
@ -840,8 +840,8 @@ describe('classic use', () => {
|
|||
// Test case for finding elements in a given range
|
||||
it('@example Find elements in a range', () => {
|
||||
const tmm = new TreeMultiMap<number>([10, 5, 15, 3, 7, 12, 18]);
|
||||
expect(tmm.search(new Range(5, 10))).toEqual([5, 10, 7]);
|
||||
expect(tmm.search(new Range(4, 12))).toEqual([5, 10, 12, 7]);
|
||||
expect(tmm.search(new Range(5, 10))).toEqual([5, 7, 10]);
|
||||
expect(tmm.search(new Range(4, 12))).toEqual([5, 7, 10, 12]);
|
||||
expect(tmm.search(new Range(15, 20))).toEqual([15, 18]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue