feat: Perfectly implement fast conversion between data structures. Implement a getter size for Trie. docs: Add comments to the 'add' and 'addMany' methods of all binary tree data structures.

This commit is contained in:
Revone 2023-11-25 22:32:09 +08:00
parent 76db084bda
commit f9f9df81f5
9 changed files with 303 additions and 159 deletions

View file

@ -27,15 +27,28 @@ export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNeste
}
}
/**
* 1. Height-Balanced: Each node's left and right subtrees differ in height by no more than one.
* 2. Automatic Rebalancing: AVL trees rebalance themselves automatically during insertions and deletions.
* 3. Rotations for Balancing: Utilizes rotations (single or double) to maintain balance after updates.
* 4. Order Preservation: Maintains the binary search tree property where left child values are less than the parent, and right child values are greater.
* 5. Efficient Lookups: Offers O(log n) search time, where 'n' is the number of nodes, due to its balanced nature.
* 6. Complex Insertions and Deletions: Due to rebalancing, these operations are more complex than in a regular BST.
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes.
* 8. Memory Overhead: Stores balance factors (or heights) at each node, leading to slightly higher memory usage compared to a regular BST.
*/
export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>, TREE extends AVLTree<V, N, TREE> = AVLTree<V, N, AVLTreeNested<V, N>>>
extends BST<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
/**
* This is a constructor function for an AVL tree data structure in TypeScript.
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
* constructor of the AVLTree class. It allows you to customize the behavior of the AVL tree by providing different
* options.
* The constructor function initializes an AVLTree object with optional elements and options.
* @param [elements] - The `elements` parameter is an optional iterable of `BTNodeExemplar<V, N>`
* objects. It represents a collection of elements that will be added to the AVL tree during
* initialization.
* @param [options] - The `options` parameter is an optional object that allows you to customize the
* behavior of the AVL tree. It is of type `Partial<AVLTreeOptions>`, which means that you can
* provide only a subset of the properties defined in the `AVLTreeOptions` interface.
*/
constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<AVLTreeOptions>) {
super([], options);
@ -55,6 +68,13 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
return new AVLTreeNode<V, N>(key, value) as N;
}
/**
* The function creates a new AVL tree with the specified options and returns it.
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be
* passed to the `createTree` function. It is used to customize the behavior of the AVL tree that is
* being created.
* @returns a new AVLTree object.
*/
override createTree(options?: AVLTreeOptions): TREE {
return new AVLTree<V, N, TREE>([], {
iterationType: this.iterationType,
@ -62,17 +82,20 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
}) as TREE;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*
* The function overrides the add method of a class, adds a key-value pair to a data structure, and
* balances the structure if necessary.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be of type
* `BTNKey`, `N`, `null`, or `undefined`.
* @param {V} [value] - The `value` parameter is the value associated with the key that is being
* added to the binary search tree.
* @returns The method is returning either a node (N) or undefined.
* The function overrides the add method of a binary tree node and balances the tree after inserting
* a new node.
* @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be either a key, a node, or an
* entry.
* @returns The method is returning either the inserted node or `undefined`.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | undefined {
if (keyOrNodeOrEntry === null) return undefined;

View file

@ -34,26 +34,12 @@ import { Queue } from '../queue';
* @template N - The type of the family relationship in the binary tree.
*/
export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>> {
/**
* The key associated with the node.
*/
key: BTNKey;
/**
* The value stored in the node.
*/
value?: V;
/**
* The parent node of the current node.
*/
parent?: N;
/**
* Creates a new instance of BinaryTreeNode.
* @param {BTNKey} key - The key associated with the node.
* @param {V} value - The value stored in the node.
*/
constructor(key: BTNKey, value?: V) {
this.key = key;
this.value = value;
@ -61,17 +47,10 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
protected _left?: N | null;
/**
* Get the left child node.
*/
get left(): N | null | undefined {
return this._left;
}
/**
* Set the left child node.
* @param {N | null | undefined} v - The left child node.
*/
set left(v: N | null | undefined) {
if (v) {
v.parent = this as unknown as N;
@ -81,17 +60,10 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
protected _right?: N | null;
/**
* Get the right child node.
*/
get right(): N | null | undefined {
return this._right;
}
/**
* Set the right child node.
* @param {N | null | undefined} v - The right child node.
*/
set right(v: N | null | undefined) {
if (v) {
v.parent = this as unknown as N;
@ -120,8 +92,15 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
}
/**
* Represents a binary tree data structure.
* @template N - The type of the binary tree's nodes.
* 1. Two Children Maximum: Each node has at most two children.
* 2. Left and Right Children: Nodes have distinct left and right children.
* 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree.
* 4. Subtrees: Each child of a node forms the root of a subtree.
* 5. Leaf Nodes: Nodes without children are leaves.
* 6. Internal Nodes: Nodes with at least one child are internal.
* 7. Balanced Trees: The heights of the left and right subtrees of any node differ by no more than one.
* 8. Full Trees: Every node has either 0 or 2 children.
* 9. Complete Trees: All levels are fully filled except possibly the last, filled from left to right.
*/
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>, TREE extends BinaryTree<V, N, TREE> = BinaryTree<V, N, BinaryTreeNested<V, N>>>
implements IBinaryTree<V, N, TREE> {
@ -129,8 +108,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = IterationType.ITERATIVE
/**
* Creates a new instance of BinaryTree.
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
* The constructor function initializes a binary tree object with optional elements and options.
* @param [elements] - An optional iterable of BTNodeExemplar objects. These objects represent the
* elements to be added to the binary tree.
* @param [options] - The `options` parameter is an optional object that can contain additional
* configuration options for the binary tree. In this case, it is of type
* `Partial<BinaryTreeOptions>`, which means that not all properties of `BinaryTreeOptions` are
* required.
*/
constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<BinaryTreeOptions>) {
@ -148,18 +132,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
protected _root?: N | null;
/**
* Get the root node of the binary tree.
*/
get root(): N | null | undefined {
return this._root;
}
protected _size: number;
/**
* Get the number of nodes in the binary tree.
*/
get size(): number {
return this._size;
}
@ -174,28 +152,44 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return new BinaryTreeNode<V, N>(key, value) as N;
}
/**
* The function creates a binary tree with the given options.
* @param [options] - The `options` parameter is an optional object that allows you to customize the
* behavior of the `BinaryTree` class. It is of type `Partial<BinaryTreeOptions>`, which means that
* you can provide only a subset of the properties defined in the `BinaryTreeOptions` interface.
* @returns a new instance of a binary tree.
*/
createTree(options?: Partial<BinaryTreeOptions>): TREE {
return new BinaryTree<V, N, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
}
/**
* The function checks if a given value is an entry in a binary tree node.
* @param kne - BTNodeExemplar<V, N> - A generic type representing a node in a binary tree. It has
* two type parameters V and N, representing the value and node type respectively.
* @returns a boolean value.
*/
isEntry(kne: BTNodeExemplar<V, N>): kne is BTNodeEntry<V> {
return Array.isArray(kne) && kne.length === 2;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
* Time Complexity O(log n) - O(n)
* Space Complexity O(1)
*/
/**
* Time Complexity O(log n) - O(n)
* Space Complexity O(1)
*
* The `add` function adds a new node with a key and value to a binary tree, or updates the value of
* an existing node with the same key.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be one of the
* following types:
* @param {V} [value] - The value to be associated with the key or node being added to the binary
* tree.
* @returns The function `add` returns a node (`N`) if it was successfully inserted into the binary
* tree, or `null` or `undefined` if the insertion was not successful.
* The `add` function adds a new node to a binary tree, either by key or by providing a node object.
* @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be one of the following:
* @returns The function `add` returns the inserted node (`N`), `null`, or `undefined`.
*/
add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | null | undefined {
let inserted: N | null | undefined, needInsert: N | null | undefined;
const _bfs = (root: N, newNode: N | null): N | undefined | null => {
const queue = new Queue<N>([root]);
while (queue.size > 0) {
@ -211,8 +205,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
};
let inserted: N | null | undefined, needInsert: N | null | undefined;
if (keyOrNodeOrEntry === null) {
needInsert = null;
} else if (this.isNodeKey(keyOrNodeOrEntry)) {
@ -247,24 +239,22 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
/**
* Time Complexity: O(n)
* Time Complexity: O(k log n) - O(k * n)
* Space Complexity: O(1)
* Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
*/
/**
* Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
* Time Complexity: O(k log n) - O(k * n)
* Space Complexity: O(1)
*
* The `addMany` function takes an array of keys or nodes and an optional array of values, and adds
* each key-value pair to a data structure.
* @param {(BTNKey | N |null | undefined)[]} keysOrNodes - An array of keys or nodes to be added to
* the binary search tree. Each element can be of type `BTNKey` (a key value), `N` (a node), `null`,
* or `undefined`.
* @param {(V | undefined)[]} [values] - The `values` parameter is an optional array of values that
* correspond to the keys or nodes being added. If provided, the values will be associated with the
* keys or nodes during the add operation.
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
* The function `addMany` takes in an iterable of `BTNodeExemplar` objects, adds each object to the
* current instance, and returns an array of the inserted nodes.
* @param nodes - The `nodes` parameter is an iterable (such as an array or a set) of
* `BTNodeExemplar<V, N>` objects.
* @returns The function `addMany` returns an array of values, where each value is either of type
* `N`, `null`, or `undefined`.
*/
addMany(nodes: Iterable<BTNodeExemplar<V, N>>): (N | null | undefined)[] {
// TODO not sure addMany not be run multi times
@ -284,13 +274,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
* Space Complexity: O(1)
*
* The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data.
* @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either
* `BTNKey` or `N` values.
* @param {N[] | Array<V>} [values] - The `data` parameter is an optional array of values that will be assigned to
* the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes`
* array. Each value in the `data` array will be assigned to the
* @returns The method is returning a boolean value.
* The `refill` function clears the current collection and adds new nodes, keys, or entries to it.
* @param nodesOrKeysOrEntries - The parameter `nodesOrKeysOrEntries` is an iterable object that can
* contain either `BTNodeExemplar` objects, keys, or entries.
*/
refill(nodesOrKeysOrEntries: Iterable<BTNodeExemplar<V, N>>): void {
this.clear();
@ -1939,6 +1925,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return undefined;
}
/**
* The function replaces an old node with a new node in a binary tree.
* @param {N} oldNode - The oldNode parameter represents the node that needs to be replaced in the
* tree.
* @param {N} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the
* tree.
* @returns The method is returning the newNode.
*/
protected _replaceNode(oldNode: N, newNode: N): N {
if (oldNode.parent) {
if (oldNode.parent.left === oldNode) {

View file

@ -72,11 +72,28 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
}
}
/**
* 1. Node Order: Each node's left child has a lesser value, and the right child has a greater value.
* 2. Unique Keys: No duplicate keys in a standard BST.
* 3. Efficient Search: Enables quick search, minimum, and maximum operations.
* 4. Inorder Traversal: Yields nodes in ascending order.
* 5. Logarithmic Operations: Ideal operations like insertion, deletion, and searching are O(log n) time-efficient.
* 6. Balance Variability: Can become unbalanced; special types maintain balance.
* 7. No Auto-Balancing: Standard BSTs don't automatically balance themselves.
*/
export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>, TREE extends BST<V, N, TREE> = BST<V, N, BSTNested<V, N>>>
extends BinaryTree<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
/**
* This is the constructor function for a binary search tree class in TypeScript, which initializes
* the tree with optional elements and options.
* @param [elements] - An optional iterable of BTNodeExemplar objects that will be added to the
* binary search tree.
* @param [options] - The `options` parameter is an optional object that can contain additional
* configuration options for the binary search tree. It can have the following properties:
*/
constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<BSTOptions>) {
super([], options);
@ -94,9 +111,6 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
protected override _root?: N;
/**
* Get the root node of the binary tree.
*/
override get root(): N | undefined {
return this._root;
}
@ -115,6 +129,13 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return new BSTNode<V, N>(key, value) as N;
}
/**
* The function creates a new binary search tree with the specified options.
* @param [options] - The `options` parameter is an optional object that allows you to customize the
* behavior of the `createTree` method. It accepts a partial `BSTOptions` object, which is a type
* that defines various options for creating a binary search tree.
* @returns a new instance of the BST class with the specified options.
*/
override createTree(options?: Partial<BSTOptions>): TREE {
return new BST<V, N, TREE>([], {
iterationType: this.iterationType,
@ -122,17 +143,20 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}) as TREE;
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
* Space Complexity: O(1) - Constant space is used.
*/
/**
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
* Space Complexity: O(1) - Constant space is used.
*
* The `add` function adds a new node to a binary search tree based on the provided key and value.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be one of the
* following types:
* @param {V} [value] - The `value` parameter is an optional value that can be associated with the
* key or node being added to the binary search tree.
* @returns The method `add` returns a node (`N`) that was inserted into the binary search tree. If
* no node was inserted, it returns `undefined`.
* The `add` function adds a new node to a binary search tree, either by key or by providing a node
* object.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following:
* @returns The method returns either the newly added node (`newNode`) or `undefined` if the input
* (`keyOrNodeOrEntry`) is null, undefined, or does not match any of the expected types.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | undefined {
if (keyOrNodeOrEntry === null || keyOrNodeOrEntry === undefined) {
@ -198,29 +222,25 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
* Space Complexity: O(1) - Constant space is used.
* Time Complexity: O(k log n) - Adding each element individually in a balanced tree.
* Space Complexity: O(k) - Additional space is required for the sorted array.
*/
/**
* Time Complexity: O(n log n) - Adding each element individually in a balanced tree.
* Space Complexity: O(n) - Additional space is required for the sorted array.
* Time Complexity: O(k log n) - Adding each element individually in a balanced tree.
* Space Complexity: O(k) - Additional space is required for the sorted array.
*
* The `addMany` function is used to efficiently add multiple keys or nodes with corresponding data
* to a binary search tree.
* @param {(BTNKey | N | undefined)[]} keysOrNodes - An array of keys or nodes to be added to the
* binary search tree. Each element can be of type `BTNKey` (binary tree node key), `N` (binary tree
* node), or `undefined`.
* @param {(V | undefined)[]} [data] - An optional array of values to associate with the keys or
* nodes being added. If provided, the length of the `data` array must be the same as the length of
* the `keysOrNodes` array.
* The `addMany` function in TypeScript adds multiple nodes to a binary tree, either in a balanced or
* unbalanced manner, and returns an array of the inserted nodes.
* @param keysOrNodesOrEntries - An iterable containing keys, nodes, or entries to be added to the
* binary tree.
* @param [isBalanceAdd=true] - A boolean flag indicating whether the tree should be balanced after
* adding the nodes. The default value is `true`.
* adding the nodes. The default value is true.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to use when adding multiple keys or nodes to the binary search tree. It has a
* default value of `this.iterationType`, which means it will use the iteration type specified in the
* current instance of the binary search tree
* @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values.
* type of iteration to use when adding multiple keys or nodes to the binary tree. It has a default
* value of `this.iterationType`, which means it will use the iteration type specified by the binary
* tree instance.
* @returns The `addMany` function returns an array of `N` or `undefined` values.
*/
override addMany(
keysOrNodesOrEntries: Iterable<BTNodeExemplar<V, N>>,

View file

@ -46,11 +46,16 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
implements IBinaryTree<V, N, TREE> {
Sentinel: N = new RedBlackTreeNode<V>(NaN) as unknown as N;
/**
* The constructor function initializes a Red-Black Tree with an optional set of options.
* @param {RBTreeOptions} [options] - The `options` parameter is an optional object that can be
* passed to the constructor. It is used to configure the RBTree object with specific options.
* This is the constructor function for a Red-Black Tree data structure in TypeScript, which
* initializes the tree with optional elements and options.
* @param [elements] - The `elements` parameter is an optional iterable of `BTNodeExemplar<V, N>`
* objects. It represents the initial elements that will be added to the RBTree during its
* construction. If this parameter is provided, the `addMany` method is called to add all the
* elements to the
* @param [options] - The `options` parameter is an optional object that allows you to customize the
* behavior of the RBTree. It is of type `Partial<RBTreeOptions>`, which means that you can provide
* only a subset of the properties defined in the `RBTreeOptions` interface.
*/
constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<RBTreeOptions>) {
super([], options);
@ -71,10 +76,29 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
return this._size;
}
/**
* The function creates a new Red-Black Tree node with the specified key, value, and color.
* @param {BTNKey} key - The key parameter is the key value associated with the node. It is used to
* identify and compare nodes in the Red-Black Tree.
* @param {V} [value] - The `value` parameter is an optional parameter that represents the value
* associated with the node. It is of type `V`, which is a generic type that can be replaced with any
* specific type when using the `createNode` method.
* @param {RBTNColor} color - The "color" parameter is used to specify the color of the node in a
* Red-Black Tree. It can be either "RED" or "BLACK". By default, the color is set to "BLACK".
* @returns The method is returning a new instance of a RedBlackTreeNode with the specified key,
* value, and color.
*/
override createNode(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK): N {
return new RedBlackTreeNode<V, N>(key, value, color) as N;
}
/**
* The function creates a Red-Black Tree with the specified options and returns it.
* @param {RBTreeOptions} [options] - The `options` parameter is an optional object that can be
* passed to the `createTree` function. It is used to customize the behavior of the `RedBlackTree`
* class.
* @returns a new instance of a RedBlackTree object.
*/
override createTree(options?: RBTreeOptions): TREE {
return new RedBlackTree<V, N, TREE>([], {
iterationType: this.iterationType,
@ -85,13 +109,14 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*
* The `add` function adds a new node to a Red-Black Tree data structure.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be one of the
* following types:
* @param {V} [value] - The `value` parameter is an optional value that can be associated with the
* key in the node being added to the Red-Black Tree.
* @returns The method returns either a node (`N`) or `undefined`.
*/
/**
* The function adds a node to a Red-Black Tree data structure.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following:
* @returns The method `add` returns either an instance of `N` (the node that was added) or
* `undefined`.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | undefined {
let node: N;
@ -270,6 +295,11 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
iterationType?: IterationType
): N | undefined;
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
@ -593,6 +623,15 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
this.root.color = RBTNColor.BLACK;
}
/**
* The function replaces an old node with a new node while preserving the color of the old node.
* @param {N} oldNode - The `oldNode` parameter represents the node that needs to be replaced in a
* data structure. It is of type `N`, which is the type of the nodes in the data structure.
* @param {N} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the
* data structure.
* @returns The method is returning the result of calling the `_replaceNode` method from the
* superclass, passing in the `oldNode` and `newNode` as arguments.
*/
protected _replaceNode(oldNode: N, newNode: N): N {
newNode.color = oldNode.color;

View file

@ -46,12 +46,6 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
extends AVLTree<V, N, TREE>
implements IBinaryTree<V, N, TREE> {
/**
* The constructor function for a TreeMultimap class in TypeScript, which extends another class and sets an option to
* merge duplicated values.
* @param {TreeMultimapOptions} [options] - An optional object that contains additional configuration options for the
* TreeMultimap.
*/
constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<TreeMultimapOptions>) {
super([], options);
if (elements) this.addMany(elements);
@ -86,19 +80,22 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}) as TREE;
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*
* The `add` function adds a new node to the tree multimap, updating the count if the key already
* exists, and balances the tree if necessary.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be one of the
* following types:
* @param {V} [value] - The `value` parameter represents the value associated with the key that is
* being added to the tree. It is an optional parameter, so it can be omitted if not needed.
* The `add` function overrides the base class `add` function to add a new node to the tree multimap
* and update the count.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following:
* @param [count=1] - The `count` parameter is an optional parameter that specifies the number of
* times the key-value pair should be added to the multimap. If not provided, the default value is 1.
* @returns a node (`N`) or `undefined`.
* times the key or node or entry should be added to the multimap. If not provided, the default value
* is 1.
* @returns either a node (`N`) or `undefined`.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>, count = 1): N | undefined {
let newNode: N | undefined;
@ -127,22 +124,19 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Time Complexity: O(k log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(k log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each.
* Time Complexity: O(k log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
*
* The function `addMany` takes an array of keys or nodes and adds them to the TreeMultimap,
* returning an array of the inserted nodes.
* @param {(BTNKey | N | undefined)[]} keysOrNodes - An array of keys or nodes. Each element can be
* of type BTNKey, N, or undefined.
* @param {V[]} [data] - The `data` parameter is an optional array of values that correspond to the
* keys or nodes being added. It is used to associate data with each key or node being added to the
* TreeMultimap. If provided, the length of the `data` array should be the same as the length of the
* @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values.
* The function overrides the addMany method to add multiple keys, nodes, or entries to a data
* structure.
* @param keysOrNodesOrEntries - The parameter `keysOrNodesOrEntries` is an iterable that can contain
* either keys, nodes, or entries.
* @returns The method is returning an array of type `N | undefined`.
*/
override addMany(keysOrNodesOrEntries: Iterable<BTNodeExemplar<V, N>>): (N | undefined)[] {
return super.addMany(keysOrNodesOrEntries);

View file

@ -19,20 +19,16 @@ export class HashMap<K = any, V = any> {
protected _hashFn: (key: K) => string;
protected _objHashFn: (key: K) => object;
/**
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(options: HashMapOptions<K, V> = {
elements: [],
constructor(elements?: Iterable<[K, V]>, options: HashMapOptions<K, V> = {
hashFn: (key: K) => String(key),
objHashFn: (key: K) => (<object>key)
}) {
this._sentinel = <HashMapLinkedNode<K, V>>{};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
const { elements, hashFn, objHashFn } = options;
const { hashFn, objHashFn } = options;
this._hashFn = hashFn;
this._objHashFn = objHashFn;
if (elements) {
@ -379,6 +375,10 @@ export class HashMap<K = any, V = any> {
}
}
print() {
console.log([...this]);
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)

View file

@ -29,13 +29,20 @@ export class Trie {
constructor(words?: string[], caseSensitive = true) {
this._root = new TrieNode('');
this._caseSensitive = caseSensitive;
this._size = 0;
if (words) {
for (const i of words) {
this.add(i);
for (const word of words) {
this.add(word);
}
}
}
protected _size: number;
get size(): number {
return this._size;
}
protected _caseSensitive: boolean;
get caseSensitive(): boolean {
@ -64,6 +71,7 @@ export class Trie {
add(word: string): boolean {
word = this._caseProcess(word);
let cur = this.root;
let isNewWord = false;
for (const c of word) {
let nodeC = cur.children.get(c);
if (!nodeC) {
@ -72,8 +80,12 @@ export class Trie {
}
cur = nodeC;
}
cur.isEnd = true;
return true;
if (!cur.isEnd) {
isNewWord = true;
cur.isEnd = true;
this._size++;
}
return isNewWord;
}
/**
@ -143,6 +155,9 @@ export class Trie {
};
dfs(this.root, 0);
if (isDeleted) {
this._size--;
}
return isDeleted;
}
@ -377,6 +392,10 @@ export class Trie {
return accumulator;
}
print() {
console.log([...this]);
}
/**
* Time Complexity: O(M), where M is the length of the input string.
* Space Complexity: O(1) - Constant space.

View file

@ -6,7 +6,6 @@ export type HashMapLinkedNode<K, V> = {
};
export type HashMapOptions<K, V> = {
elements: Iterable<[K, V]>;
hashFn: (key: K) => string;
objHashFn: (key: K) => object
}

View file

@ -4,6 +4,8 @@ import {
BST,
Deque,
DoublyLinkedList,
HashMap,
Heap,
MaxHeap,
MaxPriorityQueue,
MinHeap,
@ -12,12 +14,25 @@ import {
RedBlackTree,
SinglyLinkedList,
Stack,
TreeMultimap
TreeMultimap,
Trie
} from '../../src';
import { isDebugTest } from "../config";
const isDebug = isDebugTest;
const orgArr: number[] = [6, 1, 2, 7, 5, 3, 4, 9, 8];
const orgStrArr: string[] = [
"trie",
"trial",
"trick",
"trip",
"tree",
"trend",
"triangle",
"track",
"trace",
"transmit"
];
const entries: [number, number][] = [[6, 6], [1, 1], [2, 2], [7, 7], [5, 5], [3, 3], [4, 4], [9, 9], [8, 8]];
describe('conversions', () => {
@ -72,28 +87,69 @@ describe('conversions', () => {
})
it('Entry Array to BST', () => {
const bst = new BST<number>(orgArr);
const bst = new BST<number>(entries);
expect(bst.size).toBe(9)
isDebug && bst.print();
})
it('Entry Array to RedBlackTree', () => {
const rbTree = new RedBlackTree<number>(orgArr);
const rbTree = new RedBlackTree<number>(entries);
expect(rbTree.size).toBe(9)
isDebug && rbTree.print();
})
it('Entry Array to AVLTree', () => {
const avl = new AVLTree<number>(orgArr);
const avl = new AVLTree<number>(entries);
expect(avl.size).toBe(9)
isDebug && avl.print();
})
it('Entry Array to TreeMultimap', () => {
const treeMulti = new TreeMultimap<number>(orgArr);
const treeMulti = new TreeMultimap<number>(entries);
expect(treeMulti.size).toBe(9)
isDebug && treeMulti.print();
})
it('HashMap to RedBlackTree', () => {
const hm = new HashMap(entries);
isDebug && hm.print()
const rbTree = new RedBlackTree<number>(hm);
expect(rbTree.size).toBe(9)
isDebug && rbTree.print();
})
it('PriorityQueue to BST', () => {
const pq = new MinPriorityQueue(orgArr);
isDebug && pq.print();
const bst = new BST<number>(pq);
expect(bst.size).toBe(9)
isDebug && bst.print();
})
it('Deque to RedBlackTree', () => {
const dq = new Deque(orgArr);
isDebug && dq.print();
const rbTree = new RedBlackTree<number>(dq);
expect(rbTree.size).toBe(9)
isDebug && rbTree.print();
})
it('Trie to Heap to Deque', () => {
const trie = new Trie(orgStrArr);
expect(trie.size).toBe(10);
isDebug && trie.print();
const heap = new Heap<string>(trie, { comparator: (a, b) => Number(a) - Number(b) });
expect(heap.size).toBe(10);
isDebug && heap.print();
const dq = new Deque<string>(heap);
expect(dq.size).toBe(10);
isDebug && dq.print();
const entries = dq.map((el, i) => <[number, string]>[i, el]);
const avl = new AVLTree<string>(entries);
expect(avl.size).toBe(10)
isDebug && avl.print();
})
})