[core] renamed id to key

This commit is contained in:
Revone 2023-10-10 19:55:52 +08:00
parent 55b4034e1a
commit 45c49c99bf
34 changed files with 843 additions and 826 deletions

View file

@ -12,7 +12,7 @@ import type {
AbstractBinaryTreeNodeProperties,
AbstractBinaryTreeNodeProperty,
BinaryTreeDeletedResult,
BinaryTreeNodeId,
BinaryTreeNodeKey,
BinaryTreeNodePropertyName,
DFSOrderPattern,
NodeOrPropertyName
@ -26,25 +26,25 @@ export abstract class AbstractBinaryTreeNode<
> implements IAbstractBinaryTreeNode<V, NEIGHBOR>
{
/**
* The constructor function initializes a BinaryTreeNode object with an id and an optional value.
* @param {BinaryTreeNodeId} id - The `id` parameter is of type `BinaryTreeNodeId` and represents the unique identifier
* The constructor function initializes a BinaryTreeNode object with an key and an optional value.
* @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier
* of the binary tree node. It is used to distinguish one node from another in the binary tree.
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It represents the value that will be
* stored in the binary tree node. If no value is provided, it will be set to undefined.
*/
protected constructor(id: BinaryTreeNodeId, val?: V) {
this._id = id;
protected constructor(key: BinaryTreeNodeKey, val?: V) {
this._key = key;
this._val = val;
}
private _id: BinaryTreeNodeId;
private _key: BinaryTreeNodeKey;
get id(): BinaryTreeNodeId {
return this._id;
get key(): BinaryTreeNodeKey {
return this._key;
}
set id(v: BinaryTreeNodeId) {
this._id = v;
set key(v: BinaryTreeNodeKey) {
this._key = v;
}
private _val: V | undefined;
@ -169,10 +169,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._loopType;
}
private _visitedId: BinaryTreeNodeId[] = [];
private _visitedKey: BinaryTreeNodeKey[] = [];
get visitedId(): BinaryTreeNodeId[] {
return this._visitedId;
get visitedKey(): BinaryTreeNodeKey[] {
return this._visitedKey;
}
private _visitedVal: N['val'][] = [];
@ -187,7 +187,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._visitedNode;
}
abstract createNode(id: BinaryTreeNodeId, val?: N['val']): N | null;
abstract createNode(key: BinaryTreeNodeKey, val?: N['val']): N | null;
/**
* The `swapLocation` function swaps the location of two nodes in a binary tree.
@ -197,17 +197,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The `destNode` is being returned.
*/
swapLocation(srcNode: N, destNode: N): N {
const {id, val, height} = destNode;
const tempNode = this.createNode(id, val);
const {key, val, height} = destNode;
const tempNode = this.createNode(key, val);
if (tempNode) {
tempNode.height = height;
destNode.id = srcNode.id;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
srcNode.id = tempNode.id;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.height = tempNode.height;
}
@ -216,7 +216,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The clear() function resets the root, size, and maxId properties to their initial values.
* The clear() function resets the root, size, and maxKey properties to their initial values.
*/
clear() {
this._root = null;
@ -239,20 +239,20 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `add` function adds a new node to a binary tree, either by ID or by creating a new node with a given value.
* @param {BinaryTreeNodeId | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId`, which
* @param {BinaryTreeNodeKey | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeKey`, which
* is a number representing the ID of a binary tree node, or it can be a `N` object, which represents a binary tree
* node itself. It can also be `null` if no node is specified.
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node
* being added to the binary tree.
* @returns The function `add` returns either the inserted node (`N`), `null`, or `undefined`.
*/
add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
add(idOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
const _bfs = (root: N, newNode: N | null): N | undefined | null => {
const queue: Array<N | null> = [root];
while (queue.length > 0) {
const cur = queue.shift();
if (cur) {
if (newNode && cur.id === newNode.id) return;
if (newNode && cur.key === newNode.key) return;
const inserted = this._addTo(newNode, cur);
if (inserted !== undefined) return inserted;
if (cur.left) queue.push(cur.left);
@ -274,7 +274,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return;
}
const existNode = idOrNode ? this.get(idOrNode, 'id') : undefined;
const existNode = idOrNode ? this.get(idOrNode, 'key') : undefined;
if (this.root) {
if (existNode) {
@ -298,21 +298,21 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `addMany` function takes an array of binary tree node IDs or nodes, and optionally an array of corresponding data
* values, and adds them to the binary tree.
* @param {(BinaryTreeNodeId | null)[] | (N | null)[]} idsOrNodes - An array of BinaryTreeNodeId or BinaryTreeNode
* @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} idsOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode
* objects, or null values.
* @param {N['val'][]} [data] - The `data` parameter is an optional array of values (`N['val'][]`) that corresponds to
* the nodes or node IDs being added. It is used to set the value of each node being added. If `data` is not provided,
* the value of the nodes will be `undefined`.
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
*/
addMany(idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[], data?: N['val'][]): (N | null | undefined)[] {
addMany(idsOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][]): (N | null | undefined)[] {
// TODO not sure addMany not be run multi times
const inserted: (N | null | undefined)[] = [];
for (let i = 0; i < idsOrNodes.length; i++) {
const idOrNode = idsOrNodes[i];
if (idOrNode instanceof AbstractBinaryTreeNode) {
inserted.push(this.add(idOrNode.id, idOrNode.val));
inserted.push(this.add(idOrNode.key, idOrNode.val));
continue;
}
@ -329,14 +329,14 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `fill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data.
* @param {(BinaryTreeNodeId | N)[]} idsOrNodes - The `idsOrNodes` parameter is an array that can contain either
* `BinaryTreeNodeId` or `N` values.
* @param {(BinaryTreeNodeKey | N)[]} idsOrNodes - The `idsOrNodes` parameter is an array that can contain either
* `BinaryTreeNodeKey` or `N` values.
* @param {N[] | Array<N['val']>} [data] - 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 `idsOrNodes`
* array. Each value in the `data` array will be assigned to the
* @returns The method is returning a boolean value.
*/
fill(idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[], data?: N[] | Array<N['val']>): boolean {
fill(idsOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N[] | Array<N['val']>): boolean {
this.clear();
return idsOrNodes.length === this.addMany(idsOrNodes, data).length;
}
@ -344,15 +344,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `remove` function in TypeScript is used to delete a node from a binary search tree and returns an array of objects
* containing the deleted node and the node that needs to be balanced.
* @param {N | BinaryTreeNodeId} nodeOrId - The `nodeOrId` parameter can be either a node object (`N`) or a binary tree
* node ID (`BinaryTreeNodeId`).
* @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object (`N`) or a binary tree
* node ID (`BinaryTreeNodeKey`).
* @returns The function `remove` returns an array of `BinaryTreeDeletedResult<N>` objects.
*/
remove(nodeOrId: N | BinaryTreeNodeId): BinaryTreeDeletedResult<N>[] {
remove(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const curr: N | null = typeof nodeOrId === 'number' ? this.get(nodeOrId) : nodeOrId;
const curr: N | null = typeof nodeOrKey === 'number' ? this.get(nodeOrKey) : nodeOrKey;
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;
@ -392,11 +392,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function calculates the depth of a node in a binary tree.
* @param {N | BinaryTreeNodeId | null} beginRoot - The `beginRoot` parameter can be one of the following:
* @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter can be one of the following:
* @returns the depth of the given node or binary tree.
*/
getDepth(beginRoot: N | BinaryTreeNodeId | null): number {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'id');
getDepth(beginRoot: N | BinaryTreeNodeKey | null): number {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
let depth = 0;
while (beginRoot?.parent) {
@ -408,15 +408,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `getHeight` function calculates the maximum height of a binary tree, either recursively or iteratively.
* @param {N | BinaryTreeNodeId | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeId` (a type representing the ID of a binary tree
* @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
* node), or `null`.
* @returns the height of the binary tree.
*/
getHeight(beginRoot?: N | BinaryTreeNodeId | null): number {
getHeight(beginRoot?: N | BinaryTreeNodeKey | null): number {
beginRoot = beginRoot ?? this.root;
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'id');
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
if (!beginRoot) return -1;
if (this._loopType === LoopType.RECURSIVE) {
@ -518,18 +518,18 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `getNodes` returns an array of nodes that match a given property name and value in a binary tree.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
* generic type `N`. It represents the property of the binary tree node that you want to search for.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to use when searching for nodes. If not provided, it defaults to 'id'.
* specifies the property name to use when searching for nodes. If not provided, it defaults to 'key'.
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
* return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the
* function will stop traversing the tree and return the first matching node. If `only
* @returns an array of nodes (type N).
*/
getNodes(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[] {
getNodes(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[] {
if (!this.root) return [];
propertyName = propertyName ?? 'id';
propertyName = propertyName ?? 'key';
const result: N[] = [];
@ -559,14 +559,14 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function checks if a binary tree node has a specific property.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or `N`.
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`.
* It represents the property of the binary tree node that you want to check.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'id'.
* specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'.
* @returns a boolean value.
*/
has(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): boolean {
propertyName = propertyName ?? 'id';
has(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): boolean {
propertyName = propertyName ?? 'key';
// TODO may support finding node by value equal
return this.getNodes(nodeProperty, propertyName).length > 0;
}
@ -574,16 +574,16 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function returns the first node that matches the given property name and value, or null if no matching node is
* found.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or `N`.
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`.
* It represents the property of the binary tree node that you want to search for.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the
* default value is set to `'id'`.
* default value is set to `'key'`.
* @returns either the value of the specified property of the node, or the node itself if no property name is provided.
* If no matching node is found, it returns null.
*/
get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'id';
get(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'key';
// TODO may support finding node by value equal
return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
}
@ -599,7 +599,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
*/
getPathToRoot(node: N, isReverse = true): N[] {
// TODO to support get path through passing id
// TODO to support get path through passing key
const result: N[] = [];
while (node.parent) {
// Array.push + Array.reverse is more efficient than Array.unshift
@ -614,7 +614,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
* no node is specified.
* generic type representing a node in a binary tree), `BinaryTreeNodeId` (a type representing the ID of a binary tree
* generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
* node), or `null`.
* @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
* provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
@ -626,8 +626,8 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
* no node is specified.
* @param {N | BinaryTreeNodeId | null} [node] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeId` (a type representing the ID of a binary tree
* @param {N | BinaryTreeNodeKey | null} [node] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
* node).
* @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
* provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
@ -639,16 +639,16 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
* no node is specified.
* @param {N | BinaryTreeNodeId | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeId` (a type representing the ID of a binary tree
* @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
* generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
* node), or `null`.
* @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
* provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
* from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost
* node is found (
*/
getLeftMost(beginRoot?: N | BinaryTreeNodeId | null): N | null {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'id');
getLeftMost(beginRoot?: N | BinaryTreeNodeKey | null): N | null {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
beginRoot = beginRoot ?? this.root;
if (!beginRoot) return beginRoot;
@ -701,7 +701,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* rightmost node starting from the root of the binary tree.
*/
getRightMost(node?: N | null): N | null {
// TODO support get right most by passing id in
// TODO support get right most by passing key in
node = node ?? this.root;
if (!node) return node;
@ -733,10 +733,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
if (!node) return true;
if (this._loopType === LoopType.RECURSIVE) {
const dfs = (cur: N | null | undefined, min: BinaryTreeNodeId, max: BinaryTreeNodeId): boolean => {
const dfs = (cur: N | null | undefined, min: BinaryTreeNodeKey, max: BinaryTreeNodeKey): boolean => {
if (!cur) return true;
if (cur.id <= min || cur.id >= max) return false;
return dfs(cur.left, min, cur.id) && dfs(cur.right, cur.id, max);
if (cur.key <= min || cur.key >= max) return false;
return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max);
};
return dfs(node, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
@ -750,8 +750,8 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
curr = curr.left;
}
curr = stack.pop()!;
if (!curr || prev >= curr.id) return false;
prev = curr.id;
if (!curr || prev >= curr.key) return false;
prev = curr.key;
curr = curr.right;
}
return true;
@ -773,7 +773,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns the size of the subtree rooted at `subTreeRoot`.
*/
getSubTreeSize(subTreeRoot: N | null | undefined) {
// TODO support id passed in
// TODO support key passed in
let size = 0;
if (!subTreeRoot) return size;
@ -802,16 +802,16 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `subTreeSum` calculates the sum of a specified property in a binary tree or subtree.
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
* tree or the ID of a binary tree node. It can also be `null` if there is no subtree.
* @param {BinaryTreeNodePropertyName} [propertyName] - propertyName is an optional parameter that specifies the
* property of the binary tree node to use for calculating the sum. It can be either 'id' or 'val'. If propertyName is
* not provided, it defaults to 'id'.
* property of the binary tree node to use for calculating the sum. It can be either 'key' or 'val'. If propertyName is
* not provided, it defaults to 'key'.
* @returns a number, which is the sum of the values of the specified property in the subtree rooted at `subTreeRoot`.
*/
subTreeSum(subTreeRoot: N | BinaryTreeNodeId | null, propertyName?: BinaryTreeNodePropertyName): number {
propertyName = propertyName ?? 'id';
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
subTreeSum(subTreeRoot: N | BinaryTreeNodeKey | null, propertyName?: BinaryTreeNodePropertyName): number {
propertyName = propertyName ?? 'key';
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
if (!subTreeRoot) return 0;
@ -820,14 +820,14 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
const _sumByProperty = (cur: N) => {
let needSum: number;
switch (propertyName) {
case 'id':
needSum = cur.id;
case 'key':
needSum = cur.key;
break;
case 'val':
needSum = typeof cur.val === 'number' ? cur.val : 0;
break;
default:
needSum = cur.id;
needSum = cur.key;
break;
}
return needSum;
@ -857,31 +857,31 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function `subTreeAdd` adds a delta value to a specified property of each node in a subtree.
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
* tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to.
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the property value of
* each node in the subtree should be incremented.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'id'.
* specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'.
* @returns a boolean value.
*/
subTreeAdd(
subTreeRoot: N | BinaryTreeNodeId | null,
subTreeRoot: N | BinaryTreeNodeKey | null,
delta: number,
propertyName?: BinaryTreeNodePropertyName
): boolean {
propertyName = propertyName ?? 'id';
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
propertyName = propertyName ?? 'key';
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
if (!subTreeRoot) return false;
const _addByProperty = (cur: N) => {
switch (propertyName) {
case 'id':
cur.id += delta;
case 'key':
cur.key += delta;
break;
default:
cur.id += delta;
cur.key += delta;
break;
}
};
@ -909,17 +909,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* Performs a breadth-first search (BFS) on a binary tree, accumulating properties of each node based on their 'id' property.
* Performs a breadth-first search (BFS) on a binary tree, accumulating properties of each node based on their 'key' property.
* @returns An array of binary tree node IDs.
*/
BFS(): BinaryTreeNodeId[];
BFS(): BinaryTreeNodeKey[];
/**
* Performs a breadth-first search (BFS) on a binary tree, accumulating properties of each node based on the specified property name.
* @param {'id'} nodeOrPropertyName - The name of the property to accumulate.
* @param {'key'} nodeOrPropertyName - The name of the property to accumulate.
* @returns An array of values corresponding to the specified property.
*/
BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[];
BFS(nodeOrPropertyName: 'key'): BinaryTreeNodeKey[];
/**
* Performs a breadth-first search (BFS) on a binary tree, accumulating the 'val' property of each node.
@ -943,7 +943,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns An instance of the `AbstractBinaryTreeNodeProperties` class with generic type `N`.
*/
BFS(nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
nodeOrPropertyName = nodeOrPropertyName ?? 'key';
this._clearResults();
const queue: Array<N | null | undefined> = [this.root];
@ -960,10 +960,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* Performs a depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on their 'id' property.
* Performs a depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on their 'key' property.
* @returns An array of binary tree node IDs.
*/
DFS(): BinaryTreeNodeId[];
DFS(): BinaryTreeNodeKey[];
/**
* Performs a depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on the specified property name.
@ -971,7 +971,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @param {string} nodeOrPropertyName - The name of the property to accumulate.
* @returns An array of values corresponding to the specified property.
*/
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
/**
* Performs a depth-first search (DFS) traversal on a binary tree and accumulates the 'val' property of each node.
@ -993,12 +993,12 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* The DFS function performs a depth-first search traversal on a binary tree and returns the accumulated properties of
* each node based on the specified pattern and property name.
* @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. If no `nodeOrPropertyName` is provided, the default value is `'id'`.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. If no `nodeOrPropertyName` is provided, the default value is `'key'`.
* @returns an instance of the AbstractBinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name.
*/
DFS(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
pattern = pattern ?? 'in';
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
nodeOrPropertyName = nodeOrPropertyName ?? 'key';
this._clearResults();
const _traverse = (node: N) => {
switch (pattern) {
@ -1027,10 +1027,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
// --- start additional methods ---
/**
* Performs an iterative depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on their 'id' property.
* Performs an iterative depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on their 'key' property.
* @returns An array of binary tree node IDs.
*/
DFSIterative(): BinaryTreeNodeId[];
DFSIterative(): BinaryTreeNodeKey[];
/**
* Performs an iterative depth-first search (DFS) traversal on a binary tree and accumulates properties of each node based on the specified property name.
@ -1038,7 +1038,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @param {string} nodeOrPropertyName - The name of the property to accumulate.
* @returns An array of values corresponding to the specified property.
*/
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
/**
* Performs an iterative depth-first search (DFS) traversal on a binary tree and accumulates the 'val' property of each node.
@ -1060,7 +1060,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* The DFSIterative function performs an iterative depth-first search traversal on a binary tree, with the option to
* specify the traversal pattern and the property name to accumulate results by.
* @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. By default, it is set to `'id'`.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. By default, it is set to `'key'`.
* @returns An object of type AbstractBinaryTreeNodeProperties<N>.
*/
DFSIterative(
@ -1068,7 +1068,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
nodeOrPropertyName?: NodeOrPropertyName
): AbstractBinaryTreeNodeProperties<N> {
pattern = pattern || 'in';
nodeOrPropertyName = nodeOrPropertyName || 'id';
nodeOrPropertyName = nodeOrPropertyName || 'key';
this._clearResults();
if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName);
// 0: visit, 1: print
@ -1109,11 +1109,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on their 'id' property.
* Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on their 'key' property.
* @param {N | null} node - The starting node for the level order traversal. If null, the root node of the tree is used as the starting node.
* @returns An array of binary tree node IDs.
*/
levelIterative(node: N | null): BinaryTreeNodeId[];
levelIterative(node: N | null): BinaryTreeNodeKey[];
/**
* Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on the specified property name.
@ -1121,7 +1121,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @param {string} nodeOrPropertyName - The name of the property to accumulate.
* @returns An array of values corresponding to the specified property.
*/
levelIterative(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
levelIterative(node: N | null, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
/**
* Performs a level-order traversal on a binary tree starting from the specified node and accumulates the 'val' property of each node.
@ -1146,13 +1146,13 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* node for the level order traversal. It can be null if no specific node is provided, in which case the root node of
* the tree is used as the starting node.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that
* can be either a `BinaryTreeNode` property name or the string `'id'`. If a property name is provided, the function
* can be either a `BinaryTreeNode` property name or the string `'key'`. If a property name is provided, the function
* will accumulate results based on that property. If no property name is provided, the function will default to
* accumulating results based on the 'id' property.
* accumulating results based on the 'key' property.
* @returns An object of type `AbstractBinaryTreeNodeProperties<N>`.
*/
levelIterative(node: N | null, nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName || 'id';
nodeOrPropertyName = nodeOrPropertyName || 'key';
node = node || this.root;
if (!node) return [];
@ -1180,15 +1180,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
* @returns A 2D array of AbstractBinaryTreeNodeProperty<N> objects.
*/
listLevels(node: N | null): BinaryTreeNodeId[][];
listLevels(node: N | null): BinaryTreeNodeKey[][];
/**
* Collects nodes from a binary tree by a specified property and organizes them into levels.
* @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
* @param {'id} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
* @param {'key} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
* @returns A 2D array of values corresponding to the specified property.
*/
listLevels(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][];
listLevels(node: N | null, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[][];
/**
* Collects nodes from a binary tree by a specified property and organizes them into levels.
@ -1209,11 +1209,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels.
* @param {N | null} node - The `node` parameter is a BinaryTreeNode object or null. It represents the root node of a binary tree. If it is null, the function will use the root node of the current binary tree instance.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that specifies the property of the `BinaryTreeNode` object to collect at each level. It can be one of the following values: 'id', 'val', or 'node'. If not provided, it defaults to 'id'.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that specifies the property of the `BinaryTreeNode` object to collect at each level. It can be one of the following values: 'key', 'val', or 'node'. If not provided, it defaults to 'key'.
* @returns A 2D array of `AbstractBinaryTreeNodeProperty<N>` objects.
*/
listLevels(node: N | null, nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperty<N>[][] {
nodeOrPropertyName = nodeOrPropertyName || 'id';
nodeOrPropertyName = nodeOrPropertyName || 'key';
node = node || this.root;
if (!node) return [];
@ -1221,8 +1221,8 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
const collectByProperty = (node: N, level: number) => {
switch (nodeOrPropertyName) {
case 'id':
levelsNodes[level].push(node.id);
case 'key':
levelsNodes[level].push(node.key);
break;
case 'val':
levelsNodes[level].push(node.val);
@ -1231,7 +1231,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
levelsNodes[level].push(node);
break;
default:
levelsNodes[level].push(node.id);
levelsNodes[level].push(node.key);
break;
}
};
@ -1290,15 +1290,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm.
* @returns An array of binary tree node IDs.
*/
morris(): BinaryTreeNodeId[];
morris(): BinaryTreeNodeKey[];
/**
* Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates properties of each node based on the specified property name.
* @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
* @param {'id'} nodeOrPropertyName - The name of the property to accumulate.
* @param {'key'} nodeOrPropertyName - The name of the property to accumulate.
* @returns An array of values corresponding to the specified property.
*/
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
/**
* Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates the 'val' property of each node.
@ -1319,7 +1319,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm.
* @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The property name of the nodes to retrieve or perform operations on during the traversal. It can be any valid property name of the nodes in the binary tree. If not provided, it defaults to 'id'.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The property name of the nodes to retrieve or perform operations on during the traversal. It can be any valid property name of the nodes in the binary tree. If not provided, it defaults to 'key'.
* @returns An array of AbstractBinaryTreeNodeProperties<N> objects.
*/
morris(
@ -1329,7 +1329,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
if (this.root === null) return [];
pattern = pattern || 'in';
nodeOrPropertyName = nodeOrPropertyName || 'id';
nodeOrPropertyName = nodeOrPropertyName || 'key';
this._clearResults();
@ -1454,11 +1454,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function sets the value of the `_visitedId` property in a protected manner.
* @param {BinaryTreeNodeId[]} value - value is an array of BinaryTreeNodeId values.
* The function sets the value of the `_visitedKey` property in a protected manner.
* @param {BinaryTreeNodeKey[]} value - value is an array of BinaryTreeNodeKey values.
*/
protected _setVisitedId(value: BinaryTreeNodeId[]) {
this._visitedId = value;
protected _setVisitedKey(value: BinaryTreeNodeKey[]) {
this._visitedKey = value;
}
/**
@ -1502,7 +1502,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* properties.
*/
protected _clearResults() {
this._visitedId = [];
this._visitedKey = [];
this._visitedVal = [];
this._visitedNode = [];
}
@ -1512,11 +1512,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* a result array.
* @param {N} cur - The current node being processed.
* @param {(N | null | undefined)[]} result - An array that stores the matching nodes.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter is either a `BinaryTreeNodeId` or a `N`
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is either a `BinaryTreeNodeKey` or a `N`
* type. It represents the property value that we are comparing against in the switch statement.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to compare against when pushing nodes into the `result` array. It can be either `'id'`
* or `'val'`. If it is not provided or is not equal to `'id'` or `'val'`, the
* specifies the property name to compare against when pushing nodes into the `result` array. It can be either `'key'`
* or `'val'`. If it is not provided or is not equal to `'key'` or `'val'`, the
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
* stop after finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set to
* `true`, the function will stop after finding the first matching node and return `true`. If `onlyOne
@ -1525,13 +1525,13 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
protected _pushByPropertyNameStopOrNot(
cur: N,
result: (N | null | undefined)[],
nodeProperty: BinaryTreeNodeId | N,
nodeProperty: BinaryTreeNodeKey | N,
propertyName?: BinaryTreeNodePropertyName,
onlyOne?: boolean
) {
switch (propertyName) {
case 'id':
if (cur.id === nodeProperty) {
case 'key':
if (cur.key === nodeProperty) {
result.push(cur);
return !!onlyOne;
}
@ -1543,7 +1543,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
break;
default:
if (cur.id === nodeProperty) {
if (cur.key === nodeProperty) {
result.push(cur);
return !!onlyOne;
}
@ -1559,11 +1559,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* specifies the property name to be used for accumulating values. If it is a `Node` object, it specifies
*/
protected _accumulatedByPropertyName(node: N, nodeOrPropertyName?: NodeOrPropertyName) {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
nodeOrPropertyName = nodeOrPropertyName ?? 'key';
switch (nodeOrPropertyName) {
case 'id':
this._visitedId.push(node.id);
case 'key':
this._visitedKey.push(node.key);
break;
case 'val':
this._visitedVal.push(node.val);
@ -1572,7 +1572,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
this._visitedNode.push(node);
break;
default:
this._visitedId.push(node.id);
this._visitedKey.push(node.key);
break;
}
}
@ -1590,17 +1590,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The method `_getResultByPropertyName` returns an instance of `AbstractBinaryTreeNodeProperties<N>`.
*/
protected _getResultByPropertyName(nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
nodeOrPropertyName = nodeOrPropertyName ?? 'key';
switch (nodeOrPropertyName) {
case 'id':
return this._visitedId;
case 'key':
return this._visitedKey;
case 'val':
return this._visitedVal;
case 'node':
return this._visitedNode;
default:
return this._visitedId;
return this._visitedKey;
}
}

View file

@ -6,15 +6,15 @@
* @license MIT License
*/
import {BST, BSTNode} from './bst';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeId} from '../../types';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types';
import {IAVLTree, IAVLTreeNode} from '../../interfaces';
export class AVLTreeNode<V = any, NEIGHBOR extends AVLTreeNode<V, NEIGHBOR> = AVLTreeNodeNested<V>>
extends BSTNode<V, NEIGHBOR>
implements IAVLTreeNode<V, NEIGHBOR>
{
constructor(id: BinaryTreeNodeId, val?: V) {
super(id, val);
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);
}
}
@ -30,27 +30,27 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
}
/**
* The function creates a new AVL tree node with the given id and value.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is used to uniquely
* The function creates a new AVL tree node with the given key and value.
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely
* identify each node in the tree.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value
* that will be stored in the node.
* @returns a new AVLTreeNode object with the specified id and value.
* @returns a new AVLTreeNode object with the specified key and value.
*/
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new AVLTreeNode<N['val'], N>(id, val) as N;
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new AVLTreeNode<N['val'], N>(key, val) as N;
}
/**
* The function overrides the add method of a binary tree node and balances the tree after inserting a new node.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that we want to add.
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier of the binary tree node that we want to add.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It is of type
* `N['val']`, which means it should be of the same type as the `val` property of the nodes in the binary tree.
* @returns The method is returning the inserted node, or null or undefined if the insertion was not successful.
*/
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
override add(key: BinaryTreeNodeKey, val?: N['val']): N | null | undefined {
// TODO support node as a param
const inserted = super.add(id, val);
const inserted = super.add(key, val);
if (inserted) this._balancePath(inserted);
return inserted;
}
@ -58,12 +58,12 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
/**
* The function overrides the remove method of a binary tree and performs additional operations to balance the tree after
* deletion.
* @param {BinaryTreeNodeId} id - The `id` parameter represents the identifier of the binary tree node that needs to be
* @param {BinaryTreeNodeKey} key - The `key` parameter represents the identifier of the binary tree node that needs to be
* removed.
* @returns The method is returning an array of `BinaryTreeDeletedResult<N>` objects.
*/
override remove(id: BinaryTreeNodeId): BinaryTreeDeletedResult<N>[] {
const deletedResults = super.remove(id);
override remove(key: BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[] {
const deletedResults = super.remove(key);
for (const {needBalanced} of deletedResults) {
if (needBalanced) {
this._balancePath(needBalanced);

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import type {BinaryTreeNodeId, BinaryTreeNodeNested, BinaryTreeOptions} from '../../types';
import type {BinaryTreeNodeKey, BinaryTreeNodeNested, BinaryTreeOptions} from '../../types';
import {AbstractBinaryTree, AbstractBinaryTreeNode} from './abstract-binary-tree';
import {IBinaryTree, IBinaryTreeNode} from '../../interfaces';
@ -14,8 +14,8 @@ export class BinaryTreeNode<V = any, NEIGHBOR extends BinaryTreeNode<V, NEIGHBOR
extends AbstractBinaryTreeNode<V, NEIGHBOR>
implements IBinaryTreeNode<V, NEIGHBOR>
{
constructor(id: BinaryTreeNodeId, val?: V) {
super(id, val);
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);
}
}
@ -35,13 +35,13 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
/**
* The function creates a new binary tree node with an optional value.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is of type
* `BinaryTreeNodeId`, which represents the unique identifier for each node in the binary tree.
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is of type
* `BinaryTreeNodeKey`, which represents the unique identifier for each node in the binary tree.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value
* stored in the node.
* @returns a new instance of a BinaryTreeNode with the specified id and value.
* @returns a new instance of a BinaryTreeNode with the specified key and value.
*/
createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new BinaryTreeNode<N['val'], N>(id, val) as N;
createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new BinaryTreeNode<N['val'], N>(key, val) as N;
}
}

View file

@ -5,7 +5,13 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested, BSTOptions} from '../../types';
import type {
BinaryTreeNodeKey,
BinaryTreeNodePropertyName,
BSTComparator,
BSTNodeNested,
BSTOptions
} from '../../types';
import {CP, LoopType} from '../../types';
import {BinaryTree, BinaryTreeNode} from './binary-tree';
import {IBST, IBSTNode} from '../../interfaces';
@ -14,8 +20,8 @@ export class BSTNode<V = any, NEIGHBOR extends BSTNode<V, NEIGHBOR> = BSTNodeNes
extends BinaryTreeNode<V, NEIGHBOR>
implements IBSTNode<V, NEIGHBOR>
{
constructor(id: BinaryTreeNodeId, val?: V) {
super(id, val);
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);
}
}
@ -35,27 +41,27 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
/**
* The function creates a new binary search tree node with the given id and value.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is used to uniquely
* The function creates a new binary search tree node with the given key and value.
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely
* identify each node in the binary tree.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value
* that will be stored in the node.
* @returns a new instance of the BSTNode class with the specified id and value.
* @returns a new instance of the BSTNode class with the specified key and value.
*/
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new BSTNode<N['val'], N>(id, val) as N;
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new BSTNode<N['val'], N>(key, val) as N;
}
/**
* The `add` function adds a new node to a binary search tree, either by creating a new node or by updating an existing
* node with the same ID.
* @param {BinaryTreeNodeId | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId` or a `N`
* @param {BinaryTreeNodeKey | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N`
* (which represents a binary tree node) or `null`.
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node
* being added to the binary search tree.
* @returns The function `add` returns the inserted node (`inserted`) which can be of type `N`, `null`, or `undefined`.
*/
override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
override add(idOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
// TODO support node as a param
let inserted: N | null = null;
let newNode: N | null = null;
@ -75,14 +81,14 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
let traversing = true;
while (traversing) {
if (cur !== null && newNode !== null) {
if (this._compare(cur.id, newNode.id) === CP.eq) {
if (this._compare(cur.key, newNode.key) === CP.eq) {
if (newNode) {
cur.val = newNode.val;
}
//Duplicates are not accepted.
traversing = false;
inserted = cur;
} else if (this._compare(cur.id, newNode.id) === CP.gt) {
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
// Traverse left of the node
if (cur.left === undefined) {
if (newNode) {
@ -97,7 +103,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
//Traverse the left of the current node
if (cur.left) cur = cur.left;
}
} else if (this._compare(cur.id, newNode.id) === CP.lt) {
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
// Traverse right of the node
if (cur.right === undefined) {
if (newNode) {
@ -124,48 +130,50 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The `addMany` function overrides the base class method to add multiple nodes to a binary search tree in a balanced
* manner.
* @param {[BinaryTreeNodeId | N , N['val']][]} idsOrNodes - The `idsOrNodes` parameter in the `addMany` function is an array of
* `BinaryTreeNodeId` or `N` (node) objects, or `null` values. It represents the nodes or node IDs that need to be added
* @param {[BinaryTreeNodeKey | N , N['val']][]} idsOrNodes - The `idsOrNodes` parameter in the `addMany` function is an array of
* `BinaryTreeNodeKey` or `N` (node) objects, or `null` values. It represents the nodes or node IDs that need to be added
* to the binary search tree.
* @param {N['val'][]} data - The values of tree nodes
* @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method.
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
*/
override addMany(
idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[],
idsOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
data?: N['val'][],
isBalanceAdd = false
): (N | null | undefined)[] {
function hasNoNull(arr: (BinaryTreeNodeId | null)[] | (N | null)[]): arr is BinaryTreeNodeId[] | N[] {
function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] {
return arr.indexOf(null) === -1;
}
if (!isBalanceAdd || !hasNoNull(idsOrNodes)) {
return super.addMany(idsOrNodes, data);
}
const inserted: (N | null | undefined)[] = [];
const combinedArr: [BinaryTreeNodeId | N, N['val']][] = idsOrNodes.map((value, index) => [value, data?.[index]]);
const combinedArr: [BinaryTreeNodeKey | N, N['val']][] = idsOrNodes.map((value, index) => [value, data?.[index]]);
let sorted = [];
function isNodeOrNullTuple(arr: [BinaryTreeNodeId | N, N['val']][]): arr is [N, N['val']][] {
function isNodeOrNullTuple(arr: [BinaryTreeNodeKey | N, N['val']][]): arr is [N, N['val']][] {
for (const [idOrNode] of arr) if (idOrNode instanceof BSTNode) return true;
return false;
}
function isBinaryTreeIdOrNullTuple(arr: [BinaryTreeNodeId | N, N['val']][]): arr is [BinaryTreeNodeId, N['val']][] {
function isBinaryTreeKeyOrNullTuple(
arr: [BinaryTreeNodeKey | N, N['val']][]
): arr is [BinaryTreeNodeKey, N['val']][] {
for (const [idOrNode] of arr) if (typeof idOrNode === 'number') return true;
return false;
}
let sortedIdsOrNodes: (number | N | null)[] = [],
let sortedKeysOrNodes: (number | N | null)[] = [],
sortedData: (N['val'] | undefined)[] | undefined = [];
if (isNodeOrNullTuple(combinedArr)) {
sorted = combinedArr.sort((a, b) => a[0].id - b[0].id);
} else if (isBinaryTreeIdOrNullTuple(combinedArr)) {
sorted = combinedArr.sort((a, b) => a[0].key - b[0].key);
} else if (isBinaryTreeKeyOrNullTuple(combinedArr)) {
sorted = combinedArr.sort((a, b) => a[0] - b[0]);
} else {
throw new Error('Invalid input idsOrNodes');
}
sortedIdsOrNodes = sorted.map(([idOrNode]) => idOrNode);
sortedKeysOrNodes = sorted.map(([idOrNode]) => idOrNode);
sortedData = sorted.map(([, val]) => val);
const recursive = (arr: (BinaryTreeNodeId | null | N)[], data?: N['val'][]) => {
const recursive = (arr: (BinaryTreeNodeKey | null | N)[], data?: N['val'][]) => {
if (arr.length === 0) return;
const mid = Math.floor((arr.length - 1) / 2);
@ -183,7 +191,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const newNode = this.add(sortedIdsOrNodes[m], sortedData?.[m]);
const newNode = this.add(sortedKeysOrNodes[m], sortedData?.[m]);
inserted.push(newNode);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
@ -192,7 +200,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
};
if (this.loopType === LoopType.RECURSIVE) {
recursive(sortedIdsOrNodes, sortedData);
recursive(sortedKeysOrNodes, sortedData);
} else {
iterative();
}
@ -202,44 +210,44 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The function returns the first node in a binary tree that matches the given property name and value.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
* generic type `N`. It represents the property of the binary tree node that you want to search for.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'id'`.
* @returns The method is returning either a BinaryTreeNodeId or N (generic type) or null.
* specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'key'`.
* @returns The method is returning either a BinaryTreeNodeKey or N (generic type) or null.
*/
override get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'id';
override get(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'key';
return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
}
/**
* The function returns the id of the rightmost node if the comparison between two values is less than, the id of the
* leftmost node if the comparison is greater than, and the id of the rightmost node otherwise.
* @returns The method `lastKey()` returns the id of the rightmost node in the binary tree if the comparison between
* the values at index 0 and 1 is less than, otherwise it returns the id of the leftmost node. If the comparison is
* equal, it returns the id of the rightmost node. If there are no nodes in the tree, it returns 0.
* The function returns the key of the rightmost node if the comparison between two values is less than, the key of the
* leftmost node if the comparison is greater than, and the key of the rightmost node otherwise.
* @returns The method `lastKey()` returns the key of the rightmost node in the binary tree if the comparison between
* the values at index 0 and 1 is less than, otherwise it returns the key of the leftmost node. If the comparison is
* equal, it returns the key of the rightmost node. If there are no nodes in the tree, it returns 0.
*/
lastKey(): BinaryTreeNodeId {
if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.id ?? 0;
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.id ?? 0;
else return this.getRightMost()?.id ?? 0;
lastKey(): BinaryTreeNodeKey {
if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.key ?? 0;
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.key ?? 0;
else return this.getRightMost()?.key ?? 0;
}
/**
* The function `getNodes` returns an array of nodes in a binary tree that match a given property value.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or an
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or an
* `N` type. It represents the property of the binary tree node that you want to compare with.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to use for comparison. If not provided, it defaults to `'id'`.
* specifies the property name to use for comparison. If not provided, it defaults to `'key'`.
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
* return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne`
* is set to `true`, the function will return an array with only one node (if
* @returns an array of nodes (type N).
*/
override getNodes(
nodeProperty: BinaryTreeNodeId | N,
propertyName: BinaryTreeNodePropertyName = 'id',
nodeProperty: BinaryTreeNodeKey | N,
propertyName: BinaryTreeNodePropertyName = 'key',
onlyOne?: boolean
): N[] {
if (!this.root) return [];
@ -250,9 +258,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return;
if (!cur.left && !cur.right) return;
if (propertyName === 'id') {
if (this._compare(cur.id, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left);
if (this._compare(cur.id, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right);
if (propertyName === 'key') {
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left);
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right);
} else {
cur.left && _traverse(cur.left);
cur.right && _traverse(cur.right);
@ -266,9 +274,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
const cur = queue.shift();
if (cur) {
if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result;
if (propertyName === 'id') {
if (this._compare(cur.id, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left);
if (this._compare(cur.id, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right);
if (propertyName === 'key') {
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left);
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right);
} else {
cur.left && queue.push(cur.left);
cur.right && queue.push(cur.right);
@ -284,26 +292,26 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The `lesserSum` function calculates the sum of property values in a binary tree for nodes that have a property value
* less than a given node.
* @param {N | BinaryTreeNodeId | null} beginNode - The `beginNode` parameter can be one of the following:
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name to use for calculating the sum. If not provided, it defaults to `'id'`.
* specifies the property name to use for calculating the sum. If not provided, it defaults to `'key'`.
* @returns The function `lesserSum` returns a number, which represents the sum of the values of the nodes in the
* binary tree that have a lesser value than the specified `beginNode` based on the `propertyName`.
*/
lesserSum(beginNode: N | BinaryTreeNodeId | null, propertyName?: BinaryTreeNodePropertyName): number {
propertyName = propertyName ?? 'id';
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'id');
lesserSum(beginNode: N | BinaryTreeNodeKey | null, propertyName?: BinaryTreeNodePropertyName): number {
propertyName = propertyName ?? 'key';
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
if (!beginNode) return 0;
if (!this.root) return 0;
const id = beginNode.id;
const key = beginNode.key;
const getSumByPropertyName = (cur: N) => {
let needSum: number;
switch (propertyName) {
case 'id':
needSum = cur.id;
case 'key':
needSum = cur.key;
break;
default:
needSum = cur.id;
needSum = cur.key;
break;
}
return needSum;
@ -313,7 +321,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (this.loopType === LoopType.RECURSIVE) {
const _traverse = (cur: N): void => {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.eq) {
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
return;
@ -334,7 +342,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
while (queue.length > 0) {
const cur = queue.shift();
if (cur) {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.eq) {
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
return sum;
@ -358,44 +366,44 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The `allGreaterNodesAdd` function adds a delta value to the specified property of all nodes in a binary tree that
* have a greater value than a given node.
* @param {N | BinaryTreeNodeId | null} node - The `node` parameter can be either of type `N` (a generic type),
* `BinaryTreeNodeId`, or `null`. It represents the node in the binary tree to which the delta value will be added.
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type),
* `BinaryTreeNodeKey`, or `null`. It represents the node in the binary tree to which the delta value will be added.
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the property value of
* each greater node should be increased.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property name of the nodes in the binary tree that you want to update. If not provided, it defaults to
* 'id'.
* 'key'.
* @returns a boolean value.
*/
allGreaterNodesAdd(
node: N | BinaryTreeNodeId | null,
node: N | BinaryTreeNodeKey | null,
delta: number,
propertyName?: BinaryTreeNodePropertyName
): boolean {
propertyName = propertyName ?? 'id';
if (typeof node === 'number') node = this.get(node, 'id');
propertyName = propertyName ?? 'key';
if (typeof node === 'number') node = this.get(node, 'key');
if (!node) return false;
const id = node.id;
const key = node.key;
if (!this.root) return false;
const _sumByPropertyName = (cur: N) => {
switch (propertyName) {
case 'id':
cur.id += delta;
case 'key':
cur.key += delta;
break;
default:
cur.id += delta;
cur.key += delta;
break;
}
};
if (this.loopType === LoopType.RECURSIVE) {
const _traverse = (cur: N) => {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.gt) _sumByPropertyName(cur);
if (!cur.left && !cur.right) return;
if (cur.left && this._compare(cur.left.id, id) === CP.gt) _traverse(cur.left);
if (cur.right && this._compare(cur.right.id, id) === CP.gt) _traverse(cur.right);
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
};
_traverse(this.root);
@ -405,11 +413,11 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
while (queue.length > 0) {
const cur = queue.shift();
if (cur) {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.gt) _sumByPropertyName(cur);
if (cur.left && this._compare(cur.left.id, id) === CP.gt) queue.push(cur.left);
if (cur.right && this._compare(cur.right.id, id) === CP.gt) queue.push(cur.right);
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
}
}
return true;
@ -442,7 +450,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val);
this.add(midNode.key, midNode.val);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -458,7 +466,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val);
this.add(midNode.key, midNode.val);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
@ -521,12 +529,12 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The function compares two binary tree node IDs using a comparator function and returns whether the first ID is
* greater than, less than, or equal to the second ID.
* @param {BinaryTreeNodeId} a - a is a BinaryTreeNodeId, which represents the identifier of a binary tree node.
* @param {BinaryTreeNodeId} b - The parameter "b" in the above code refers to a BinaryTreeNodeId.
* @param {BinaryTreeNodeKey} a - a is a BinaryTreeNodeKey, which represents the identifier of a binary tree node.
* @param {BinaryTreeNodeKey} b - The parameter "b" in the above code refers to a BinaryTreeNodeKey.
* @returns a value of type CP (ComparisonResult). The possible return values are CP.gt (greater than), CP.lt (less
* than), or CP.eq (equal).
*/
protected _compare(a: BinaryTreeNodeId, b: BinaryTreeNodeId): CP {
protected _compare(a: BinaryTreeNodeKey, b: BinaryTreeNodeKey): CP {
const compared = this._comparator(a, b);
if (compared > 0) return CP.gt;
else if (compared < 0) return CP.lt;

View file

@ -1,4 +1,4 @@
import {BinaryTreeNodeId, RBColor, RBTreeNodeNested, RBTreeOptions} from '../../types';
import {BinaryTreeNodeKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../../types';
import {IRBTree, IRBTreeNode} from '../../interfaces';
import {BST, BSTNode} from './bst';
@ -8,8 +8,8 @@ export class RBTreeNode<V = any, NEIGHBOR extends RBTreeNode<V, NEIGHBOR> = RBTr
{
private _color: RBColor;
constructor(id: BinaryTreeNodeId, val?: V) {
super(id, val);
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);
this._color = RBColor.RED;
}
@ -27,11 +27,11 @@ export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<
super(options);
}
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new RBTreeNode(id, val) as N;
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
return new RBTreeNode(key, val) as N;
}
// override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
// override add(idOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
// const inserted = super.add(idOrNode, val);
// if (inserted) this._fixInsertViolation(inserted);
// return inserted;
@ -205,8 +205,8 @@ export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<
// node.right = null;
// }
//
// override remove(nodeOrId: BinaryTreeNodeId | N): BinaryTreeDeletedResult<N>[] {
// const node = this.get(nodeOrId);
// override remove(nodeOrKey: BinaryTreeNodeKey | N): BinaryTreeDeletedResult<N>[] {
// const node = this.get(nodeOrKey);
// const result: BinaryTreeDeletedResult<N>[] = [{deleted: undefined, needBalanced: null}];
// if (!node) return result; // Node does not exist
//

View file

@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {BinaryTreeNodeId, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType} from '../../types';
import {ITreeMultiset, ITreeMultisetNode} from '../../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
@ -15,8 +15,8 @@ export class TreeMultisetNode<V = any, NEIGHBOR extends TreeMultisetNode<V, NEIG
implements ITreeMultisetNode<V, NEIGHBOR>
{
/**
* The constructor function initializes a BinaryTreeNode object with an id, value, and count.
* @param {BinaryTreeNodeId} id - The `id` parameter is of type `BinaryTreeNodeId` and represents the unique identifier
* The constructor function initializes a BinaryTreeNode object with an key, value, and count.
* @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier
* of the binary tree node.
* @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value of the binary
* tree node. If no value is provided, it will be `undefined`.
@ -24,8 +24,8 @@ export class TreeMultisetNode<V = any, NEIGHBOR extends TreeMultisetNode<V, NEIG
* occurs in a binary tree node. It has a default value of 1, which means that if no value is provided for the `count`
* parameter when creating a new instance of the `BinaryTreeNode` class,
*/
constructor(id: BinaryTreeNodeId, val?: V, count = 1) {
super(id, val);
constructor(key: BinaryTreeNodeKey, val?: V, count = 1) {
super(key, val);
this._count = count;
}
@ -64,16 +64,16 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
}
/**
* The function creates a new BSTNode with the given id, value, and count.
* @param {BinaryTreeNodeId} id - The id parameter is the unique identifier for the binary tree node. It is used to
* The function creates a new BSTNode with the given key, value, and count.
* @param {BinaryTreeNodeKey} key - The key parameter is the unique identifier for the binary tree node. It is used to
* distinguish one node from another in the tree.
* @param {N} val - The `val` parameter represents the value that will be stored in the binary search tree node.
* @param {number} [count] - The "count" parameter is an optional parameter of type number. It represents the number of
* occurrences of the value in the binary search tree node. If not provided, the count will default to 1.
* @returns A new instance of the BSTNode class with the specified id, value, and count (if provided).
* @returns A new instance of the BSTNode class with the specified key, value, and count (if provided).
*/
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new TreeMultisetNode(id, val, count) as N;
override createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N {
return new TreeMultisetNode(key, val, count) as N;
}
/**
@ -84,17 +84,17 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
* @returns the `destNode` after swapping its values with the `srcNode`.
*/
override swapLocation(srcNode: N, destNode: N): N {
const {id, val, count, height} = destNode;
const tempNode = this.createNode(id, val, count);
const {key, val, count, height} = destNode;
const tempNode = this.createNode(key, val, count);
if (tempNode) {
tempNode.height = height;
destNode.id = srcNode.id;
destNode.key = srcNode.key;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.id = tempNode.id;
srcNode.key = tempNode.key;
srcNode.val = tempNode.val;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
@ -106,19 +106,19 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The `add` function adds a new node to a binary search tree, maintaining the tree's properties and balancing if
* necessary.
* @param {BinaryTreeNodeId | N} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId` or a `N` (which
* @param {BinaryTreeNodeKey | N} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N` (which
* represents a `BinaryTreeNode`).
* @param [val] - The `val` parameter represents the value to be added to the binary tree node.
* @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the
* value should be added to the binary tree. If the `count` parameter is not provided, it defaults to 1.
* @returns The method `add` returns either the inserted node (`N`), `null`, or `undefined`.
*/
override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val'], count?: number): N | null | undefined {
override add(idOrNode: BinaryTreeNodeKey | N | null, val?: N['val'], count?: number): N | null | undefined {
count = count ?? 1;
let inserted: N | null | undefined = undefined,
newNode: N | null;
if (idOrNode instanceof TreeMultisetNode) {
newNode = this.createNode(idOrNode.id, idOrNode.val, idOrNode.count);
newNode = this.createNode(idOrNode.key, idOrNode.val, idOrNode.count);
} else if (idOrNode === null) {
newNode = null;
} else {
@ -135,13 +135,13 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
while (traversing) {
if (cur) {
if (newNode) {
if (this._compare(cur.id, newNode.id) === CP.eq) {
if (this._compare(cur.key, newNode.key) === CP.eq) {
cur.val = newNode.val;
cur.count += newNode.count;
this._setCount(this.count + newNode.count);
traversing = false;
inserted = cur;
} else if (this._compare(cur.id, newNode.id) === CP.gt) {
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
// Traverse left of the node
if (cur.left === undefined) {
//Add to the left of the current node
@ -155,7 +155,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
//Traverse the left of the current node
if (cur.left) cur = cur.left;
}
} else if (this._compare(cur.id, newNode.id) === CP.lt) {
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
// Traverse right of the node
if (cur.right === undefined) {
//Add to the right of the current node
@ -219,7 +219,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The `addMany` function takes an array of node IDs or nodes and adds them to the tree multiset, returning an array of
* the inserted nodes.
* @param {(BinaryTreeNodeId | null)[] | (N | null)[]} idsOrNodes - An array of BinaryTreeNodeId or BinaryTreeNode
* @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} idsOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode
* objects, or null values.
* @param {N['val'][]} [data] - The `data` parameter is an optional array of values (`N['val'][]`) that corresponds to
* the nodes being added. It is used when adding nodes using the `idOrNode` and `data` arguments in the `this.add()`
@ -227,7 +227,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
*/
override addMany(
idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[],
idsOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
data?: N['val'][]
): (N | null | undefined)[] {
const inserted: (N | null | undefined)[] = [];
@ -236,7 +236,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
const idOrNode = idsOrNodes[i];
if (idOrNode instanceof TreeMultisetNode) {
inserted.push(this.add(idOrNode.id, idOrNode.val, idOrNode.count));
inserted.push(this.add(idOrNode.key, idOrNode.val, idOrNode.count));
continue;
}
@ -267,7 +267,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val, midNode.count);
this.add(midNode.key, midNode.val, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -283,7 +283,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val, midNode.count);
this.add(midNode.key, midNode.val, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
@ -296,17 +296,17 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The `remove` function removes a node from a binary search tree and returns the deleted node along with the parent
* node that needs to be balanced.
* @param {N | BinaryTreeNodeId | null} nodeOrId - The `nodeOrId` parameter can be one of the following:
* @param {N | BinaryTreeNodeKey | null} nodeOrKey - The `nodeOrKey` parameter can be one of the following:
* @param {boolean} [ignoreCount] - The `ignoreCount` parameter is an optional boolean parameter that determines
* whether to ignore the count of the node being removed. If `ignoreCount` is set to `true`, the count of the node will
* not be taken into account when removing it. If `ignoreCount` is set to `false
* @returns The function `remove` returns an array of `BinaryTreeDeletedResult<N>` objects.
*/
override remove(nodeOrId: N | BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
override remove(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const curr: N | null = this.get(nodeOrId);
const curr: N | null = this.get(nodeOrKey);
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;
@ -397,13 +397,13 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The function `subTreeSumCount` calculates the sum of the `count` property of each node in a subtree, either
* recursively or iteratively.
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
* in a binary tree. It can be either a `BinaryTreeNodeId` (a unique identifier for a node in the binary tree) or
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree) or
* `null` if the subtree is empty.
* @returns the sum of the count values of all nodes in the subtree rooted at `subTreeRoot`.
*/
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeId | null): number {
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeKey | null): number {
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
if (!subTreeRoot) return 0;
@ -434,15 +434,15 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The function `subTreeAddCount` recursively or iteratively traverses a binary tree and adds a given delta value to
* the `count` property of each node.
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
* in a binary tree. It can be either a `BinaryTreeNodeId` (a unique identifier for a node in the binary tree), a
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree), a
* `BinaryTreeNode` object, or `null` if the subtree is empty.
* @param {number} delta - The delta parameter is a number that represents the amount by which the count of each node
* in the subtree should be increased or decreased.
* @returns a boolean value.
*/
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeId | null, delta: number): boolean {
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeKey | null, delta: number): boolean {
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
if (!subTreeRoot) return false;
@ -476,14 +476,14 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or
* using a queue.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
* `N`. It represents the property of the nodes that you want to search for.
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
* return only one node that matches the `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` is set
* to `true`, the function will return only one node. If `onlyOne`
* @returns an array of nodes that match the given nodeProperty.
*/
getNodesByCount(nodeProperty: BinaryTreeNodeId | N, onlyOne?: boolean): N[] {
getNodesByCount(nodeProperty: BinaryTreeNodeKey | N, onlyOne?: boolean): N[] {
if (!this.root) return [];
const result: N[] = [];
@ -585,20 +585,20 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The `lesserSumCount` function calculates the sum of the counts of all nodes in a binary tree that have a lesser
* value than a given node.
* @param {N | BinaryTreeNodeId | null} beginNode - The `beginNode` parameter can be one of the following:
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
* @returns the sum of the counts of nodes in the binary tree that have a lesser value than the given beginNode.
*/
lesserSumCount(beginNode: N | BinaryTreeNodeId | null): number {
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'id');
lesserSumCount(beginNode: N | BinaryTreeNodeKey | null): number {
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
if (!beginNode) return 0;
if (!this.root) return 0;
const id = beginNode.id;
const key = beginNode.key;
let sum = 0;
if (this.loopType === LoopType.RECURSIVE) {
const _traverse = (cur: N): void => {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.eq) {
if (cur.right) sum += this.subTreeSumCount(cur.right);
return;
@ -619,7 +619,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
while (queue.length > 0) {
const cur = queue.shift();
if (cur) {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.eq) {
if (cur.right) sum += this.subTreeSumCount(cur.right);
return sum;
@ -643,25 +643,25 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
/**
* The function `allGreaterNodesAddCount` updates the count property of all nodes in a binary tree that have an ID
* greater than a given ID by a specified delta value.
* @param {N | BinaryTreeNodeId | null} node - The `node` parameter can be one of the following:
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be one of the following:
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the `count` property
* of each node should be increased.
* @returns a boolean value.
*/
allGreaterNodesAddCount(node: N | BinaryTreeNodeId | null, delta: number): boolean {
if (typeof node === 'number') node = this.get(node, 'id');
allGreaterNodesAddCount(node: N | BinaryTreeNodeKey | null, delta: number): boolean {
if (typeof node === 'number') node = this.get(node, 'key');
if (!node) return false;
const id = node.id;
const key = node.key;
if (!this.root) return false;
if (this.loopType === LoopType.RECURSIVE) {
const _traverse = (cur: N) => {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.gt) cur.count += delta;
if (!cur.left && !cur.right) return;
if (cur.left && this._compare(cur.left.id, id) === CP.gt) _traverse(cur.left);
if (cur.right && this._compare(cur.right.id, id) === CP.gt) _traverse(cur.right);
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
};
_traverse(this.root);
@ -671,11 +671,11 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
while (queue.length > 0) {
const cur = queue.shift();
if (cur) {
const compared = this._compare(cur.id, id);
const compared = this._compare(cur.key, key);
if (compared === CP.gt) cur.count += delta;
if (cur.left && this._compare(cur.left.id, id) === CP.gt) queue.push(cur.left);
if (cur.right && this._compare(cur.right.id, id) === CP.gt) queue.push(cur.right);
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
}
}
return true;

View file

@ -7,30 +7,30 @@
*/
import {arrayRemove, uuidV4} from '../../utils';
import {PriorityQueue} from '../priority-queue';
import type {DijkstraResult, VertexId} from '../../types';
import type {DijkstraResult, VertexKey} from '../../types';
import {IAbstractGraph} from '../../interfaces';
export abstract class AbstractVertex<V = any> {
/**
* The function is a protected constructor that takes an id and an optional value as parameters.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
* The function is a protected constructor that takes an key and an optional value as parameters.
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
* used to uniquely identify the vertex object.
* @param {V} [val] - The parameter "val" is an optional parameter of type V. It is used to assign a value to the
* vertex. If no value is provided, it will be set to undefined.
*/
protected constructor(id: VertexId, val?: V) {
this._id = id;
protected constructor(key: VertexKey, val?: V) {
this._key = key;
this._val = val;
}
private _id: VertexId;
private _key: VertexKey;
get id(): VertexId {
return this._id;
get key(): VertexKey {
return this._key;
}
set id(v: VertexId) {
this._id = v;
set key(v: VertexKey) {
this._key = v;
}
private _val: V | undefined;
@ -106,19 +106,19 @@ export abstract class AbstractGraph<
E extends AbstractEdge<any> = AbstractEdge<any>
> implements IAbstractGraph<V, E>
{
private _vertices: Map<VertexId, V> = new Map<VertexId, V>();
private _vertices: Map<VertexKey, V> = new Map<VertexKey, V>();
get vertices(): Map<VertexId, V> {
get vertices(): Map<VertexKey, V> {
return this._vertices;
}
/**
* In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it.
* This means that using abstract methods in the parent class cannot constrain the grandchild classes. Defining methods within an interface also cannot constrain the descendant classes. When inheriting from this class, developers need to be aware that this method needs to be overridden.
* @param id
* @param key
* @param val
*/
abstract createVertex(id: VertexId, val?: V): V;
abstract createVertex(key: VertexKey, val?: V): V;
/**
* In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it.
@ -128,48 +128,48 @@ export abstract class AbstractGraph<
* @param weight
* @param val
*/
abstract createEdge(srcOrV1: VertexId | string, destOrV2: VertexId | string, weight?: number, val?: E): E;
abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E;
abstract removeEdge(edge: E): E | null;
abstract getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
abstract getEdge(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null;
abstract degreeOf(vertexOrId: V | VertexId): number;
abstract degreeOf(vertexOrKey: V | VertexKey): number;
abstract edgeSet(): E[];
abstract edgesOf(vertexOrId: V | VertexId): E[];
abstract edgesOf(vertexOrKey: V | VertexKey): E[];
abstract getNeighbors(vertexOrId: V | VertexId): V[];
abstract getNeighbors(vertexOrKey: V | VertexKey): V[];
abstract getEndsOfEdge(edge: E): [V, V] | null;
/**
* The function "getVertex" returns the vertex with the specified ID or null if it doesn't exist.
* @param {VertexId} vertexId - The `vertexId` parameter is the identifier of the vertex that you want to retrieve from
* @param {VertexKey} vertexKey - The `vertexKey` parameter is the identifier of the vertex that you want to retrieve from
* the `_vertices` map.
* @returns The method `getVertex` returns the vertex with the specified `vertexId` if it exists in the `_vertices`
* @returns The method `getVertex` returns the vertex with the specified `vertexKey` if it exists in the `_vertices`
* map. If the vertex does not exist, it returns `null`.
*/
getVertex(vertexId: VertexId): V | null {
return this._vertices.get(vertexId) || null;
getVertex(vertexKey: VertexKey): V | null {
return this._vertices.get(vertexKey) || null;
}
/**
* The function checks if a vertex exists in a graph.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns a boolean value.
*/
hasVertex(vertexOrId: V | VertexId): boolean {
return this._vertices.has(this._getVertexId(vertexOrId));
hasVertex(vertexOrKey: V | VertexKey): boolean {
return this._vertices.has(this._getVertexKey(vertexOrKey));
}
addVertex(vertex: V): boolean;
addVertex(id: VertexId, val?: V['val']): boolean;
addVertex(key: VertexKey, val?: V['val']): boolean;
addVertex(idOrVertex: VertexId | V, val?: V['val']): boolean {
addVertex(idOrVertex: VertexKey | V, val?: V['val']): boolean {
if (idOrVertex instanceof AbstractVertex) {
return this._addVertexOnly(idOrVertex);
} else {
@ -180,23 +180,23 @@ export abstract class AbstractGraph<
/**
* The `removeVertex` function removes a vertex from a graph by its ID or by the vertex object itself.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns The method is returning a boolean value.
*/
removeVertex(vertexOrId: V | VertexId): boolean {
const vertexId = this._getVertexId(vertexOrId);
return this._vertices.delete(vertexId);
removeVertex(vertexOrKey: V | VertexKey): boolean {
const vertexKey = this._getVertexKey(vertexOrKey);
return this._vertices.delete(vertexKey);
}
/**
* The function removes all vertices from a graph and returns a boolean indicating if any vertices were removed.
* @param {V[] | VertexId[]} vertices - The `vertices` parameter can be either an array of vertices (`V[]`) or an array
* of vertex IDs (`VertexId[]`).
* @param {V[] | VertexKey[]} vertices - The `vertices` parameter can be either an array of vertices (`V[]`) or an array
* of vertex IDs (`VertexKey[]`).
* @returns a boolean value. It returns true if at least one vertex was successfully removed, and false if no vertices
* were removed.
*/
removeAllVertices(vertices: V[] | VertexId[]): boolean {
removeAllVertices(vertices: V[] | VertexKey[]): boolean {
const removed: boolean[] = [];
for (const v of vertices) {
removed.push(this.removeVertex(v));
@ -206,50 +206,50 @@ export abstract class AbstractGraph<
/**
* The function checks if there is an edge between two vertices and returns a boolean value indicating the result.
* @param {VertexId | V} v1 - The parameter v1 can be either a VertexId or a V. A VertexId represents the unique
* @param {VertexKey | V} v1 - The parameter v1 can be either a VertexKey or a V. A VertexKey represents the unique
* identifier of a vertex in a graph, while V represents the type of the vertex object itself.
* @param {VertexId | V} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a
* `VertexId` or a `V` type, which represents the type of the vertex.
* @param {VertexKey | V} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a
* `VertexKey` or a `V` type, which represents the type of the vertex.
* @returns A boolean value is being returned.
*/
hasEdge(v1: VertexId | V, v2: VertexId | V): boolean {
hasEdge(v1: VertexKey | V, v2: VertexKey | V): boolean {
const edge = this.getEdge(v1, v2);
return !!edge;
}
addEdge(edge: E): boolean;
addEdge(src: V | VertexId, dest: V | VertexId, weight?: number, val?: E['val']): boolean;
addEdge(src: V | VertexKey, dest: V | VertexKey, weight?: number, val?: E['val']): boolean;
addEdge(srcOrEdge: V | VertexId | E, dest?: V | VertexId, weight?: number, val?: E['val']): boolean {
addEdge(srcOrEdge: V | VertexKey | E, dest?: V | VertexKey, weight?: number, val?: E['val']): boolean {
if (srcOrEdge instanceof AbstractEdge) {
return this._addEdgeOnly(srcOrEdge);
} else {
if (dest instanceof AbstractVertex || typeof dest === 'string' || typeof dest === 'number') {
if (!(this.hasVertex(srcOrEdge) && this.hasVertex(dest))) return false;
if (srcOrEdge instanceof AbstractVertex) srcOrEdge = srcOrEdge.id;
if (dest instanceof AbstractVertex) dest = dest.id;
if (srcOrEdge instanceof AbstractVertex) srcOrEdge = srcOrEdge.key;
if (dest instanceof AbstractVertex) dest = dest.key;
const newEdge = this.createEdge(srcOrEdge, dest, weight, val);
return this._addEdgeOnly(newEdge);
} else {
throw new Error('dest must be a Vertex or vertex id while srcOrEdge is an Edge');
throw new Error('dest must be a Vertex or vertex key while srcOrEdge is an Edge');
}
}
}
/**
* The function sets the weight of an edge between two vertices in a graph.
* @param {VertexId | V} srcOrId - The `srcOrId` parameter can be either a `VertexId` or a `V` object. It represents
* @param {VertexKey | V} srcOrKey - The `srcOrKey` parameter can be either a `VertexKey` or a `V` object. It represents
* the source vertex of the edge.
* @param {VertexId | V} destOrId - The `destOrId` parameter represents the destination vertex of the edge. It can be
* either a `VertexId` or a vertex object `V`.
* @param {number} weight - The weight parameter represents the weight of the edge between the source vertex (srcOrId)
* and the destination vertex (destOrId).
* @param {VertexKey | V} destOrKey - The `destOrKey` parameter represents the destination vertex of the edge. It can be
* either a `VertexKey` or a vertex object `V`.
* @param {number} weight - The weight parameter represents the weight of the edge between the source vertex (srcOrKey)
* and the destination vertex (destOrKey).
* @returns a boolean value. If the edge exists between the source and destination vertices, the function will update
* the weight of the edge and return true. If the edge does not exist, the function will return false.
*/
setEdgeWeight(srcOrId: VertexId | V, destOrId: VertexId | V, weight: number): boolean {
const edge = this.getEdge(srcOrId, destOrId);
setEdgeWeight(srcOrKey: VertexKey | V, destOrKey: VertexKey | V, weight: number): boolean {
const edge = this.getEdge(srcOrKey, destOrKey);
if (edge) {
edge.weight = weight;
return true;
@ -260,12 +260,12 @@ export abstract class AbstractGraph<
/**
* The function `getAllPathsBetween` finds all paths between two vertices in a graph using depth-first search.
* @param {V | VertexId} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
* @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
* It is the starting vertex for finding paths.
* @param {V | VertexId} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
* @param {V | VertexKey} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
* @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`V[][]`).
*/
getAllPathsBetween(v1: V | VertexId, v2: V | VertexId): V[][] {
getAllPathsBetween(v1: V | VertexKey, v2: V | VertexKey): V[][] {
const paths: V[][] = [];
const vertex1 = this._getVertex(v1);
const vertex2 = this._getVertex(v2);
@ -312,8 +312,8 @@ export abstract class AbstractGraph<
/**
* The function `getMinCostBetween` calculates the minimum cost between two vertices in a graph, either based on edge
* weights or using a breadth-first search algorithm.
* @param {V | VertexId} v1 - The parameter `v1` represents the starting vertex or its ID.
* @param {V | VertexId} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which
* @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex or its ID.
* @param {V | VertexKey} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which
* you want to find the minimum cost or weight from the source vertex `v1`.
* @param {boolean} [isWeight] - isWeight is an optional parameter that indicates whether the graph edges have weights.
* If isWeight is set to true, the function will calculate the minimum cost between v1 and v2 based on the weights of
@ -323,7 +323,7 @@ export abstract class AbstractGraph<
* vertices. If `isWeight` is `false` or not provided, it uses a breadth-first search (BFS) algorithm to calculate the
* minimum number of
*/
getMinCostBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): number | null {
getMinCostBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): number | null {
if (isWeight === undefined) isWeight = false;
if (isWeight) {
@ -371,9 +371,9 @@ export abstract class AbstractGraph<
/**
* The function `getMinPathBetween` returns the minimum path between two vertices in a graph, either based on weight or
* using a breadth-first search algorithm.
* @param {V | VertexId} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex
* object (`V`) or a vertex ID (`VertexId`).
* @param {V | VertexId} v2 - V | VertexId - The second vertex or vertex ID between which we want to find the minimum
* @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex
* object (`V`) or a vertex ID (`VertexKey`).
* @param {V | VertexKey} v2 - V | VertexKey - The second vertex or vertex ID between which we want to find the minimum
* path.
* @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
* minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
@ -381,7 +381,7 @@ export abstract class AbstractGraph<
* @returns The function `getMinPathBetween` returns an array of vertices (`V[]`) representing the minimum path between
* two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
*/
getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null {
getMinPathBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): V[] | null {
if (isWeight === undefined) isWeight = false;
if (isWeight) {
@ -440,9 +440,9 @@ export abstract class AbstractGraph<
* Dijkstra algorithm time: O(VE) space: O(V + E)
* The function `dijkstraWithoutHeap` implements Dijkstra's algorithm to find the shortest path between two vertices in
* a graph without using a heap data structure.
* @param {V | VertexId} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a
* @param {V | VertexKey} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a
* vertex object or a vertex ID.
* @param {V | VertexId | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
* @param {V | VertexKey | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
* parameter that specifies the destination vertex for the Dijkstra algorithm. It can be either a vertex object or its
* identifier. If no destination is provided, the value is set to `null`.
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
@ -454,8 +454,8 @@ export abstract class AbstractGraph<
* @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult<V>`.
*/
dijkstraWithoutHeap(
src: V | VertexId,
dest?: V | VertexId | null,
src: V | VertexKey,
dest?: V | VertexKey | null,
getMinDist?: boolean,
genPaths?: boolean
): DijkstraResult<V> {
@ -481,8 +481,8 @@ export abstract class AbstractGraph<
}
for (const vertex of vertices) {
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
const vertexOrKey = vertex[1];
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
}
distMap.set(srcVertex, 0);
preMap.set(srcVertex, null);
@ -503,11 +503,11 @@ export abstract class AbstractGraph<
const getPaths = (minV: V | null) => {
for (const vertex of vertices) {
const vertexOrId = vertex[1];
const vertexOrKey = vertex[1];
if (vertexOrId instanceof AbstractVertex) {
const path: V[] = [vertexOrId];
let parent = preMap.get(vertexOrId);
if (vertexOrKey instanceof AbstractVertex) {
const path: V[] = [vertexOrKey];
let parent = preMap.get(vertexOrKey);
while (parent) {
path.push(parent);
parent = preMap.get(parent);
@ -580,9 +580,9 @@ export abstract class AbstractGraph<
* Dijkstra's algorithm is used to find the shortest paths from a source node to all other nodes in a graph. Its basic idea is to repeatedly choose the node closest to the source node and update the distances of other nodes using this node as an intermediary. Dijkstra's algorithm requires that the edge weights in the graph are non-negative.
* The `dijkstra` function implements Dijkstra's algorithm to find the shortest path between a source vertex and an
* optional destination vertex, and optionally returns the minimum distance, the paths, and other information.
* @param {V | VertexId} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will
* @param {V | VertexKey} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will
* start. It can be either a vertex object or a vertex ID.
* @param {V | VertexId | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
* @param {V | VertexKey | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
* vertex to which the shortest path is calculated from the source vertex. If no destination is provided, the algorithm
* will calculate the shortest paths to all other vertices from the source vertex.
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
@ -593,7 +593,12 @@ export abstract class AbstractGraph<
* shortest paths from the source vertex to all other vertices in the graph. If `genPaths
* @returns The function `dijkstra` returns an object of type `DijkstraResult<V>`.
*/
dijkstra(src: V | VertexId, dest?: V | VertexId | null, getMinDist?: boolean, genPaths?: boolean): DijkstraResult<V> {
dijkstra(
src: V | VertexKey,
dest?: V | VertexKey | null,
getMinDist?: boolean,
genPaths?: boolean
): DijkstraResult<V> {
if (getMinDist === undefined) getMinDist = false;
if (genPaths === undefined) genPaths = false;
@ -613,14 +618,14 @@ export abstract class AbstractGraph<
if (!srcVertex) return null;
for (const vertex of vertices) {
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
const vertexOrKey = vertex[1];
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
}
const heap = new PriorityQueue<{id: number; val: V}>({
comparator: (a, b) => a.id - b.id
const heap = new PriorityQueue<{key: number; val: V}>({
comparator: (a, b) => a.key - b.key
});
heap.add({id: 0, val: srcVertex});
heap.add({key: 0, val: srcVertex});
distMap.set(srcVertex, 0);
preMap.set(srcVertex, null);
@ -632,10 +637,10 @@ export abstract class AbstractGraph<
*/
const getPaths = (minV: V | null) => {
for (const vertex of vertices) {
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) {
const path: V[] = [vertexOrId];
let parent = preMap.get(vertexOrId);
const vertexOrKey = vertex[1];
if (vertexOrKey instanceof AbstractVertex) {
const path: V[] = [vertexOrKey];
let parent = preMap.get(vertexOrKey);
while (parent) {
path.push(parent);
parent = preMap.get(parent);
@ -649,7 +654,7 @@ export abstract class AbstractGraph<
while (heap.size > 0) {
const curHeapNode = heap.poll();
const dist = curHeapNode?.id;
const dist = curHeapNode?.key;
const cur = curHeapNode?.val;
if (dist !== undefined) {
if (cur) {
@ -671,7 +676,7 @@ export abstract class AbstractGraph<
const distSrcToNeighbor = distMap.get(neighbor);
if (distSrcToNeighbor) {
if (dist + weight < distSrcToNeighbor) {
heap.add({id: dist + weight, val: neighbor});
heap.add({key: dist + weight, val: neighbor});
preMap.set(neighbor, cur);
distMap.set(neighbor, dist + weight);
}
@ -712,7 +717,7 @@ export abstract class AbstractGraph<
* The Bellman-Ford algorithm is also used to find the shortest paths from a source node to all other nodes in a graph. Unlike Dijkstra's algorithm, it can handle edge weights that are negative. Its basic idea involves iterative relaxation of all edges for several rounds to gradually approximate the shortest paths. Due to its ability to handle negative-weight edges, the Bellman-Ford algorithm is more flexible in some scenarios.
* The `bellmanFord` function implements the Bellman-Ford algorithm to find the shortest path from a source vertex to
* all other vertices in a graph, and optionally detects negative cycles and generates the minimum path.
* @param {V | VertexId} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will
* @param {V | VertexKey} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will
* start calculating the shortest paths. It can be either a vertex object or a vertex ID.
* @param {boolean} [scanNegativeCycle] - A boolean flag indicating whether to scan for negative cycles in the graph.
* @param {boolean} [getMin] - The `getMin` parameter is a boolean flag that determines whether the algorithm should
@ -722,7 +727,7 @@ export abstract class AbstractGraph<
* vertex.
* @returns The function `bellmanFord` returns an object with the following properties:
*/
bellmanFord(src: V | VertexId, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) {
bellmanFord(src: V | VertexKey, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) {
if (getMin === undefined) getMin = false;
if (genPath === undefined) genPath = false;
@ -780,10 +785,10 @@ export abstract class AbstractGraph<
if (genPath) {
for (const vertex of vertices) {
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) {
const path: V[] = [vertexOrId];
let parent = preMap.get(vertexOrId);
const vertexOrKey = vertex[1];
if (vertexOrKey instanceof AbstractVertex) {
const path: V[] = [vertexOrKey];
let parent = preMap.get(vertexOrKey);
while (parent !== undefined) {
path.push(parent);
parent = preMap.get(parent);
@ -1019,22 +1024,22 @@ export abstract class AbstractGraph<
protected _addVertexOnly(newVertex: V): boolean {
if (this.hasVertex(newVertex)) {
return false;
// throw (new Error('Duplicated vertex id is not allowed'));
// throw (new Error('Duplicated vertex key is not allowed'));
}
this._vertices.set(newVertex.id, newVertex);
this._vertices.set(newVertex.key, newVertex);
return true;
}
protected _getVertex(vertexOrId: VertexId | V): V | null {
const vertexId = this._getVertexId(vertexOrId);
return this._vertices.get(vertexId) || null;
protected _getVertex(vertexOrKey: VertexKey | V): V | null {
const vertexKey = this._getVertexKey(vertexOrKey);
return this._vertices.get(vertexKey) || null;
}
protected _getVertexId(vertexOrId: V | VertexId): VertexId {
return vertexOrId instanceof AbstractVertex ? vertexOrId.id : vertexOrId;
protected _getVertexKey(vertexOrKey: V | VertexKey): VertexKey {
return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
}
protected _setVertices(value: Map<VertexId, V>) {
protected _setVertices(value: Map<VertexKey, V>) {
this._vertices = value;
}
}

View file

@ -7,19 +7,19 @@
*/
import {arrayRemove} from '../../utils';
import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph';
import type {TopologicalStatus, VertexId} from '../../types';
import type {TopologicalStatus, VertexKey} from '../../types';
import {IDirectedGraph} from '../../interfaces';
export class DirectedVertex<V = any> extends AbstractVertex<V> {
/**
* The constructor function initializes a vertex with an optional value.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
* used to uniquely identify the vertex within a graph or data structure.
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the
* vertex. If no value is provided, the vertex will be initialized with a default value.
*/
constructor(id: VertexId, val?: V) {
super(id, val);
constructor(key: VertexKey, val?: V) {
super(key, val);
}
}
@ -27,37 +27,37 @@ export class DirectedEdge<V = any> extends AbstractEdge<V> {
/**
* The constructor function initializes the source and destination vertices of an edge, along with an optional weight
* and value.
* @param {VertexId} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
* @param {VertexKey} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
* a graph.
* @param {VertexId} dest - The `dest` parameter represents the destination vertex of an edge. It is of type
* `VertexId`, which is likely a unique identifier for a vertex in a graph.
* @param {VertexKey} dest - The `dest` parameter represents the destination vertex of an edge. It is of type
* `VertexKey`, which is likely a unique identifier for a vertex in a graph.
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
* @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value associated with
* the edge.
*/
constructor(src: VertexId, dest: VertexId, weight?: number, val?: V) {
constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) {
super(weight, val);
this._src = src;
this._dest = dest;
}
private _src: VertexId;
private _src: VertexKey;
get src(): VertexId {
get src(): VertexKey {
return this._src;
}
set src(v: VertexId) {
set src(v: VertexKey) {
this._src = v;
}
private _dest: VertexId;
private _dest: VertexKey;
get dest(): VertexId {
get dest(): VertexKey {
return this._dest;
}
set dest(v: VertexId) {
set dest(v: VertexKey) {
this._dest = v;
}
}
@ -92,15 +92,15 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function creates a new vertex with an optional value and returns it.
* @param {VertexId} id - The `id` parameter is the unique identifier for the vertex. It is of type `VertexId`, which
* @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is of type `VertexKey`, which
* could be a number or a string depending on how you want to identify your vertices.
* @param [val] - The 'val' parameter is an optional value that can be assigned to the vertex. If a value is provided,
* it will be assigned to the 'val' property of the vertex. If no value is provided, the 'val' property will be
* assigned the same value as the 'id' parameter
* assigned the same value as the 'key' parameter
* @returns a new instance of a DirectedVertex object, casted as type V.
*/
createVertex(id: VertexId, val?: V['val']): V {
return new DirectedVertex(id, val ?? id) as V;
createVertex(key: VertexKey, val?: V['val']): V {
return new DirectedVertex(key, val ?? key) as V;
}
/**
@ -110,37 +110,37 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function creates a directed edge between two vertices with an optional weight and value.
* @param {VertexId} src - The source vertex ID of the edge. It represents the starting point of the edge.
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for the edge.
* @param {VertexKey} src - The source vertex ID of the edge. It represents the starting point of the edge.
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for the edge.
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. If no
* weight is provided, it defaults to 1.
* @param [val] - The 'val' parameter is an optional value that can be assigned to the edge. It can be of any type and
* is used to store additional information or data associated with the edge.
* @returns a new instance of a DirectedEdge object, casted as type E.
*/
createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E {
return new DirectedEdge(src, dest, weight ?? 1, val) as E;
}
/**
* The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs.
* @param {V | null | VertexId} srcOrId - The source vertex or its ID. It can be either a vertex object or a vertex ID.
* @param {V | null | VertexId} destOrId - The `destOrId` parameter in the `getEdge` function represents the
* destination vertex of the edge. It can be either a vertex object (`V`), a vertex ID (`VertexId`), or `null` if the
* @param {V | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID.
* @param {V | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the
* destination vertex of the edge. It can be either a vertex object (`V`), a vertex ID (`VertexKey`), or `null` if the
* destination is not specified.
* @returns the first edge found between the source and destination vertices, or null if no such edge is found.
*/
getEdge(srcOrId: V | null | VertexId, destOrId: V | null | VertexId): E | null {
getEdge(srcOrKey: V | null | VertexKey, destOrKey: V | null | VertexKey): E | null {
let edges: E[] = [];
if (srcOrId !== null && destOrId !== null) {
const src: V | null = this._getVertex(srcOrId);
const dest: V | null = this._getVertex(destOrId);
if (srcOrKey !== null && destOrKey !== null) {
const src: V | null = this._getVertex(srcOrKey);
const dest: V | null = this._getVertex(destOrKey);
if (src && dest) {
const srcOutEdges = this._outEdgeMap.get(src);
if (srcOutEdges) {
edges = srcOutEdges.filter(edge => edge.dest === dest.id);
edges = srcOutEdges.filter(edge => edge.dest === dest.key);
}
}
}
@ -150,13 +150,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function removes an edge between two vertices in a graph and returns the removed edge.
* @param {V | VertexId} srcOrId - The source vertex or its ID.
* @param {V | VertexId} destOrId - The `destOrId` parameter represents the destination vertex or its ID.
* @param {V | VertexKey} srcOrKey - The source vertex or its ID.
* @param {V | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID.
* @returns the removed edge (E) if it exists, or null if either the source or destination vertex does not exist.
*/
removeEdgeSrcToDest(srcOrId: V | VertexId, destOrId: V | VertexId): E | null {
const src: V | null = this._getVertex(srcOrId);
const dest: V | null = this._getVertex(destOrId);
removeEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null {
const src: V | null = this._getVertex(srcOrKey);
const dest: V | null = this._getVertex(destOrKey);
let removed: E | null = null;
if (!src || !dest) {
return null;
@ -164,12 +164,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
const srcOutEdges = this._outEdgeMap.get(src);
if (srcOutEdges) {
arrayRemove<E>(srcOutEdges, (edge: E) => edge.dest === dest.id);
arrayRemove<E>(srcOutEdges, (edge: E) => edge.dest === dest.key);
}
const destInEdges = this._inEdgeMap.get(dest);
if (destInEdges) {
removed = arrayRemove<E>(destInEdges, (edge: E) => edge.src === src.id)[0] || null;
removed = arrayRemove<E>(destInEdges, (edge: E) => edge.src === src.key)[0] || null;
}
return removed;
}
@ -187,12 +187,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
if (src && dest) {
const srcOutEdges = this._outEdgeMap.get(src);
if (srcOutEdges && srcOutEdges.length > 0) {
arrayRemove(srcOutEdges, (edge: E) => edge.src === src.id);
arrayRemove(srcOutEdges, (edge: E) => edge.src === src.key);
}
const destInEdges = this._inEdgeMap.get(dest);
if (destInEdges && destInEdges.length > 0) {
removed = arrayRemove(destInEdges, (edge: E) => edge.dest === dest.id)[0];
removed = arrayRemove(destInEdges, (edge: E) => edge.dest === dest.key)[0];
}
}
@ -201,13 +201,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function removes edges between two vertices and returns the removed edges.
* @param {VertexId | V} v1 - The parameter `v1` can be either a `VertexId` or a `V`. A `VertexId` represents the
* @param {VertexKey | V} v1 - The parameter `v1` can be either a `VertexKey` or a `V`. A `VertexKey` represents the
* unique identifier of a vertex in a graph, while `V` represents the actual vertex object.
* @param {VertexId | V} v2 - The parameter `v2` represents either a `VertexId` or a `V` object. It is used to specify
* @param {VertexKey | V} v2 - The parameter `v2` represents either a `VertexKey` or a `V` object. It is used to specify
* the second vertex in the edge that needs to be removed.
* @returns an array of removed edges (E[]).
*/
removeEdgesBetween(v1: VertexId | V, v2: VertexId | V): E[] {
removeEdgesBetween(v1: VertexKey | V, v2: VertexKey | V): E[] {
const removed: E[] = [];
if (v1 && v2) {
@ -223,12 +223,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function `incomingEdgesOf` returns an array of incoming edges for a given vertex or vertex ID.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns The method `incomingEdgesOf` returns an array of edges (`E[]`).
*/
incomingEdgesOf(vertexOrId: V | VertexId): E[] {
const target = this._getVertex(vertexOrId);
incomingEdgesOf(vertexOrKey: V | VertexKey): E[] {
const target = this._getVertex(vertexOrKey);
if (target) {
return this.inEdgeMap.get(target) || [];
}
@ -237,12 +237,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function `outgoingEdgesOf` returns an array of outgoing edges from a given vertex or vertex ID.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can accept either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can accept either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns The method `outgoingEdgesOf` returns an array of edges (`E[]`).
*/
outgoingEdgesOf(vertexOrId: V | VertexId): E[] {
const target = this._getVertex(vertexOrId);
outgoingEdgesOf(vertexOrKey: V | VertexKey): E[] {
const target = this._getVertex(vertexOrKey);
if (target) {
return this._outEdgeMap.get(target) || [];
}
@ -251,38 +251,38 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function "degreeOf" returns the total degree of a vertex, which is the sum of its out-degree and in-degree.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
* @returns The sum of the out-degree and in-degree of the specified vertex or vertex ID.
*/
degreeOf(vertexOrId: VertexId | V): number {
return this.outDegreeOf(vertexOrId) + this.inDegreeOf(vertexOrId);
degreeOf(vertexOrKey: VertexKey | V): number {
return this.outDegreeOf(vertexOrKey) + this.inDegreeOf(vertexOrKey);
}
/**
* The function "inDegreeOf" returns the number of incoming edges for a given vertex.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
* @returns The number of incoming edges of the specified vertex or vertex ID.
*/
inDegreeOf(vertexOrId: VertexId | V): number {
return this.incomingEdgesOf(vertexOrId).length;
inDegreeOf(vertexOrKey: VertexKey | V): number {
return this.incomingEdgesOf(vertexOrKey).length;
}
/**
* The function `outDegreeOf` returns the number of outgoing edges from a given vertex.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
* @returns The number of outgoing edges from the specified vertex or vertex ID.
*/
outDegreeOf(vertexOrId: VertexId | V): number {
return this.outgoingEdgesOf(vertexOrId).length;
outDegreeOf(vertexOrKey: VertexKey | V): number {
return this.outgoingEdgesOf(vertexOrKey).length;
}
/**
* The function "edgesOf" returns an array of both outgoing and incoming edges of a given vertex or vertex ID.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
* @returns The function `edgesOf` returns an array of edges.
*/
edgesOf(vertexOrId: VertexId | V): E[] {
return [...this.outgoingEdgesOf(vertexOrId), ...this.incomingEdgesOf(vertexOrId)];
edgesOf(vertexOrKey: VertexKey | V): E[] {
return [...this.outgoingEdgesOf(vertexOrKey), ...this.incomingEdgesOf(vertexOrKey)];
}
/**
@ -305,11 +305,11 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function `getDestinations` returns an array of destination vertices connected to a given vertex.
* @param {V | VertexId | null} vertex - The `vertex` parameter represents the starting vertex from which we want to
* find the destinations. It can be either a `V` object, a `VertexId` value, or `null`.
* @param {V | VertexKey | null} vertex - The `vertex` parameter represents the starting vertex from which we want to
* find the destinations. It can be either a `V` object, a `VertexKey` value, or `null`.
* @returns an array of vertices (V[]).
*/
getDestinations(vertex: V | VertexId | null): V[] {
getDestinations(vertex: V | VertexKey | null): V[] {
if (vertex === null) {
return [];
}
@ -327,23 +327,23 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The `topologicalSort` function performs a topological sort on a graph and returns an array of vertices or vertex IDs
* in the sorted order, or null if the graph contains a cycle.
* @param {'vertex' | 'id'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'id'. If 'vertex' is
* specified, the vertices themselves will be used for sorting. If 'id' is specified, the ids of
* @param {'vertex' | 'key'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'key'. If 'vertex' is
* specified, the vertices themselves will be used for sorting. If 'key' is specified, the ids of
* @returns an array of vertices or vertex IDs in topological order. If there is a cycle in the graph, it returns null.
*/
topologicalSort(propertyName?: 'vertex' | 'id'): Array<V | VertexId> | null {
propertyName = propertyName ?? 'id';
topologicalSort(propertyName?: 'vertex' | 'key'): Array<V | VertexKey> | null {
propertyName = propertyName ?? 'key';
// When judging whether there is a cycle in the undirected graph, all nodes with degree of **<= 1** are enqueued
// When judging whether there is a cycle in the directed graph, all nodes with **in degree = 0** are enqueued
const statusMap: Map<V | VertexId, TopologicalStatus> = new Map<V | VertexId, TopologicalStatus>();
const statusMap: Map<V | VertexKey, TopologicalStatus> = new Map<V | VertexKey, TopologicalStatus>();
for (const entry of this.vertices) {
statusMap.set(entry[1], 0);
}
let sorted: (V | VertexId)[] = [];
let sorted: (V | VertexKey)[] = [];
let hasCycle = false;
const dfs = (cur: V | VertexId) => {
const dfs = (cur: V | VertexKey) => {
statusMap.set(cur, 1);
const children = this.getDestinations(cur);
for (const child of children) {
@ -366,7 +366,7 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
if (hasCycle) return null;
if (propertyName === 'id') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.id : vertex));
if (propertyName === 'key') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.key : vertex));
return sorted.reverse();
}
@ -384,13 +384,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* The function `getNeighbors` returns an array of neighboring vertices of a given vertex or vertex ID in a graph.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns an array of vertices (V[]).
*/
getNeighbors(vertexOrId: V | VertexId): V[] {
getNeighbors(vertexOrKey: V | VertexKey): V[] {
const neighbors: V[] = [];
const vertex = this._getVertex(vertexOrId);
const vertex = this._getVertex(vertexOrKey);
if (vertex) {
const outEdges = this.outgoingEdgesOf(vertex);
for (const outEdge of outEdges) {

View file

@ -1,10 +1,10 @@
import {MapGraphCoordinate, VertexId} from '../../types';
import {MapGraphCoordinate, VertexKey} from '../../types';
import {DirectedEdge, DirectedGraph, DirectedVertex} from './directed-graph';
export class MapVertex<V = any> extends DirectedVertex<V> {
/**
* The constructor function initializes an object with an id, latitude, longitude, and an optional value.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex.
* The constructor function initializes an object with an key, latitude, longitude, and an optional value.
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex.
* @param {number} lat - The "lat" parameter represents the latitude of a vertex. Latitude is a geographic coordinate
* that specifies the north-south position of a point on the Earth's surface. It is measured in degrees, with positive
* values representing points north of the equator and negative values representing points south of the equator.
@ -14,8 +14,8 @@ export class MapVertex<V = any> extends DirectedVertex<V> {
* @param {V} [val] - The "val" parameter is an optional value of type V. It is not required to be provided when
* creating an instance of the class.
*/
constructor(id: VertexId, lat: number, long: number, val?: V) {
super(id, val);
constructor(key: VertexKey, lat: number, long: number, val?: V) {
super(key, val);
this._lat = lat;
this._long = long;
}
@ -45,14 +45,14 @@ export class MapEdge<V = any> extends DirectedEdge<V> {
/**
* The constructor function initializes a new instance of a class with the given source, destination, weight, and
* value.
* @param {VertexId} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
* @param {VertexKey} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
* a graph.
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for an edge.
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for an edge.
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store additional
* information or data associated with the edge.
*/
constructor(src: VertexId, dest: VertexId, weight?: number, val?: V) {
constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) {
super(src, dest, weight, val);
}
}
@ -97,8 +97,8 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
}
/**
* The function creates a new vertex with the given id, value, latitude, and longitude.
* @param {VertexId} id - The id parameter is the unique identifier for the vertex. It is of type VertexId, which could
* The function creates a new vertex with the given key, value, latitude, and longitude.
* @param {VertexKey} key - The key parameter is the unique identifier for the vertex. It is of type VertexKey, which could
* be a string or a number depending on how you define it in your code.
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the vertex. It
* is of type `V['val']`, which means it should be of the same type as the `val` property of the vertex class `V`.
@ -107,14 +107,19 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
* @param {number} long - The `long` parameter represents the longitude coordinate of the vertex.
* @returns The method is returning a new instance of the `MapVertex` class, casted as type `V`.
*/
override createVertex(id: VertexId, val?: V['val'], lat: number = this.origin[0], long: number = this.origin[1]): V {
return new MapVertex(id, lat, long, val) as V;
override createVertex(
key: VertexKey,
val?: V['val'],
lat: number = this.origin[0],
long: number = this.origin[1]
): V {
return new MapVertex(key, lat, long, val) as V;
}
/**
* The function creates a new instance of a MapEdge with the given source, destination, weight, and value.
* @param {VertexId} src - The source vertex ID of the edge. It represents the starting point of the edge.
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for the edge being
* @param {VertexKey} src - The source vertex ID of the edge. It represents the starting point of the edge.
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for the edge being
* created.
* @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. It
* is used to assign a numerical value to the edge, which can be used in algorithms such as shortest path algorithms.
@ -123,7 +128,7 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
* depending on the specific implementation of the `MapEdge` class.
* @returns a new instance of the `MapEdge` class, casted as type `E`.
*/
override createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
override createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E {
return new MapEdge(src, dest, weight, val) as E;
}
}

View file

@ -7,19 +7,19 @@
*/
import {arrayRemove} from '../../utils';
import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph';
import type {VertexId} from '../../types';
import type {VertexKey} from '../../types';
import {IUNDirectedGraph} from '../../interfaces';
export class UndirectedVertex<V = any> extends AbstractVertex<V> {
/**
* The constructor function initializes a vertex with an optional value.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
* used to uniquely identify the vertex within a graph or network.
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the
* vertex. If no value is provided, the vertex will be initialized with a default value.
*/
constructor(id: VertexId, val?: V) {
super(id, val);
constructor(key: VertexKey, val?: V) {
super(key, val);
}
}
@ -27,25 +27,25 @@ export class UndirectedEdge<V = number> extends AbstractEdge<V> {
/**
* The constructor function creates an instance of a class with two vertex IDs, an optional weight, and an optional
* value.
* @param {VertexId} v1 - The first vertex ID of the edge.
* @param {VertexId} v2 - The parameter `v2` is a `VertexId`, which represents the identifier of the second vertex in a
* @param {VertexKey} v1 - The first vertex ID of the edge.
* @param {VertexKey} v2 - The parameter `v2` is a `VertexKey`, which represents the identifier of the second vertex in a
* graph edge.
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store a value associated
* with the edge.
*/
constructor(v1: VertexId, v2: VertexId, weight?: number, val?: V) {
constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: V) {
super(weight, val);
this._vertices = [v1, v2];
}
private _vertices: [VertexId, VertexId];
private _vertices: [VertexKey, VertexKey];
get vertices() {
return this._vertices;
}
set vertices(v: [VertexId, VertexId]) {
set vertices(v: [VertexKey, VertexKey]) {
this._vertices = v;
}
}
@ -73,40 +73,40 @@ export class UndirectedGraph<
/**
* The function creates a new vertex with an optional value and returns it.
* @param {VertexId} id - The `id` parameter is the unique identifier for the vertex. It is used to distinguish one
* @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is used to distinguish one
* vertex from another in the graph.
* @param [val] - The `val` parameter is an optional value that can be assigned to the vertex. If a value is provided,
* it will be used as the value of the vertex. If no value is provided, the `id` parameter will be used as the value of
* it will be used as the value of the vertex. If no value is provided, the `key` parameter will be used as the value of
* the vertex.
* @returns The method is returning a new instance of the `UndirectedVertex` class, casted as type `V`.
*/
override createVertex(id: VertexId, val?: V['val']): V {
return new UndirectedVertex(id, val ?? id) as V;
override createVertex(key: VertexKey, val?: V['val']): V {
return new UndirectedVertex(key, val ?? key) as V;
}
/**
* The function creates an undirected edge between two vertices with an optional weight and value.
* @param {VertexId} v1 - The parameter `v1` represents the first vertex of the edge.
* @param {VertexId} v2 - The parameter `v2` represents the second vertex of the edge.
* @param {VertexKey} v1 - The parameter `v1` represents the first vertex of the edge.
* @param {VertexKey} v2 - The parameter `v2` represents the second vertex of the edge.
* @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. If
* no weight is provided, it defaults to 1.
* @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type and
* is used to store additional information or data associated with the edge.
* @returns a new instance of the `UndirectedEdge` class, which is casted as type `E`.
*/
override createEdge(v1: VertexId, v2: VertexId, weight?: number, val?: E['val']): E {
override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, val?: E['val']): E {
return new UndirectedEdge(v1, v2, weight ?? 1, val) as E;
}
/**
* The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists.
* @param {V | null | VertexId} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `V` (vertex
* object), `null`, or `VertexId` (a string or number representing the ID of a vertex).
* @param {V | null | VertexId} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `V` (vertex
* object), `null`, or `VertexId` (vertex ID).
* @param {V | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `V` (vertex
* object), `null`, or `VertexKey` (a string or number representing the ID of a vertex).
* @param {V | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `V` (vertex
* object), `null`, or `VertexKey` (vertex ID).
* @returns an edge (E) or null.
*/
getEdge(v1: V | null | VertexId, v2: V | null | VertexId): E | null {
getEdge(v1: V | null | VertexKey, v2: V | null | VertexKey): E | null {
let edges: E[] | undefined = [];
if (v1 !== null && v2 !== null) {
@ -114,7 +114,7 @@ export class UndirectedGraph<
const vertex2: V | null = this._getVertex(v2);
if (vertex1 && vertex2) {
edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.id));
edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.key));
}
}
@ -123,12 +123,12 @@ export class UndirectedGraph<
/**
* The function removes an edge between two vertices in a graph and returns the removed edge.
* @param {V | VertexId} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
* @param {V | VertexId} v2 - V | VertexId - This parameter can be either a vertex object (V) or a vertex ID
* (VertexId). It represents the second vertex of the edge that needs to be removed.
* @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
* @param {V | VertexKey} v2 - V | VertexKey - This parameter can be either a vertex object (V) or a vertex ID
* (VertexKey). It represents the second vertex of the edge that needs to be removed.
* @returns the removed edge (E) if it exists, or null if either of the vertices (V) does not exist.
*/
removeEdgeBetween(v1: V | VertexId, v2: V | VertexId): E | null {
removeEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null {
const vertex1: V | null = this._getVertex(v1);
const vertex2: V | null = this._getVertex(v2);
@ -139,11 +139,11 @@ export class UndirectedGraph<
const v1Edges = this._edges.get(vertex1);
let removed: E | null = null;
if (v1Edges) {
removed = arrayRemove<E>(v1Edges, (e: E) => e.vertices.includes(vertex2.id))[0] || null;
removed = arrayRemove<E>(v1Edges, (e: E) => e.vertices.includes(vertex2.key))[0] || null;
}
const v2Edges = this._edges.get(vertex2);
if (v2Edges) {
arrayRemove<E>(v2Edges, (e: E) => e.vertices.includes(vertex1.id));
arrayRemove<E>(v2Edges, (e: E) => e.vertices.includes(vertex1.key));
}
return removed;
}
@ -160,12 +160,12 @@ export class UndirectedGraph<
/**
* The function `degreeOf` returns the degree of a vertex in a graph, which is the number of edges connected to that
* vertex.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
* @returns The function `degreeOf` returns the degree of a vertex in a graph. The degree of a vertex is the number of
* edges connected to that vertex.
*/
degreeOf(vertexOrId: VertexId | V): number {
const vertex = this._getVertex(vertexOrId);
degreeOf(vertexOrKey: VertexKey | V): number {
const vertex = this._getVertex(vertexOrKey);
if (vertex) {
return this._edges.get(vertex)?.length || 0;
} else {
@ -175,12 +175,12 @@ export class UndirectedGraph<
/**
* The function returns the edges of a given vertex or vertex ID.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`. A `VertexId` is a
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. A `VertexKey` is a
* unique identifier for a vertex in a graph, while `V` represents the type of the vertex.
* @returns an array of edges.
*/
edgesOf(vertexOrId: VertexId | V): E[] {
const vertex = this._getVertex(vertexOrId);
edgesOf(vertexOrKey: VertexKey | V): E[] {
const vertex = this._getVertex(vertexOrKey);
if (vertex) {
return this._edges.get(vertex) || [];
} else {
@ -204,17 +204,17 @@ export class UndirectedGraph<
/**
* The function "getNeighbors" returns an array of neighboring vertices for a given vertex or vertex ID.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
* (`VertexKey`).
* @returns an array of vertices (V[]).
*/
getNeighbors(vertexOrId: V | VertexId): V[] {
getNeighbors(vertexOrKey: V | VertexKey): V[] {
const neighbors: V[] = [];
const vertex = this._getVertex(vertexOrId);
const vertex = this._getVertex(vertexOrKey);
if (vertex) {
const neighborEdges = this.edgesOf(vertex);
for (const edge of neighborEdges) {
const neighbor = this._getVertex(edge.vertices.filter(e => e !== vertex.id)[0]);
const neighbor = this._getVertex(edge.vertices.filter(e => e !== vertex.key)[0]);
if (neighbor) {
neighbors.push(neighbor);
}

View file

@ -1,18 +1,18 @@
export class TreeNode<V = any> {
constructor(id: string, value?: V, children?: TreeNode<V>[]) {
this._id = id;
constructor(key: string, value?: V, children?: TreeNode<V>[]) {
this._key = key;
this._value = value || undefined;
this._children = children || [];
}
private _id: string;
private _key: string;
get id(): string {
return this._id;
get key(): string {
return this._key;
}
set id(value: string) {
this._id = value;
set key(value: string) {
this._key = value;
}
private _value?: V | undefined;

View file

@ -2,7 +2,7 @@ import {
AbstractBinaryTreeNodeProperties,
AbstractBinaryTreeNodeProperty,
BinaryTreeDeletedResult,
BinaryTreeNodeId,
BinaryTreeNodeKey,
BinaryTreeNodePropertyName,
DFSOrderPattern,
FamilyPosition,
@ -12,9 +12,9 @@ import {
import {AbstractBinaryTreeNode} from '../data-structures';
export interface IAbstractBinaryTreeNode<T, NEIGHBOR extends IAbstractBinaryTreeNode<T, NEIGHBOR>> {
get id(): BinaryTreeNodeId;
get key(): BinaryTreeNodeKey;
set id(v: BinaryTreeNodeId);
set key(v: BinaryTreeNodeKey);
get val(): T | undefined;
@ -40,11 +40,11 @@ export interface IAbstractBinaryTreeNode<T, NEIGHBOR extends IAbstractBinaryTree
}
export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'], N>> {
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null;
createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N | null;
get loopType(): LoopType;
get visitedId(): BinaryTreeNodeId[];
get visitedKey(): BinaryTreeNodeKey[];
get visitedVal(): Array<N['val']>;
@ -60,13 +60,13 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
isEmpty(): boolean;
add(id: BinaryTreeNodeId | N, val?: N['val']): N | null | undefined;
add(key: BinaryTreeNodeKey | N, val?: N['val']): N | null | undefined;
addMany(idsOrNodes: (BinaryTreeNodeId | N | null)[], data?: N['val'][]): (N | null | undefined)[];
addMany(idsOrNodes: (BinaryTreeNodeKey | N | null)[], data?: N['val'][]): (N | null | undefined)[];
fill(idsOrNodes: (BinaryTreeNodeId | N | null)[], data?: N[] | Array<N['val']>): boolean;
fill(idsOrNodes: (BinaryTreeNodeKey | N | null)[], data?: N[] | Array<N['val']>): boolean;
remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
remove(key: BinaryTreeNodeKey, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
getDepth(node: N): number;
@ -76,11 +76,11 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
isPerfectlyBalanced(beginRoot?: N | null): boolean;
getNodes(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
getNodes(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
has(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): boolean;
has(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): boolean;
get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null;
get(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): N | null;
getPathToRoot(node: N): N[];
@ -108,9 +108,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
subTreeAdd(subTreeRoot: N, delta: number, propertyName?: BinaryTreeNodePropertyName): boolean;
BFS(): BinaryTreeNodeId[];
BFS(): BinaryTreeNodeKey[];
BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[];
BFS(nodeOrPropertyName: 'key'): BinaryTreeNodeKey[];
BFS(nodeOrPropertyName: 'val'): N['val'][];
@ -120,9 +120,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
BFS(nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
DFS(): BinaryTreeNodeId[];
DFS(): BinaryTreeNodeKey[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
@ -132,9 +132,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
DFS(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
DFSIterative(): BinaryTreeNodeId[];
DFSIterative(): BinaryTreeNodeKey[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
@ -147,9 +147,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
nodeOrPropertyName?: NodeOrPropertyName
): AbstractBinaryTreeNodeProperties<N>;
levelIterative(node: N | null): BinaryTreeNodeId[];
levelIterative(node: N | null): BinaryTreeNodeKey[];
levelIterative(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
levelIterative(node: N | null, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
levelIterative(node: N | null, nodeOrPropertyName?: 'val'): N['val'][];
@ -159,9 +159,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
levelIterative(node: N | null, nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
listLevels(node: N | null): BinaryTreeNodeId[][];
listLevels(node: N | null): BinaryTreeNodeKey[][];
listLevels(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][];
listLevels(node: N | null, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[][];
listLevels(node: N | null, nodeOrPropertyName?: 'val'): N['val'][][];
@ -173,9 +173,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
getPredecessor(node: N): N;
morris(): BinaryTreeNodeId[];
morris(): BinaryTreeNodeKey[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'key'): BinaryTreeNodeKey[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];

View file

@ -1,31 +1,31 @@
import {VertexId} from '../types';
import {VertexKey} from '../types';
export interface IAbstractGraph<V, E> {
hasVertex(vertexOrId: V | VertexId): boolean;
hasVertex(vertexOrKey: V | VertexKey): boolean;
addVertex(id: VertexId, val?: V): boolean;
addVertex(key: VertexKey, val?: V): boolean;
removeVertex(vertexOrId: V | VertexId): boolean;
removeVertex(vertexOrKey: V | VertexKey): boolean;
removeAllVertices(vertices: V[] | VertexId[]): boolean;
removeAllVertices(vertices: V[] | VertexKey[]): boolean;
degreeOf(vertexOrId: V | VertexId): number;
degreeOf(vertexOrKey: V | VertexKey): number;
edgesOf(vertexOrId: V | VertexId): E[];
edgesOf(vertexOrKey: V | VertexKey): E[];
hasEdge(src: V | VertexId, dest: V | VertexId): boolean;
hasEdge(src: V | VertexKey, dest: V | VertexKey): boolean;
getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
getEdge(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null;
edgeSet(): E[];
addEdge(src: V | VertexId, dest: V | VertexId, weight: number, val: E): boolean;
addEdge(src: V | VertexKey, dest: V | VertexKey, weight: number, val: E): boolean;
removeEdge(edge: E): E | null;
setEdgeWeight(srcOrId: V | VertexId, destOrId: V | VertexId, weight: number): boolean;
setEdgeWeight(srcOrKey: V | VertexKey, destOrKey: V | VertexKey, weight: number): boolean;
getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null;
getMinPathBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): V[] | null;
getNeighbors(vertexOrId: V | VertexId): V[];
getNeighbors(vertexOrKey: V | VertexKey): V[];
}

View file

@ -1,13 +1,13 @@
import {AVLTreeNode} from '../data-structures';
import {IBST, IBSTNode} from './bst';
import {BinaryTreeDeletedResult, BinaryTreeNodeId} from '../types';
import {BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../types';
export type IAVLTreeNode<T, NEIGHBOR extends IAVLTreeNode<T, NEIGHBOR>> = IBSTNode<T, NEIGHBOR>;
export interface IAVLTree<N extends AVLTreeNode<N['val'], N>> extends IBST<N> {
add(id: BinaryTreeNodeId, val?: N['val'] | null): N | null | undefined;
add(key: BinaryTreeNodeKey, val?: N['val'] | null): N | null | undefined;
remove(id: BinaryTreeNodeId): BinaryTreeDeletedResult<N>[];
remove(key: BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[];
// _balanceFactor(node: N): number
//

View file

@ -1,25 +1,25 @@
import {BSTNode} from '../data-structures';
import {IBinaryTree, IBinaryTreeNode} from './binary-tree';
import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types';
import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodePropertyName} from '../types';
export type IBSTNode<T, NEIGHBOR extends IBSTNode<T, NEIGHBOR>> = IBinaryTreeNode<T, NEIGHBOR>;
export interface IBST<N extends BSTNode<N['val'], N>> extends IBinaryTree<N> {
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N;
createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N;
add(id: BinaryTreeNodeId, val?: N['val'] | null, count?: number): N | null | undefined;
add(key: BinaryTreeNodeKey, val?: N['val'] | null, count?: number): N | null | undefined;
get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null;
get(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName): N | null;
lastKey(): BinaryTreeNodeId;
lastKey(): BinaryTreeNodeKey;
remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
remove(key: BinaryTreeNodeKey, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
getNodes(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
getNodes(nodeProperty: BinaryTreeNodeKey | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
// --- start additional functions
lesserSum(id: BinaryTreeNodeId, propertyName?: BinaryTreeNodePropertyName): number;
lesserSum(key: BinaryTreeNodeKey, propertyName?: BinaryTreeNodePropertyName): number;
allGreaterNodesAdd(node: N, delta: number, propertyName?: BinaryTreeNodePropertyName): boolean;

View file

@ -1,4 +1,4 @@
import {VertexId} from '../types';
import {VertexKey} from '../types';
import {IAbstractGraph} from './abstract-graph';
export interface IDirectedGraph<V, E> extends IAbstractGraph<V, E> {
@ -6,15 +6,15 @@ export interface IDirectedGraph<V, E> extends IAbstractGraph<V, E> {
outgoingEdgesOf(vertex: V): E[];
inDegreeOf(vertexOrId: V | VertexId): number;
inDegreeOf(vertexOrKey: V | VertexKey): number;
outDegreeOf(vertexOrId: V | VertexId): number;
outDegreeOf(vertexOrKey: V | VertexKey): number;
getEdgeSrc(e: E): V | null;
getEdgeDest(e: E): V | null;
removeEdgeSrcToDest(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
removeEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null;
removeEdgesBetween(v1: V | VertexId, v2: V | VertexId): E[];
removeEdgesBetween(v1: V | VertexKey, v2: V | VertexKey): E[];
}

View file

@ -1,9 +1,9 @@
import {RBTreeNode} from '../data-structures';
import {IBST, IBSTNode} from './bst';
import {BinaryTreeNodeId} from '../types';
import {BinaryTreeNodeKey} from '../types';
export type IRBTreeNode<T, NEIGHBOR extends IRBTreeNode<T, NEIGHBOR>> = IBSTNode<T, NEIGHBOR>;
export interface IRBTree<N extends RBTreeNode<N['val'], N>> extends IBST<N> {
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N;
createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N;
}

View file

@ -1,6 +1,6 @@
import {VertexId} from '../types';
import {VertexKey} from '../types';
import {IAbstractGraph} from './abstract-graph';
export interface IUNDirectedGraph<V, E> extends IAbstractGraph<V, E> {
removeEdgeBetween(v1: V | VertexId, v2: V | VertexId): E | null;
removeEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null;
}

View file

@ -23,13 +23,13 @@ export enum FamilyPosition {
MAL_NODE = 'MAL_NODE'
}
export type BinaryTreeNodePropertyName = 'id' | 'val';
export type BinaryTreeNodePropertyName = 'key' | 'val';
export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
export type DFSOrderPattern = 'in' | 'pre' | 'post';
export type BinaryTreeNodeId = number;
export type BinaryTreeNodeKey = number;
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null };
@ -37,7 +37,7 @@ export type AbstractBinaryTreeNodeProperty<N extends AbstractBinaryTreeNode<N['v
| N['val']
| N
| number
| BinaryTreeNodeId;
| BinaryTreeNodeKey;
export type AbstractBinaryTreeNodeProperties<N extends AbstractBinaryTreeNode<N['val'], N>> =

View file

@ -1,5 +1,5 @@
export type VertexId = string | number;
export type EdgeId = string;
export type VertexKey = string | number;
export type EdgeKey = string;
export type DijkstraResult<V> = {
distMap: Map<V, number>;
distPaths?: Map<V, V[]>;

View file

@ -1,8 +1,8 @@
import {BSTNode} from '../../data-structures/binary-tree';
import type {BinaryTreeOptions} from './binary-tree';
import {BinaryTreeNodeId} from './abstract-binary-tree';
import {BinaryTreeNodeKey} from './abstract-binary-tree';
export type BSTComparator = (a: BinaryTreeNodeId, b: BinaryTreeNodeId) => number;
export type BSTComparator = (a: BinaryTreeNodeKey, b: BinaryTreeNodeKey) => number;
// prettier-ignore
export type BSTNodeNested<T> = BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

View file

@ -3,4 +3,4 @@ import {AVLTreeOptions} from './avl-tree';
export type TreeMultisetNodeNested<T> = TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeById'> & {}
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeByKey'> & {}

View file

@ -1,26 +1,26 @@
export type KeyValueObject = {[key: string]: any};
export type KeyValueObjectWithId = {[key: string]: any; id: string | number | symbol};
export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol};
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;
export type ObjectWithoutId = Omit<KeyValueObject, 'id'>;
export type ObjectWithoutKey = Omit<KeyValueObject, 'key'>;
export type ObjectWithNonNumberId = {
export type ObjectWithNonNumberKey = {
[key: string]: any;
id: string | boolean | symbol | null | object | undefined;
key: string | boolean | symbol | null | object | undefined;
};
export type ObjectWithNumberId = {
export type ObjectWithNumberKey = {
[key: string]: any;
id: number;
key: number;
};
export type RestrictValById =
export type RestrictValByKey =
| NonNumberNonObjectButDefined
| ObjectWithoutId
| ObjectWithNonNumberId
| ObjectWithNumberId;
| ObjectWithoutKey
| ObjectWithNonNumberKey
| ObjectWithNumberKey;
export type DummyAny =
| string

View file

@ -12,15 +12,15 @@ describe('AVL Tree Test', () => {
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.get(10, 'id');
expect(getNodeById?.id).toBe(10);
const getNodeById = tree.get(10, 'key');
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot?.id).toBe(1);
expect(getMinNodeByRoot?.key).toBe(1);
const node15 = tree.get(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
expect(getMinNodeBySpecificNode?.id).toBe(12);
expect(getMinNodeBySpecificNode?.key).toBe(12);
const subTreeSum = node15 && tree.subTreeSum(node15);
expect(subTreeSum).toBe(70);
@ -32,65 +32,65 @@ describe('AVL Tree Test', () => {
expect(node15?.val).toBe(15);
const dfs = tree.DFS('in', 'node');
expect(dfs[0].id).toBe(1);
expect(dfs[dfs.length - 1].id).toBe(16);
expect(dfs[0].key).toBe(1);
expect(dfs[dfs.length - 1].key).toBe(16);
tree.perfectlyBalance();
const bfs = tree.BFS('node');
expect(tree.isPerfectlyBalanced()).toBe(true);
expect(bfs[0].id).toBe(8);
expect(bfs[bfs.length - 1].id).toBe(16);
expect(bfs[0].key).toBe(8);
expect(bfs[bfs.length - 1].key).toBe(16);
expect(tree.remove(11)[0].deleted?.id).toBe(11);
expect(tree.remove(11)[0].deleted?.key).toBe(11);
expect(tree.isAVLBalanced()).toBe(true);
expect(node15 && tree.getHeight(node15)).toBe(2);
expect(tree.remove(1)[0].deleted?.id).toBe(1);
expect(tree.remove(1)[0].deleted?.key).toBe(1);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(tree.remove(4)[0].deleted?.id).toBe(4);
expect(tree.remove(4)[0].deleted?.key).toBe(4);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(tree.remove(10)[0].deleted?.id).toBe(10);
expect(tree.remove(10)[0].deleted?.key).toBe(10);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(15)[0].deleted?.id).toBe(15);
expect(tree.remove(15)[0].deleted?.key).toBe(15);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(5)[0].deleted?.id).toBe(5);
expect(tree.remove(5)[0].deleted?.key).toBe(5);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(13)[0].deleted?.id).toBe(13);
expect(tree.remove(13)[0].deleted?.key).toBe(13);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(3)[0].deleted?.id).toBe(3);
expect(tree.remove(3)[0].deleted?.key).toBe(3);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(8)[0].deleted?.id).toBe(8);
expect(tree.remove(8)[0].deleted?.key).toBe(8);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.remove(6)[0].deleted?.id).toBe(6);
expect(tree.remove(6)[0].deleted?.key).toBe(6);
expect(tree.remove(6).length).toBe(0);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.remove(7)[0].deleted?.id).toBe(7);
expect(tree.remove(7)[0].deleted?.key).toBe(7);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.remove(9)[0].deleted?.id).toBe(9);
expect(tree.remove(9)[0].deleted?.key).toBe(9);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.remove(14)[0].deleted?.id).toBe(14);
expect(tree.remove(14)[0].deleted?.key).toBe(14);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(1);
@ -101,8 +101,8 @@ describe('AVL Tree Test', () => {
expect(lastBFSIds[2]).toBe(16);
const lastBFSNodes = tree.BFS('node');
expect(lastBFSNodes[0].id).toBe(12);
expect(lastBFSNodes[1].id).toBe(2);
expect(lastBFSNodes[2].id).toBe(16);
expect(lastBFSNodes[0].key).toBe(12);
expect(lastBFSNodes[1].key).toBe(2);
expect(lastBFSNodes[2].key).toBe(16);
});
});

View file

@ -8,10 +8,10 @@ describe('BinaryTreeNode', () => {
it('should set and get the ID correctly', () => {
const node = new BinaryTreeNode<number>(1);
expect(node.id).toBe(1);
expect(node.key).toBe(1);
node.id = 2;
expect(node.id).toBe(2);
node.key = 2;
expect(node.key).toBe(2);
});
it('should set and get the value correctly', () => {

View file

@ -10,7 +10,7 @@ describe('BST operations test', () => {
bst.addMany(idsAndValues, idsAndValues);
expect(bst.root).toBeInstanceOf(BSTNode);
if (bst.root) expect(bst.root.id).toBe(11);
if (bst.root) expect(bst.root.key).toBe(11);
expect(bst.size).toBe(16);
@ -21,17 +21,17 @@ describe('BST operations test', () => {
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.get(10);
expect(nodeId10?.id).toBe(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.get(9, 'val');
expect(nodeVal9?.id).toBe(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = bst.getLeftMost();
expect(leftMost?.id).toBe(1);
expect(leftMost?.key).toBe(1);
const node15 = bst.get(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
expect(minNodeBySpecificNode?.id).toBe(12);
expect(minNodeBySpecificNode?.key).toBe(12);
const subTreeSum = node15 && bst.subTreeSum(15);
expect(subTreeSum).toBe(70);
@ -45,22 +45,22 @@ describe('BST operations test', () => {
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = bst.DFS('in', 'node');
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
bst.perfectlyBalance();
expect(bst.isPerfectlyBalanced()).toBe(true);
const bfsNodesAfterBalanced = bst.BFS('node');
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = bst.remove(11);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(bst.isAVLBalanced()).toBe(true);
@ -70,7 +70,7 @@ describe('BST operations test', () => {
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(bst.isAVLBalanced()).toBe(true);
@ -80,7 +80,7 @@ describe('BST operations test', () => {
expect(removed4).toBeInstanceOf(Array);
expect(removed4[0]).toBeDefined();
expect(removed4[0].deleted).toBeDefined();
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(4);
@ -88,7 +88,7 @@ describe('BST operations test', () => {
expect(removed10).toBeInstanceOf(Array);
expect(removed10[0]).toBeDefined();
expect(removed10[0].deleted).toBeDefined();
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(4);
@ -96,7 +96,7 @@ describe('BST operations test', () => {
expect(removed15).toBeInstanceOf(Array);
expect(removed15[0]).toBeDefined();
expect(removed15[0].deleted).toBeDefined();
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
@ -105,7 +105,7 @@ describe('BST operations test', () => {
expect(removed5).toBeInstanceOf(Array);
expect(removed5[0]).toBeDefined();
expect(removed5[0].deleted).toBeDefined();
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
@ -114,7 +114,7 @@ describe('BST operations test', () => {
expect(removed13).toBeInstanceOf(Array);
expect(removed13[0]).toBeDefined();
expect(removed13[0].deleted).toBeDefined();
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
@ -122,7 +122,7 @@ describe('BST operations test', () => {
expect(removed3).toBeInstanceOf(Array);
expect(removed3[0]).toBeDefined();
expect(removed3[0].deleted).toBeDefined();
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
@ -130,7 +130,7 @@ describe('BST operations test', () => {
expect(removed8).toBeInstanceOf(Array);
expect(removed8[0]).toBeDefined();
expect(removed8[0].deleted).toBeDefined();
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
@ -138,7 +138,7 @@ describe('BST operations test', () => {
expect(removed6).toBeInstanceOf(Array);
expect(removed6[0]).toBeDefined();
expect(removed6[0].deleted).toBeDefined();
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(bst.remove(6).length).toBe(0);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
@ -147,7 +147,7 @@ describe('BST operations test', () => {
expect(removed7).toBeInstanceOf(Array);
expect(removed7[0]).toBeDefined();
expect(removed7[0].deleted).toBeDefined();
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
@ -155,7 +155,7 @@ describe('BST operations test', () => {
expect(removed9).toBeInstanceOf(Array);
expect(removed9[0]).toBeDefined();
expect(removed9[0].deleted).toBeDefined();
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
@ -163,7 +163,7 @@ describe('BST operations test', () => {
expect(removed14).toBeInstanceOf(Array);
expect(removed14[0]).toBeDefined();
expect(removed14[0].deleted).toBeDefined();
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(2);
@ -175,41 +175,41 @@ describe('BST operations test', () => {
expect(bfsIDs[2]).toBe(16);
const bfsNodes = bst.BFS('node');
expect(bfsNodes[0].id).toBe(2);
expect(bfsNodes[1].id).toBe(12);
expect(bfsNodes[2].id).toBe(16);
expect(bfsNodes[0].key).toBe(2);
expect(bfsNodes[1].key).toBe(12);
expect(bfsNodes[2].key).toBe(16);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<BSTNode<{id: number; keyA: number}>>();
const objBST = new BST<BSTNode<{key: number; keyA: number}>>();
expect(objBST).toBeInstanceOf(BST);
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});
const values = [
{id: 15, keyA: 15},
{id: 1, keyA: 1},
{id: 8, keyA: 8},
{id: 13, keyA: 13},
{id: 16, keyA: 16},
{id: 2, keyA: 2},
{id: 6, keyA: 6},
{id: 9, keyA: 9},
{id: 12, keyA: 12},
{id: 14, keyA: 14},
{id: 4, keyA: 4},
{id: 7, keyA: 7},
{id: 10, keyA: 10},
{id: 5, keyA: 5}
{key: 15, keyA: 15},
{key: 1, keyA: 1},
{key: 8, keyA: 8},
{key: 13, keyA: 13},
{key: 16, keyA: 16},
{key: 2, keyA: 2},
{key: 6, keyA: 6},
{key: 9, keyA: 9},
{key: 12, keyA: 12},
{key: 14, keyA: 14},
{key: 4, keyA: 4},
{key: 7, keyA: 7},
{key: 10, keyA: 10},
{key: 5, keyA: 5}
];
objBST.addMany(
values.map(item => item.id),
values.map(item => item.key),
values
);
expect(objBST.root).toBeInstanceOf(BSTNode);
if (objBST.root) expect(objBST.root.id).toBe(11);
if (objBST.root) expect(objBST.root.key).toBe(11);
expect(objBST.has(6)).toBe(true);
@ -217,19 +217,19 @@ describe('BST operations test', () => {
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.get(10, 'id');
expect(nodeId10?.id).toBe(10);
const nodeId10 = objBST.get(10, 'key');
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.get(9, 'id');
expect(nodeVal9?.id).toBe(9);
const nodeVal9 = objBST.get(9, 'key');
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost?.id).toBe(1);
expect(leftMost?.key).toBe(1);
const node15 = objBST.get(15);
expect(node15?.val).toEqual({id: 15, keyA: 15});
expect(node15?.val).toEqual({key: 15, keyA: 15});
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
expect(minNodeBySpecificNode?.id).toBe(12);
expect(minNodeBySpecificNode?.key).toBe(12);
const subTreeSum = node15 && objBST.subTreeSum(node15);
expect(subTreeSum).toBe(70);
@ -243,22 +243,22 @@ describe('BST operations test', () => {
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = objBST.DFS('in', 'node');
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
objBST.perfectlyBalance();
expect(objBST.isPerfectlyBalanced()).toBe(true);
const bfsNodesAfterBalanced = objBST.BFS('node');
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = objBST.remove(11);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(objBST.isAVLBalanced()).toBe(true);
@ -268,7 +268,7 @@ describe('BST operations test', () => {
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(objBST.isAVLBalanced()).toBe(true);
@ -278,7 +278,7 @@ describe('BST operations test', () => {
expect(removed4).toBeInstanceOf(Array);
expect(removed4[0]).toBeDefined();
expect(removed4[0].deleted).toBeDefined();
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(4);
@ -286,7 +286,7 @@ describe('BST operations test', () => {
expect(removed10).toBeInstanceOf(Array);
expect(removed10[0]).toBeDefined();
expect(removed10[0].deleted).toBeDefined();
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(4);
@ -294,7 +294,7 @@ describe('BST operations test', () => {
expect(removed15).toBeInstanceOf(Array);
expect(removed15[0]).toBeDefined();
expect(removed15[0].deleted).toBeDefined();
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
@ -303,7 +303,7 @@ describe('BST operations test', () => {
expect(removed5).toBeInstanceOf(Array);
expect(removed5[0]).toBeDefined();
expect(removed5[0].deleted).toBeDefined();
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
@ -312,7 +312,7 @@ describe('BST operations test', () => {
expect(removed13).toBeInstanceOf(Array);
expect(removed13[0]).toBeDefined();
expect(removed13[0].deleted).toBeDefined();
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
@ -320,7 +320,7 @@ describe('BST operations test', () => {
expect(removed3).toBeInstanceOf(Array);
expect(removed3[0]).toBeDefined();
expect(removed3[0].deleted).toBeDefined();
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
@ -328,7 +328,7 @@ describe('BST operations test', () => {
expect(removed8).toBeInstanceOf(Array);
expect(removed8[0]).toBeDefined();
expect(removed8[0].deleted).toBeDefined();
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
@ -336,7 +336,7 @@ describe('BST operations test', () => {
expect(removed6).toBeInstanceOf(Array);
expect(removed6[0]).toBeDefined();
expect(removed6[0].deleted).toBeDefined();
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(objBST.remove(6).length).toBe(0);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
@ -345,7 +345,7 @@ describe('BST operations test', () => {
expect(removed7).toBeInstanceOf(Array);
expect(removed7[0]).toBeDefined();
expect(removed7[0].deleted).toBeDefined();
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
@ -353,7 +353,7 @@ describe('BST operations test', () => {
expect(removed9).toBeInstanceOf(Array);
expect(removed9[0]).toBeDefined();
expect(removed9[0].deleted).toBeDefined();
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
@ -361,7 +361,7 @@ describe('BST operations test', () => {
expect(removed14).toBeInstanceOf(Array);
expect(removed14[0]).toBeDefined();
expect(removed14[0].deleted).toBeDefined();
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(2);
@ -373,8 +373,8 @@ describe('BST operations test', () => {
expect(bfsIDs[2]).toBe(16);
const bfsNodes = objBST.BFS('node');
expect(bfsNodes[0].id).toBe(2);
expect(bfsNodes[1].id).toBe(12);
expect(bfsNodes[2].id).toBe(16);
expect(bfsNodes[0].key).toBe(2);
expect(bfsNodes[1].key).toBe(12);
expect(bfsNodes[2].key).toBe(16);
});
});

View file

@ -17,8 +17,8 @@ describe('Overall BinaryTree Test', () => {
expect(bst.getHeight()).toBe(5); // true
expect(bst.getDepth(6)).toBe(3); // true
const leftMost = bst.getLeftMost();
leftMost?.id === 1; // true
expect(leftMost?.id).toBe(1);
leftMost?.key === 1; // true
expect(leftMost?.key).toBe(1);
bst.remove(6);
bst.get(6); // null
expect(bst.get(6)).toBeNull();
@ -28,27 +28,27 @@ describe('Overall BinaryTree Test', () => {
bfsIDs[0] === 11; // true
expect(bfsIDs[0]).toBe(11);
const objBST = new BST<BSTNode<{id: number; keyA: number}>>();
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
const objBST = new BST<BSTNode<{key: number; keyA: number}>>();
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});
objBST.addMany(
[15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5],
[
{id: 15, keyA: 15},
{id: 1, keyA: 1},
{id: 8, keyA: 8},
{id: 13, keyA: 13},
{id: 16, keyA: 16},
{id: 2, keyA: 2},
{id: 6, keyA: 6},
{id: 9, keyA: 9},
{id: 12, keyA: 12},
{id: 14, keyA: 14},
{id: 4, keyA: 4},
{id: 7, keyA: 7},
{id: 10, keyA: 10},
{id: 5, keyA: 5}
{key: 15, keyA: 15},
{key: 1, keyA: 1},
{key: 8, keyA: 8},
{key: 13, keyA: 13},
{key: 16, keyA: 16},
{key: 2, keyA: 2},
{key: 6, keyA: 6},
{key: 9, keyA: 9},
{key: 12, keyA: 12},
{key: 14, keyA: 14},
{key: 4, keyA: 4},
{key: 7, keyA: 7},
{key: 10, keyA: 10},
{key: 5, keyA: 5}
]
);

View file

@ -11,21 +11,21 @@ describe('TreeMultiset operations test', () => {
treeMultiset.addMany(idAndValues, idAndValues);
expect(treeMultiset.root instanceof TreeMultisetNode);
if (treeMultiset.root) expect(treeMultiset.root.id == 11);
if (treeMultiset.root) expect(treeMultiset.root.key == 11);
expect(treeMultiset.size).toBe(16);
expect(treeMultiset.count).toBe(18);
expect(treeMultiset.BFS('id'));
expect(treeMultiset.BFS('key'));
expect(treeMultiset.has(6));
expect(treeMultiset.getHeight(6)).toBe(3);
expect(treeMultiset.getDepth(6)).toBe(1);
const nodeId10 = treeMultiset.get(10);
expect(nodeId10?.id).toBe(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultiset.get(9, 'val');
expect(nodeVal9?.id).toBe(9);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultiset.getNodesByCount(1);
expect(nodesByCount1.length).toBe(14);
@ -33,11 +33,11 @@ describe('TreeMultiset operations test', () => {
const nodesByCount2 = treeMultiset.getNodesByCount(2);
expect(nodesByCount2.length).toBe(2);
const leftMost = treeMultiset.getLeftMost();
expect(leftMost?.id).toBe(1);
expect(leftMost?.key).toBe(1);
const node15 = treeMultiset.get(15);
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
expect(minNodeBySpecificNode?.id).toBe(12);
expect(minNodeBySpecificNode?.key).toBe(12);
const subTreeSum = node15 && treeMultiset.subTreeSum(15);
expect(subTreeSum).toBe(70);
@ -57,8 +57,8 @@ describe('TreeMultiset operations test', () => {
}
const dfsInorderNodes = treeMultiset.DFS('in', 'node');
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
expect(treeMultiset.isPerfectlyBalanced()).toBe(false);
treeMultiset.perfectlyBalance();
@ -67,15 +67,15 @@ describe('TreeMultiset operations test', () => {
expect(treeMultiset.isAVLBalanced()).toBe(true);
const bfsNodesAfterBalanced = treeMultiset.BFS('node');
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = treeMultiset.remove(11, true);
expect(removed11 instanceof Array);
expect(removed11[0]);
expect(removed11[0].deleted);
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(treeMultiset.isAVLBalanced()).toBe(true);
@ -85,7 +85,7 @@ describe('TreeMultiset operations test', () => {
expect(removed1 instanceof Array);
expect(removed1[0]);
expect(removed1[0].deleted);
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(treeMultiset.isAVLBalanced()).toBe(true);
@ -95,7 +95,7 @@ describe('TreeMultiset operations test', () => {
expect(removed4 instanceof Array);
expect(removed4[0]);
expect(removed4[0].deleted);
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(4);
@ -104,7 +104,7 @@ describe('TreeMultiset operations test', () => {
expect(removed10 instanceof Array);
expect(removed10[0]);
expect(removed10[0].deleted);
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -113,7 +113,7 @@ describe('TreeMultiset operations test', () => {
expect(removed15 instanceof Array);
expect(removed15[0]);
expect(removed15[0].deleted);
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -122,7 +122,7 @@ describe('TreeMultiset operations test', () => {
expect(removed5 instanceof Array);
expect(removed5[0]);
expect(removed5[0].deleted);
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -131,7 +131,7 @@ describe('TreeMultiset operations test', () => {
expect(removed13 instanceof Array);
expect(removed13[0]);
expect(removed13[0].deleted);
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -139,7 +139,7 @@ describe('TreeMultiset operations test', () => {
expect(removed3 instanceof Array);
expect(removed3[0]);
expect(removed3[0].deleted);
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -147,7 +147,7 @@ describe('TreeMultiset operations test', () => {
expect(removed8 instanceof Array);
expect(removed8[0]);
expect(removed8[0].deleted);
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
@ -155,7 +155,7 @@ describe('TreeMultiset operations test', () => {
expect(removed6 instanceof Array);
expect(removed6[0]);
expect(removed6[0].deleted);
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(treeMultiset.remove(6, true).length).toBe(0);
expect(treeMultiset.isAVLBalanced()).toBe(true);
@ -165,7 +165,7 @@ describe('TreeMultiset operations test', () => {
expect(removed7 instanceof Array);
expect(removed7[0]);
expect(removed7[0].deleted);
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
@ -173,7 +173,7 @@ describe('TreeMultiset operations test', () => {
expect(removed9 instanceof Array);
expect(removed9[0]);
expect(removed9[0].deleted);
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
@ -181,7 +181,7 @@ describe('TreeMultiset operations test', () => {
expect(removed14 instanceof Array);
expect(removed14[0]);
expect(removed14[0].deleted);
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(1);
@ -195,43 +195,43 @@ describe('TreeMultiset operations test', () => {
const bfsNodes = treeMultiset.BFS('node');
expect(bfsNodes[0].id).toBe(12);
expect(bfsNodes[1].id).toBe(2);
expect(bfsNodes[2].id).toBe(16);
expect(bfsNodes[0].key).toBe(12);
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultiset.count).toBe(9);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultiset = new TreeMultiset<TreeMultisetNode<{id: number; keyA: number}>>();
const objTreeMultiset = new TreeMultiset<TreeMultisetNode<{key: number; keyA: number}>>();
expect(objTreeMultiset).toBeInstanceOf(TreeMultiset);
objTreeMultiset.add(11, {id: 11, keyA: 11});
objTreeMultiset.add(3, {id: 3, keyA: 3});
objTreeMultiset.add(11, {key: 11, keyA: 11});
objTreeMultiset.add(3, {key: 3, keyA: 3});
const values = [
{id: 15, keyA: 15},
{id: 1, keyA: 1},
{id: 8, keyA: 8},
{id: 13, keyA: 13},
{id: 16, keyA: 16},
{id: 2, keyA: 2},
{id: 6, keyA: 6},
{id: 9, keyA: 9},
{id: 12, keyA: 12},
{id: 14, keyA: 14},
{id: 4, keyA: 4},
{id: 7, keyA: 7},
{id: 10, keyA: 10},
{id: 5, keyA: 5}
{key: 15, keyA: 15},
{key: 1, keyA: 1},
{key: 8, keyA: 8},
{key: 13, keyA: 13},
{key: 16, keyA: 16},
{key: 2, keyA: 2},
{key: 6, keyA: 6},
{key: 9, keyA: 9},
{key: 12, keyA: 12},
{key: 14, keyA: 14},
{key: 4, keyA: 4},
{key: 7, keyA: 7},
{key: 10, keyA: 10},
{key: 5, keyA: 5}
];
objTreeMultiset.addMany(
values.map(item => item.id),
values.map(item => item.key),
values
);
expect(objTreeMultiset.root).toBeInstanceOf(TreeMultisetNode);
if (objTreeMultiset.root) expect(objTreeMultiset.root.id).toBe(11);
if (objTreeMultiset.root) expect(objTreeMultiset.root.key).toBe(11);
expect(objTreeMultiset.count).toBe(16);
@ -241,22 +241,22 @@ describe('TreeMultiset operations test', () => {
// expect(node6 && objTreeMultiset.getHeight(node6)).toBe(2);
// expect(node6 && objTreeMultiset.getDepth(node6)).toBe(3);
//
// const nodeId10 = objTreeMultiset.get(10, 'id');
// expect(nodeId10?.id).toBe(10);
// const nodeId10 = objTreeMultiset.get(10, 'key');
// expect(nodeId10?.key).toBe(10);
//
// const nodeVal9 = objTreeMultiset.get(9, 'id');
// expect(nodeVal9?.id).toBe(9);
// const nodeVal9 = objTreeMultiset.get(9, 'key');
// expect(nodeVal9?.key).toBe(9);
//
// const nodesByCount1 = objTreeMultiset.getNodesByCount(1);
// expect(nodesByCount1.length).toBe(16);
//
// const leftMost = objTreeMultiset.getLeftMost();
// expect(leftMost?.id).toBe(1);
// expect(leftMost?.key).toBe(1);
//
// const node15 = objTreeMultiset.get(15);
// expect(node15?.val).toEqual({id: 15, keyA: 15});
// expect(node15?.val).toEqual({key: 15, keyA: 15});
// const minNodeBySpecificNode = node15 && objTreeMultiset.getLeftMost(node15);
// expect(minNodeBySpecificNode?.id).toBe(12);
// expect(minNodeBySpecificNode?.key).toBe(12);
//
// const subTreeSum = node15 && objTreeMultiset.subTreeSum(node15);
// expect(subTreeSum).toBe(70);
@ -278,22 +278,22 @@ describe('TreeMultiset operations test', () => {
// }
//
// const dfsInorderNodes = objTreeMultiset.DFS('in', 'node');
// expect(dfsInorderNodes[0].id).toBe(1);
// expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
// expect(dfsInorderNodes[0].key).toBe(1);
// expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
//
// objTreeMultiset.perfectlyBalance();
// expect(objTreeMultiset.isPerfectlyBalanced()).toBe(true);
//
// const bfsNodesAfterBalanced = objTreeMultiset.BFS('node');
// expect(bfsNodesAfterBalanced[0].id).toBe(8);
// expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
// expect(bfsNodesAfterBalanced[0].key).toBe(8);
// expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
//
// const removed11 = objTreeMultiset.remove(11, true);
// expect(removed11).toBeInstanceOf(Array);
// expect(removed11[0]).toBeDefined();
// expect(removed11[0].deleted).toBeDefined();
//
// if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
// if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
//
@ -303,7 +303,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed1).toBeInstanceOf(Array);
// expect(removed1[0]).toBeDefined();
// expect(removed1[0].deleted).toBeDefined();
// if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
// if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
//
@ -313,7 +313,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed4).toBeInstanceOf(Array);
// expect(removed4[0]).toBeDefined();
// expect(removed4[0].deleted).toBeDefined();
// if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
// if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(4);
//
@ -321,7 +321,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed10).toBeInstanceOf(Array);
// expect(removed10[0]).toBeDefined();
// expect(removed10[0].deleted).toBeDefined();
// if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
// if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(4);
//
@ -329,7 +329,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed15).toBeInstanceOf(Array);
// expect(removed15[0]).toBeDefined();
// expect(removed15[0].deleted).toBeDefined();
// if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
// if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
@ -338,7 +338,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed5).toBeInstanceOf(Array);
// expect(removed5[0]).toBeDefined();
// expect(removed5[0].deleted).toBeDefined();
// if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
// if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
@ -347,7 +347,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed13).toBeInstanceOf(Array);
// expect(removed13[0]).toBeDefined();
// expect(removed13[0].deleted).toBeDefined();
// if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
// if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
@ -355,7 +355,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed3).toBeInstanceOf(Array);
// expect(removed3[0]).toBeDefined();
// expect(removed3[0].deleted).toBeDefined();
// if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
// if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
@ -363,7 +363,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed8).toBeInstanceOf(Array);
// expect(removed8[0]).toBeDefined();
// expect(removed8[0].deleted).toBeDefined();
// if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
// if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
@ -371,7 +371,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed6).toBeInstanceOf(Array);
// expect(removed6[0]).toBeDefined();
// expect(removed6[0].deleted).toBeDefined();
// if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
// if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
// expect(objTreeMultiset.remove(6, true).length).toBe(0);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
@ -380,7 +380,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed7).toBeInstanceOf(Array);
// expect(removed7[0]).toBeDefined();
// expect(removed7[0].deleted).toBeDefined();
// if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
// if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
@ -388,7 +388,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed9).toBeInstanceOf(Array);
// expect(removed9[0]).toBeDefined();
// expect(removed9[0].deleted).toBeDefined();
// if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
// if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
@ -396,7 +396,7 @@ describe('TreeMultiset operations test', () => {
// expect(removed14).toBeInstanceOf(Array);
// expect(removed14[0]).toBeDefined();
// expect(removed14[0].deleted).toBeDefined();
// if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
// if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(2);
//
@ -409,9 +409,9 @@ describe('TreeMultiset operations test', () => {
// expect(bfsIDs[2]).toBe(16);
//
// const bfsNodes = objTreeMultiset.BFS('node');
// expect(bfsNodes[0].id).toBe(2);
// expect(bfsNodes[1].id).toBe(12);
// expect(bfsNodes[2].id).toBe(16);
// expect(bfsNodes[0].key).toBe(2);
// expect(bfsNodes[1].key).toBe(12);
// expect(bfsNodes[2].key).toBe(16);
//
// expect(objTreeMultiset.count).toBe(5);
});

View file

@ -63,8 +63,8 @@ describe('DirectedGraph Operation Test', () => {
});
class MyVertex<V extends string> extends DirectedVertex<V> {
constructor(id: VertexId, val?: V) {
super(id, val);
constructor(key: VertexId, val?: V) {
super(key, val);
this._data = val;
}
@ -97,8 +97,8 @@ class MyEdge<E extends string> extends DirectedEdge<E> {
}
class MyDirectedGraph<V extends MyVertex<string>, E extends MyEdge<string>> extends DirectedGraph<V, E> {
createVertex(id: VertexId, val: V['val']): V {
return new MyVertex(id, val) as V;
createVertex(key: VertexId, val: V['val']): V {
return new MyVertex(key, val) as V;
}
createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
@ -183,7 +183,7 @@ describe('Inherit from DirectedGraph and perform operations', () => {
expect(sorted.length).toBe(9);
if (sorted[0] instanceof MyVertex) expect(sorted[0].data).toBe('data9');
sorted[3] instanceof MyVertex && expect(sorted[3].data).toBe('data6');
sorted[8] instanceof MyVertex && expect(sorted[8].id).toBe(1);
sorted[8] instanceof MyVertex && expect(sorted[8].key).toBe(1);
}
});
@ -266,9 +266,9 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
if (minPath1to7 && minPath1to7.length > 0) {
expect(minPath1to7).toHaveLength(3);
expect(minPath1to7[0]).toBeInstanceOf(MyVertex);
expect(minPath1to7[0].id).toBe(1);
expect(minPath1to7[1].id).toBe(9);
expect(minPath1to7[2].id).toBe(7);
expect(minPath1to7[0].key).toBe(1);
expect(minPath1to7[1].key).toBe(9);
expect(minPath1to7[2].key).toBe(7);
}
const fordResult1 = myGraph.bellmanFord(1);

View file

@ -30,16 +30,16 @@ describe('MapGraph Operation Test', () => {
const expected1 = ['Surin', 'Lotus', 'The Breeza', 'Trinity Auto', 'Saanen Goat Farm'];
const minPathBetween = mapGraph.getMinPathBetween('Surin', 'Saanen Goat Farm');
expect(minPathBetween?.map(v => v.id)).toEqual(expected1);
expect(minPathBetween?.map(v => v.key)).toEqual(expected1);
const surinToSaanenGoatFarmDij = mapGraph.dijkstra('Surin', 'Saanen Goat Farm', true, true);
expect(surinToSaanenGoatFarmDij?.minPath.map(v => v.id)).toEqual(expected1);
expect(surinToSaanenGoatFarmDij?.minPath.map(v => v.key)).toEqual(expected1);
expect(surinToSaanenGoatFarmDij?.minDist).toBe(41.1);
mapGraph.addEdge('Surin', 'Batu Feringgi Beach', 1.5);
const expected2 = ['Surin', 'Batu Feringgi Beach', 'Hard Rock Hotel', 'Saanen Goat Farm'];
const minPathBetweenViaBFB = mapGraph.getMinPathBetween('Surin', 'Saanen Goat Farm', true);
expect(minPathBetweenViaBFB?.map(v => v.id)).toEqual(expected2);
expect(minPathBetweenViaBFB?.map(v => v.key)).toEqual(expected2);
const surinToSaanenGoatFarmViaDij = mapGraph.dijkstra('Surin', 'Saanen Goat Farm', true, true);
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.id)).toEqual(expected2);
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.key)).toEqual(expected2);
expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2);
});
});

View file

@ -43,7 +43,7 @@ describe('Overall Graph Operation Test', () => {
graph.addEdge('B', 'D');
const dijkstraResult = graph.dijkstra('A');
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id); // ['A', 'B', 'D']
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key); // ['A', 'B', 'D']
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']);
});
});

View file

@ -54,6 +54,6 @@ describe('UndirectedGraph Operation Test', () => {
graph.addEdge('B', 'D');
const dijkstraResult = graph.dijkstra('A');
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']);
});
});

View file

@ -67,4 +67,3 @@ describe('Priority Queue Performance Test', () => {
expect(sorted).toEqual(values.sort((a, b) => a - b));
});
});

View file

@ -1,9 +1,9 @@
import {TreeNode} from '../../../../src';
describe('TreeNode', () => {
it('should create a TreeNode with the given id and value', () => {
it('should create a TreeNode with the given key and value', () => {
const node = new TreeNode<string>('1', 'Node 1');
expect(node.id).toBe('1');
expect(node.key).toBe('1');
expect(node.value).toBe('Node 1');
expect(node.children).toEqual([]);
});