Redesigned for greater coherence, TreeMultiset now inherits from AVLTree, with the 'count' member variable relocated to TreeMultiset. Revisions to the documentation have been made accordingly.

This commit is contained in:
Revone 2023-08-29 20:29:53 +08:00
parent 1a893cfd20
commit df2f940189
17 changed files with 808 additions and 683 deletions

View file

@ -20,16 +20,15 @@ import type {
import {AbstractBinaryTreeOptions, FamilyPosition, LoopType} from '../types';
import {IAbstractBinaryTree, IAbstractBinaryTreeNode} from '../interfaces';
export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBinaryTreeNode<T, FAMILY> = AbstractBinaryTreeNodeNested<T>> implements IAbstractBinaryTreeNode<T, FAMILY> {
export abstract class AbstractBinaryTreeNode<T = any, NEIGHBOR extends AbstractBinaryTreeNode<T, NEIGHBOR> = AbstractBinaryTreeNodeNested<T>> implements IAbstractBinaryTreeNode<T, NEIGHBOR> {
/**
* The constructor function initializes a BinaryTreeNode object with an id, value, and count.
* 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
* for the binary tree node.
* @param {T} [val] - The `val` parameter is an optional parameter of type `T`. It represents the value of the binary
* tree node. If no value is provided, it will be `undefined`.
* @param {number} [count] - The `count` parameter is an optional parameter that represents the number of times the
* value `val` appears in the binary tree node. If the `count` parameter is not provided, it defaults to 1.
* of the binary tree node. It is used to distinguish one node from another in the binary tree.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It represents the value that will be
* stored in the binary tree node. If no value is provided, it will be set to undefined.
*/
constructor(id: BinaryTreeNodeId, val?: T) {
this._id = id;
@ -56,40 +55,39 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
this._val = value;
}
private _left?: FAMILY | null;
private _left: NEIGHBOR | null | undefined;
get left(): FAMILY | null | undefined {
get left(): NEIGHBOR | null | undefined {
return this._left;
}
set left(v: FAMILY | null | undefined) {
set left(v: NEIGHBOR | null | undefined) {
if (v) {
v.parent = this as unknown as FAMILY;
v.parent = this as unknown as NEIGHBOR;
}
this._left = v;
}
private _right: NEIGHBOR | null | undefined;
private _right?: FAMILY | null;
get right(): FAMILY | null | undefined {
get right(): NEIGHBOR | null | undefined {
return this._right;
}
set right(v: FAMILY | null | undefined) {
set right(v: NEIGHBOR | null | undefined) {
if (v) {
v.parent = this as unknown as FAMILY;
v.parent = this as unknown as NEIGHBOR;
}
this._right = v;
}
private _parent: FAMILY | null | undefined;
private _parent: NEIGHBOR | null | undefined;
get parent(): FAMILY | null | undefined {
get parent(): NEIGHBOR | null | undefined {
return this._parent;
}
set parent(v: FAMILY | null | undefined) {
set parent(v: NEIGHBOR | null | undefined) {
this._parent = v;
}
@ -103,8 +101,12 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
this._height = v;
}
/**
* The function determines the position of a node in a family tree structure.
* @returns a value of type `FamilyPosition`.
*/
get familyPosition(): FamilyPosition {
const that = this as unknown as FAMILY;
const that = this as unknown as NEIGHBOR;
if (that.parent) {
if (that.parent.left === that) {
if (that.left || that.right) {
@ -151,13 +153,45 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
}
private _root: N | null = null;
get root(): N | null {
return this._root;
}
private _size = 0;
get size(): number {
return this._size;
}
private _loopType: LoopType = LoopType.ITERATIVE;
get loopType(): LoopType {
return this._loopType;
}
private _autoIncrementId: boolean = false;
get autoIncrementId(): boolean {
return this._autoIncrementId;
}
private _maxId: number = -1;
get maxId(): number {
return this._maxId;
}
// TODO this variable may be moved to TreeMultiset
private _isMergeDuplicatedVal: boolean = true;
get isMergeDuplicatedVal(): boolean {
return this._isMergeDuplicatedVal;
}
private _visitedId: BinaryTreeNodeId[] = [];
get visitedId(): BinaryTreeNodeId[] {
return this._visitedId;
}
@ -186,40 +220,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._visitedLeftSum;
}
private _autoIncrementId: boolean = false;
get autoIncrementId(): boolean {
return this._autoIncrementId;
}
private _maxId: number = -1;
get maxId(): number {
return this._maxId;
}
private _isMergeDuplicatedVal: boolean = true;
get isMergeDuplicatedVal(): boolean {
return this._isMergeDuplicatedVal;
}
private _root: N | null = null;
get root(): N | null {
return this._root;
}
private _size = 0;
get size(): number {
return this._size;
}
abstract createNode(id: BinaryTreeNodeId, val?: N['val']): N | null ;
/**
* The `swapLocation` function swaps the location of two nodes in a binary tree.
* @param {N} srcNode - The source node that you want to swap with the destination node.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will
* be swapped to.
* @returns The `destNode` is being returned.
*/
swapLocation(srcNode: N, destNode: N): N {
const {val, height, id} = destNode;
const tempNode = this.createNode(id, val);
@ -228,8 +237,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
if (tempNode instanceof AbstractBinaryTreeNode) {
// TODO should we consider the left, right children?
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
@ -244,7 +251,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The clear function resets the state of an object by setting its properties to their initial values.
* The clear() function resets the root, size, and maxId properties to their initial values.
*/
clear() {
this._setRoot(null);
@ -261,19 +268,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The `add` function inserts a new node with a given ID and value into a binary tree, updating the count if the node
* already exists.
* @param {BinaryTreeNodeId} id - The id parameter is the identifier of the binary tree node. It is used to uniquely
* identify each node in the binary tree.
* @param {N} val - The value to be inserted into the binary tree.
* @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the
* value should be inserted into the binary tree. If not provided, it defaults to 1.
* @returns The function `add` returns a `N` object if a new node is inserted, or `null` if no new node
* is inserted, or `undefined` if the insertion fails.
* The `add` function adds a new node to a binary tree, updating the value of an existing node if it already exists.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that you want to add.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. If no value is
* provided, the default value will be the same as the `id` parameter.
* @param {number} [count] - The `count` parameter is an optional number that represents the number of times the value
* should be added to the binary tree. If not provided, the default value is `undefined`.
* @returns The function `add` returns either a `BinaryTreeNode` object (`N`), `null`, or `undefined`.
*/
add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null | undefined {
count = count ?? 1;
const _bfs = (root: N, newNode: N | null): N | undefined | null => {
const queue: Array<N | null> = [root];
while (queue.length > 0) {
@ -311,13 +314,13 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function adds a new node to a binary tree as the left or right child of a given parent node.
* The function adds a new node to the left or right child of a parent node, updating the size of the tree if
* necessary.
* @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to the tree. It can be
* either a node object (`N`) or `null`.
* @param {N} parent - The `parent` parameter represents the parent node to which the new node will be added as a
* child.
* @returns either the left or right child node that was added to the parent node. It can also return `null` or
* `undefined` in certain cases.
* @returns either the left child node, the right child node, or undefined.
*/
addTo(newNode: N | null, parent: N): N | null | undefined {
if (parent) {
@ -349,11 +352,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The `addMany` function inserts multiple items into a binary tree and returns an array of the inserted nodes or
* The `addMany` function adds multiple nodes to a binary tree and returns an array of the inserted nodes or
* null/undefined values.
* @param {N[] | N[]} data - The `data` parameter can be either an array of elements of type `N` or an
* array of `N` objects.
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
* @param {N[] | Array<N['val']>} data - The `data` parameter can be either an array of `N` objects or an array of
* `N['val']` values.
* @returns The function `addMany` returns an array of values of type `N | null | undefined`.
*/
addMany(data: N[] | Array<N['val']>): (N | null | undefined)[] {
// TODO not sure addMany not be run multi times
@ -376,7 +379,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
continue;
}
// TODO will this cause an issue?
const count = this.isMergeDuplicatedVal ? map.get(nodeOrId) : 1;
let newId: BinaryTreeNodeId;
@ -413,11 +415,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The `fill` function clears the current data and inserts new data, returning a boolean indicating if the insertion
* was successful.
* @param {N[] | N[]} data - The `data` parameter can be either an array of elements of type `N` or an
* array of `N` objects.
* @returns The method is returning a boolean value.
* The `fill` function clears the current data and adds new data, returning a boolean indicating if the operation was
* successful.
* @param {N[] | Array<N['val']>} data - The `data` parameter can be either an array of objects or an array of arrays.
* Each object or array should have a property called `val`.
* @returns a boolean value.
*/
fill(data: N[] | Array<N['val']>): boolean {
this.clear();
@ -427,10 +429,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* 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 | BinaryTreeNodeId} nodeOrId - The `nodeOrId` parameter can be either a node object (`N`) or a binary tree
* node ID (`BinaryTreeNodeId`).
* @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
* whether to ignore the count of the nodes in the binary tree. If `ignoreCount` is set to `true`, the count of the
* nodes in the binary tree will not be updated after removing a node. If `ignoreCount`
* @returns The function `remove` returns an array of `BinaryTreeDeletedResult<N>` objects.
*/
remove(nodeOrId: N | BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
@ -443,7 +446,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
const parent: N | null = curr?.parent ? curr.parent : null;
let needBalanced: N | null = null, orgCurrent = curr;
if (!curr.left) {
if (!parent) {
if (curr.right !== undefined) this._setRoot(curr.right);
@ -470,7 +472,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
this._setSize(this.size - 1);
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
return bstDeletedResult;
}
@ -492,11 +493,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The `getHeight` function calculates the maximum height of a binary tree using either a recursive or iterative
* approach.
* @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type
* `N | null`. It represents the starting node from which to calculate the height of the binary tree.
* If no value is provided for `beginRoot`, the function will use the `root` property of the class instance as
* 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
* node), or `null`.
* @returns the height of the binary tree.
*/
getHeight(beginRoot?: N | BinaryTreeNodeId | null): number {
@ -543,9 +543,9 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `getMinHeight` function calculates the minimum height of a binary tree using either a recursive or iterative
* approach.
* @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type
* `N | null`. It represents the starting node from which to calculate the minimum height of the binary
* tree. If no value is provided for `beginRoot`, the function will use the root node of the binary tree.
* @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It
* represents the starting node from which to calculate the minimum height of a binary tree. If no value is provided
* for `beginRoot`, the `this.root` property is used as the default value.
* @returns The function `getMinHeight` returns the minimum height of the binary tree.
*/
getMinHeight(beginRoot?: N | null): number {
@ -591,9 +591,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function checks if a binary tree is balanced by comparing the minimum height and the maximum height of the tree.
* @param {N | null} [beginRoot] - The `beginRoot` parameter is the root node of a binary tree. It is
* of type `N | null`, which means it can either be a `BinaryTreeNode` object or `null`.
* The function checks if a binary tree is perfectly balanced by comparing the minimum height and the height of the
* tree.
* @param {N | null} [beginRoot] - The parameter `beginRoot` is of type `N` or `null`. It represents the root node of a
* tree or null if the tree is empty.
* @returns The method is returning a boolean value.
*/
isPerfectlyBalanced(beginRoot?: N | null): boolean {
@ -601,16 +602,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function `getNodes` returns an array of binary tree nodes that match a given property value, with options for
* searching recursively or iteratively.
* 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
* 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'.
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
* return only one node that matches the `nodeProperty` or `propertyName` criteria. If `onlyOne` is set to `true`, the
* function will stop traversing the tree and return the first matching node. If `
* @returns The function `getNodes` returns an array of `N | null | undefined` objects.
* 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[] {
if (!this.root) return [];
@ -643,12 +643,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function checks if a binary tree node has a specific property or if any node in the tree has a specific
* property.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* generic type `N`. It represents the property of a binary tree node that you want to check.
* 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`.
* 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 check for in the nodes.
* specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'id'.
* @returns a boolean value.
*/
has(nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName): boolean {
@ -657,13 +656,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function returns the first binary tree node that matches the given property name and value, or null if no match
* is found.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* generic type `N`. It represents the property of the binary tree node that you want to search for.
* 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`.
* 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 of the binary tree node to search for. If not provided, it defaults to `'id'`.
* @returns a BinaryTreeNode object or null.
* 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'`.
* @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';
@ -671,11 +672,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function getPathToRoot returns an array of BinaryTreeNode objects representing the path from a given node to the
* root of a binary tree.
* @param node - The `node` parameter is a BinaryTreeNode object.
* @returns The function `getPathToRoot` returns an array of `N` objects, representing the path from
* the given `node` to the root of the binary tree.
* The function getPathToRoot takes a node and returns an array of nodes representing the path from the given node to
* the root node.
* @param {N} node - The parameter `node` represents a node in a tree data structure.
* @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
*/
getPathToRoot(node: N): N[] {
const result: N[] = [];
@ -691,7 +691,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
getLeftMost(node: N): N;
/**
* The `getLeftMost` function returns the leftmost node in a binary tree, starting from a specified node or the root if
* no node is specified.
@ -734,10 +733,12 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using
* tail recursion optimization.
* @param {N | null} [node] - The `node` parameter is an optional parameter of type `N
* | null`. It represents the starting node from which to find the rightmost node in a binary tree. If no node is
* provided, the function will use the root node of the binary tree.
* @returns The `getRightMost` function returns the rightmost node in a binary tree.
* @param {N | null} [node] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the
* starting node from which we want to find the rightmost node. If no node is provided, the `node` parameter defaults
* to `this.root`, which is the root node of the data structure
* @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If the `node` parameter is
* not provided, it defaults to the root node of the tree. If the tree is empty or the `node` parameter is `null`, the
* function returns `null`.
*/
getRightMost(node?: N | null): N | null {
node = node ?? this.root;
@ -761,9 +762,8 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
}
/**
* The function `isBSTByRooted` checks if a binary tree is a binary search tree (BST) by rooted traversal.
* The function checks if a binary search tree is valid by traversing it either recursively or iteratively.
* @param {N | null} node - The `node` parameter represents the root node of a binary search tree (BST).
* @returns a boolean value.
*/
@ -807,12 +807,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function calculates the size and count of a subtree in a binary tree using either recursive or iterative
* traversal.
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter is the root node of a binary
* tree.
* @returns The function `getSubTreeSizeAndCount` returns an array `[number, number]`. The first element of the array
* represents the size of the subtree, and the second element represents the count of the nodes in the subtree.
* The function calculates the size of a subtree by traversing it either recursively or iteratively.
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a
* binary tree.
* @returns the size of the subtree rooted at `subTreeRoot`.
*/
getSubTreeSize(subTreeRoot: N | null | undefined) {
let size = 0;
@ -841,17 +839,14 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
}
// --- start additional methods ---
/**
* The function `subTreeSum` calculates the sum of a specified property in a binary tree, either recursively or
* iteratively.
* @param subTreeRoot - The subTreeRoot parameter is the root node of the subtree for which you want to calculate the
* sum.
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
* specifies the property of the `BinaryTreeNode` object to use for calculating the sum. If `propertyName` is not
* provided, it defaults to `'val'`.
* @returns a number, which is the sum of the values of the nodes in the subtree rooted at `subTreeRoot`.
* 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
* 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'.
* @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';
@ -899,16 +894,14 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return sum;
}
/**
* 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
* tree or the ID of a binary tree node. It can also be `null` if there is no subtree root.
* 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 or decremented.
* 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. It can be either 'id' or 'count'. If no
* value is provided for `propertyName`, it defaults to 'id'.
* specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'id'.
* @returns a boolean value.
*/
subTreeAdd(subTreeRoot: N | BinaryTreeNodeId | null, delta: number, propertyName ?: BinaryTreeNodePropertyName): boolean {
@ -959,13 +952,13 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
BFS(nodeOrPropertyName: 'node'): N[];
/**
* The BFS function performs a breadth-first search on a binary tree and returns the results based on a specified node
* or property name.
* The BFS function performs a breadth-first search on a binary tree, accumulating properties of each node based on a
* specified property name.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is an optional parameter that
* represents either a node or a property name. If a node is provided, the breadth-first search algorithm will be
* performed starting from that node. If a property name is provided, the breadth-first search algorithm will be
* performed starting from the root node
* @returns an object of type `AbstractBinaryTreeNodeProperties<N>`.
* represents either a node or a property name. If a node is provided, the breadth-first search (BFS) algorithm will be
* performed starting from that node. If a property name is provided, the BFS algorithm will be performed starting from
* the
* @returns an instance of the `AbstractBinaryTreeNodeProperties` class with generic type `N`.
*/
BFS(nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
@ -993,16 +986,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
/**
* The DFS function performs a depth-first search traversal on a binary tree and returns the results based on the
* specified pattern and node or property name.
* @param {'in' | 'pre' | 'post'} [pattern] - The "pattern" parameter is used to specify the order in which the nodes
* of a binary tree are traversed during the Depth-First Search (DFS) algorithm. It can take one of three values: 'in',
* 'pre', or 'post'.
* 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 "pattern" parameter is used to specify the traversal order of the
* binary tree. It can have three possible values:
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is a string that represents
* either the name of a property in the `BinaryTreeNode` object or the value of the `id` property in the
* `BinaryTreeNode` object. This parameter is used to accumulate the results based on the specified property name. If
* no value
* @returns an object of type `AbstractBinaryTreeNodeProperties<N>`.
* 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'`.
* @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';
@ -1032,6 +1024,9 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._getResultByPropertyName(nodeOrPropertyName);
}
// --- start additional methods ---
DFSIterative(): BinaryTreeNodeId[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
@ -1041,11 +1036,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
/**
* Time complexity is O(n)
* Space complexity of Iterative DFS equals to recursive DFS which is O(n) because of the stack
* @param pattern
* @param nodeOrPropertyName
* @constructor
* 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 "pattern" parameter determines the order in which the nodes of the
* binary tree are visited during the depth-first search. It can have one of the following values:
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is used to specify the
* property of the nodes that you want to retrieve or perform operations on during the depth-first search traversal. By
* default, it is set to `'id'`, which means that the traversal will accumulate results based on the `id` property of
* the
* @returns an object of type AbstractBinaryTreeNodeProperties<N>.
*/
DFSIterative(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
pattern = pattern || 'in';
@ -1225,19 +1224,22 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
/**
* Time complexity is O(n)
* Space complexity of Iterative DFS equals to recursive DFS which is O(n) because of the stack
*/
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
/**
* The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris
* traversal algorithm and returns the results based on the specified property name.
* The time complexity of Morris traversal is O(n), it's may slower than others
* The space complexity Morris traversal is O(1) because no using stack
* @param {'in' | 'pre' | 'post'} [pattern] - The `pattern` parameter is an optional parameter that determines the
* traversal pattern of the binary tree. It can have one of three values:
* traversal algorithm.
* @param {'in' | 'pre' | 'post'} [pattern] - The `pattern` parameter determines the traversal pattern for the binary
* tree. It can have one of three values:
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is used to specify the
* property of the nodes that you want to retrieve in the results. It can be either the node itself or the name of the
* property. If not provided, it defaults to `'id'`.
* @returns The function `morris` returns an object of type `AbstractBinaryTreeNodeProperties<N>`.
* property name of the nodes that you want to retrieve. It can be any valid property name of the nodes in the binary
* tree.
* @returns an array of AbstractBinaryTreeNodeProperties<N> objects.
*/
morris(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
if (this.root === null) return [];
@ -1325,42 +1327,86 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._getResultByPropertyName(nodeOrPropertyName);
}
/**
* The function sets the loop type for a protected variable.
* @param {LoopType} value - The value parameter is of type LoopType.
*/
protected _setLoopType(value: LoopType) {
this._loopType = value;
}
/**
* The function sets the value of the `_visitedId` property in a protected manner.
* @param {BinaryTreeNodeId[]} value - value is an array of BinaryTreeNodeId values.
*/
protected _setVisitedId(value: BinaryTreeNodeId[]) {
this._visitedId = value;
}
/**
* The function sets the value of the "_visitedVal" property to the given array.
* @param value - An array of type N.
*/
protected _setVisitedVal(value: Array<N>) {
this._visitedVal = value;
}
/**
* The function sets the value of the _visitedNode property.
* @param {N[]} value - N[] is an array of elements of type N.
*/
protected _setVisitedNode(value: N[]) {
this._visitedNode = value;
}
/**
* The function sets the value of the visitedCount property.
* @param {number[]} value - The value parameter is an array of numbers.
*/
protected setVisitedCount(value: number[]) {
this._visitedCount = value;
}
/**
* The function sets the value of the `_visitedLeftSum` property to the provided array.
* @param {number[]} value - An array of numbers that represents the visited left sum.
*/
protected _setVisitedLeftSum(value: number[]) {
this._visitedLeftSum = value;
}
/**
* The function sets the value of the _autoIncrementId property.
* @param {boolean} value - The value parameter is a boolean that determines whether the id should be automatically
* incremented or not. If value is true, the id will be automatically incremented. If value is false, the id will not
* be automatically incremented.
*/
protected _setAutoIncrementId(value: boolean) {
this._autoIncrementId = value;
}
/**
* The function sets the maximum ID value.
* @param {number} value - The value parameter is a number that represents the new maximum ID value.
*/
protected _setMaxId(value: number) {
this._maxId = value;
}
/**
* The function sets the value of a protected property called "_isMergeDuplicatedVal".
* @param {boolean} value - The value parameter is a boolean value that determines whether the isMergeDuplicatedVal
* property should be set to true or false.
*/
protected _setIsDuplicatedVal(value: boolean) {
this._isMergeDuplicatedVal = value;
}
/**
* The function sets the root property of an object to a given value, and if the value is not null, it also sets the
* parent property of the value to undefined.
* @param {N | null} v - The parameter `v` is of type `N | null`, which means it can either be of type `N` or `null`.
*/
protected _setRoot(v: N | null) {
if (v) {
v.parent = undefined;
@ -1368,12 +1414,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
this._root = v;
}
/**
* The function sets the size of a protected variable.
* @param {number} v - number
*/
protected _setSize(v: number) {
this._size = v;
}
/**
* The function resets the values of several arrays used for tracking visited nodes and their properties.
* The function `_resetResults` resets the values of several arrays used for tracking visited nodes and their
* properties.
*/
protected _resetResults() {
this._visitedId = [];
@ -1385,18 +1436,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
/**
* The function checks if a given property of a binary tree node matches a specified value, and if so, adds the node to
* a result array.
* @param cur - The current binary tree node that is being checked.
* @param {(N | null | undefined)[]} result - An array that stores the matching nodes found during the
* traversal.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter is the value that we are searching for in
* the binary tree nodes. It can be either the `id`, `count`, or `val` property of the node.
* @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`
* 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 of the `BinaryTreeNode` object that you want to compare with the `nodeProperty` value. It can
* be one of the following values: 'id', 'count', or 'val'. If no `propertyName` is provided,
* 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
* @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
* @returns a boolean value indicating whether or not a node was pushed into the result array.
* @returns a boolean value indicating whether only one matching node should be pushed into the result array.
*/
protected _pushByPropertyNameStopOrNot(cur: N, result: (N | null | undefined)[], nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean) {
switch (propertyName) {
@ -1422,12 +1472,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function `_accumulatedByPropertyName` pushes a property value of a binary tree node into an array based on the
* provided property name or a default property name.
* @param node - The `node` parameter is of type `N`, which represents a node in a binary tree.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is an optional parameter that
* can be either a string representing a property name or a reference to a node object. If it is a string, it specifies
* the property name of the node that should be accumulated. If it is a node object, it specifies the node itself
* The function `_accumulatedByPropertyName` accumulates values from a given node based on the specified property name.
* @param {N} node - The `node` parameter is of type `N`, which represents a node in a data structure.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that
* can be either a string representing a property name or a reference to a `Node` object. If it is a string, it
* 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';
@ -1449,11 +1498,16 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function `_getResultByPropertyName` returns different results based on the provided property name or defaulting
* to 'id'.
* The time complexity of Morris traversal is O(n), it's may slower than others
* The space complexity Morris traversal is O(1) because no using stack
*/
/**
* The function `_getResultByPropertyName` returns the corresponding property value based on the given node or property
* name.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is an optional parameter that
* can accept a value of type `NodeOrPropertyName`.
* @returns The method returns an object of type `AbstractBinaryTreeNodeProperties<T>`.
* can accept either a `NodeOrPropertyName` type or be undefined.
* @returns The method `_getResultByPropertyName` returns an instance of `AbstractBinaryTreeNodeProperties<N>`.
*/
protected _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';

View file

@ -9,29 +9,38 @@ import {BST, BSTNode} from './bst';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeId} from '../types';
import {IAVLTree, IAVLTreeNode} from '../interfaces';
export class AVLTreeNode<T = any, FAMILY extends AVLTreeNode<T, FAMILY> = AVLTreeNodeNested<T>> extends BSTNode<T, FAMILY> implements IAVLTreeNode<T, FAMILY> {
export class AVLTreeNode<T = any, NEIGHBOR extends AVLTreeNode<T, NEIGHBOR> = AVLTreeNodeNested<T>> extends BSTNode<T, NEIGHBOR> implements IAVLTreeNode<T, NEIGHBOR> {
}
export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends BST<N> implements IAVLTree<N> {
/**
* This is a constructor function for an AVL tree data structure in TypeScript.
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
* constructor of the AVLTree class. It allows you to customize the behavior of the AVL tree by providing different
* options.
*/
constructor(options?: AVLTreeOptions) {
super(options);
}
/**
* 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
* 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.
*/
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new AVLTreeNode<N['val'], N>(id, val) as N;
}
/**
* The function overrides the add method of a Binary Search Tree to insert a node with a given id and value, and then
* balances the tree.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that we want to add or
* update in the AVL tree.
* @param {N | null} val - The `val` parameter represents the value that you want to assign to the node with the given
* `id`. It can be of type `N` (the generic type) or `null`.
* @param {number} [count] - The `count` parameter is an optional parameter of type `number`. It represents the number
* of times the value `val` should be inserted into the AVL tree. If the `count` parameter is not provided, it defaults
* to `1`, indicating that the value should be inserted once.
* @returns The method is returning either an N object or null.
* 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 [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 {
const inserted = super.add(id, val);

View file

@ -6,40 +6,35 @@
* @license MIT License
*/
import type {BinaryTreeNodeId, BinaryTreeNodeNested} from '../types';
import {BinaryTreeOptions} from '../types';
import type {BinaryTreeNodeId, BinaryTreeNodeNested, BinaryTreeOptions} from '../types';
import {AbstractBinaryTree, AbstractBinaryTreeNode} from './abstract-binary-tree';
import {IBinaryTree, IBinaryTreeNode} from '../interfaces/binary-tree';
export class BinaryTreeNode<T = any, FAMILY extends BinaryTreeNode<T, FAMILY> = BinaryTreeNodeNested<T>> extends AbstractBinaryTreeNode<T, FAMILY> implements IBinaryTreeNode<T, FAMILY> {
export class BinaryTreeNode<T = any, NEIGHBOR extends BinaryTreeNode<T, NEIGHBOR> = BinaryTreeNodeNested<T>> extends AbstractBinaryTreeNode<T, NEIGHBOR> implements IBinaryTreeNode<T, NEIGHBOR> {
}
export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode> extends AbstractBinaryTree<N> implements IBinaryTree<N> {
/**
* The constructor function accepts an optional options object and sets the values of loopType, autoIncrementId, and
* isMergeDuplicatedVal based on the provided options.
* @param [options] - An optional object that can contain the following properties:
* This is a constructor function for a binary tree class that takes an optional options parameter.
* @param {BinaryTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
* constructor of the `BinaryTree` class. It allows you to customize the behavior of the binary tree by providing
* different configuration options.
*/
constructor(options?: BinaryTreeOptions) {
super(options);
}
/**
* The function creates a new binary tree node with the given id, value, and count if the value is not null, otherwise
* it returns null.
* 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`.
* @param {N | null} val - The `val` parameter represents the value of the node. It can be of type `N` (generic type)
* or `null`.
* @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 tree node. If not provided, the default value is `undefined`.
* @returns a BinaryTreeNode object if the value is not null, otherwise it returns null.
* `BinaryTreeNodeId`, 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.
*/
createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new BinaryTreeNode<N['val'], N>(id, val) as N;
}
}

View file

@ -5,18 +5,19 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested} from '../types';
import {BSTOptions, CP, LoopType} from '../types';
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested, BSTOptions} from '../types';
import {CP, LoopType} from '../types';
import {BinaryTree, BinaryTreeNode} from './binary-tree';
import {IBST, IBSTNode} from '../interfaces';
export class BSTNode<T = any, FAMILY extends BSTNode<T, FAMILY> = BSTNodeNested<T>> extends BinaryTreeNode<T, FAMILY> implements IBSTNode<T, FAMILY> {
export class BSTNode<T = any, NEIGHBOR extends BSTNode<T, NEIGHBOR> = BSTNodeNested<T>> extends BinaryTreeNode<T, NEIGHBOR> implements IBSTNode<T, NEIGHBOR> {
}
export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N> implements IBST<N> {
/**
* The constructor function accepts an optional options object and sets the comparator property if provided.
* @param [options] - An optional object that can contain the following properties:
* The constructor function initializes a binary search tree object with an optional comparator function.
* @param {BSTOptions} [options] - An optional object that contains configuration options for the binary search tree.
*/
constructor(options?: BSTOptions) {
super(options);
@ -29,30 +30,25 @@ 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, value, and count.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is of type
* `BinaryTreeNodeId`.
* @param {N['val'] | null} [val] - The `val` parameter is the value that will be stored in the node. It can be of any
* type `N['val']` or `null`.
* @param {number} [count] - The `count` parameter is an optional parameter that represents the number of occurrences
* of a particular value in the binary search tree node.
* @returns a new instance of the BSTNode class, casted as type 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
* 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.
*/
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
return new BSTNode<N['val'], N>(id, val) as N;
}
/**
* The `add` function inserts a new node into a binary search tree, updating the count and value of an existing node if
* the ID matches, and returns the inserted node.
* @param {BinaryTreeNodeId} id - The `id` parameter represents the identifier of the binary tree node. It is used to
* determine the position of the node in the binary search tree.
* @param {N | null} val - The `val` parameter represents the value to be stored in the binary search tree node. It can
* be of type `N` (the generic type) or `null`.
* @param {number} [count=1] - The `count` parameter represents the number of times the value should be inserted into
* the binary search tree. By default, it is set to 1, meaning that if no count is specified, the value will be
* inserted once.
* @returns The method `add` returns a `N` object or `null`.
* The `add` function adds a new node to a binary tree, ensuring that duplicates are not accepted.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that we want to add. It
* is of type `BinaryTreeNodeId`.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It represents
* the value associated with the node.
* @returns The function `add` returns the inserted node (`inserted`) if it was successfully added to the binary tree.
* If the node was not added (e.g., due to a duplicate ID), it returns `null` or `undefined`.
*/
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
let inserted: N | null = null;
@ -113,13 +109,12 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
/**
* The `get` function returns the first node in a binary search tree that matches the given property value or name.
* 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
* generic type `N`. It represents the value of the property that you want to search for in the binary search tree.
* 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 search tree nodes. If not provided, it defaults to
* `'id'`.
* @returns The method is returning a N object or null.
* 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.
*/
override get(nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'id';
@ -129,10 +124,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* 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 function `lastKey()` returns the ID of the rightmost node in a binary tree. If the comparison between
* the first two elements in the tree is less than, it returns the ID of the rightmost node. If the comparison is
* greater than, it returns the ID of the leftmost node. Otherwise, it also returns the ID of the rightmost node. If
* there are no nodes in
* @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.
*/
lastKey(): BinaryTreeNodeId {
if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.id ?? 0;
@ -141,17 +135,15 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
/**
* The function `getNodes` returns an array of binary search tree nodes that match a given property value, with the
* option to specify the property name and whether to return only one node.
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
* generic type `N`. It represents the property value that you want to search for in the binary search tree.
* 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
* `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 of the nodes to compare with the `nodeProperty` parameter. If not provided, it defaults to
* `'id'`.
* @param {boolean} [onlyOne] - A boolean value indicating whether to return only one node that matches the given
* nodeProperty. If set to true, the function will stop traversing the tree and return the first matching node. If set
* to false or not provided, the function will return all nodes that match the given nodeProperty.
* @returns an array of N objects.
* specifies the property name to use for comparison. If not provided, it defaults to `'id'`.
* @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, onlyOne ?: boolean): N[] {
propertyName = propertyName ?? 'id';
@ -195,13 +187,13 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
// --- start additional functions
/**
* The `lesserSum` function calculates the sum of property values in a binary tree for nodes that have a lesser value
* than a given node.
* 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 {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'`.
* @returns The function `lesserSum` returns a number, which represents the sum of the values of the nodes in a binary
* tree that have a lesser value than the specified `beginNode` based on the specified `propertyName`.
* @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';
@ -268,15 +260,15 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
/**
* The function `allGreaterNodesAdd` updates the value of a specified property for all nodes in a binary search tree
* that have a greater value than a given node.
* @param node - The `node` parameter is of type `N`, which represents a node in a binary search tree. It
* contains properties such as `id` and `count`.
* 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 {number} delta - The `delta` parameter is a number that represents the amount by which the property value of
* each node should be increased.
* @param {BinaryTreeNodePropertyName} [propertyName] - propertyName is an optional parameter that specifies the
* property of the BSTNode to be modified. It can be either 'id' or 'count'. If propertyName is not provided, it
* defaults to 'id'.
* 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'.
* @returns a boolean value.
*/
allGreaterNodesAdd(node: N | BinaryTreeNodeId | null, delta: number, propertyName ?: BinaryTreeNodePropertyName): boolean {
@ -336,9 +328,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
/**
* The `balance` function takes a sorted array of nodes and builds a balanced binary search tree using either a
* recursive or iterative approach.
* @returns The `balance()` function returns a boolean value.
* The `perfectlyBalance` function takes a binary tree, performs a depth-first search to sort the nodes, and then
* constructs a balanced binary search tree using either a recursive or iterative approach.
* @returns The function `perfectlyBalance()` returns a boolean value.
*/
perfectlyBalance(): boolean {
const sorted = this.DFS('in', 'node'), n = sorted.length;
@ -377,9 +369,8 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
}
/**
* The function `isAVLBalanced` checks if a binary search tree is balanced according to the AVL tree property.
* @returns The function `isAVLBalanced()` returns a boolean value. It returns `true` if the binary search tree (BST)
* is balanced according to the AVL tree property, and `false` otherwise.
* The function `isAVLBalanced` checks if a binary tree is balanced according to the AVL tree property.
* @returns a boolean value.
*/
isAVLBalanced(): boolean {
if (!this.root) return true;

View file

@ -3,7 +3,7 @@ import {IRBTree, IRBTreeNode} from '../interfaces/rb-tree';
import {BST, BSTNode} from './bst';
export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> = RBTreeNodeNested<T>> extends BSTNode<T, FAMILY> implements IRBTreeNode<T, FAMILY> {
export class RBTreeNode<T = any, NEIGHBOR extends RBTreeNode<T, NEIGHBOR> = RBTreeNodeNested<T>> extends BSTNode<T, NEIGHBOR> implements IRBTreeNode<T, NEIGHBOR> {
constructor(id: BinaryTreeNodeId, color: RBColor, val?: T) {
super(id, val);
this._color = color;

View file

@ -11,7 +11,18 @@ import {ITreeMultiset, ITreeMultisetNode} from '../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
import {ObjectWithNumberId} from '../../utils';
export class TreeMultisetNode<T = any, FAMILY extends TreeMultisetNode<T, FAMILY> = TreeMultisetNodeNested<T>> extends AVLTreeNode<T, FAMILY> implements ITreeMultisetNode<T, FAMILY> {
export class TreeMultisetNode<T = any, NEIGHBOR extends TreeMultisetNode<T, NEIGHBOR> = TreeMultisetNodeNested<T>> extends AVLTreeNode<T, NEIGHBOR> implements ITreeMultisetNode<T, 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
* of the binary tree node.
* @param {T} [val] - The `val` parameter is an optional parameter of type `T`. It represents the value of the binary
* tree node. If no value is provided, it will be `undefined`.
* @param {number} [count=1] - The `count` parameter is a number that represents the number of times a particular value
* 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?: T, count: number = 1) {
super(id, val);
this._count = count;
@ -32,6 +43,13 @@ export class TreeMultisetNode<T = any, FAMILY extends TreeMultisetNode<T, FAMILY
* The only distinction between a TreeMultiset and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
*/
export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultisetNode> extends AVLTree<N> implements ITreeMultiset<N> {
/**
* The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to
* merge duplicated values.
* @param {TreeMultisetOptions} [options] - An optional object that contains additional configuration options for the
* TreeMultiset.
*/
constructor(options?: TreeMultisetOptions) {
super({...options, isMergeDuplicatedVal: true});
}
@ -55,6 +73,13 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
return new TreeMultisetNode(id, val, count) as N;
}
/**
* The function swaps the location of two nodes in a tree data structure.
* @param {N} srcNode - The source node that we want to swap with the destination node.
* @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will
* be swapped with.
* @returns the `destNode` after swapping its values with the `srcNode`.
*/
override swapLocation(srcNode: N, destNode: N): N {
const {val, count, height, id} = destNode;
const tempNode = this.createNode(id, val, count);
@ -62,9 +87,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
tempNode.height = height;
if (tempNode instanceof TreeMultisetNode) {
// TODO should we consider the left, right children?
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
@ -81,58 +103,16 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
}
/**
* The `add` function inserts a new node with a given ID and value into a binary tree, updating the count if the node
* already exists.
* @param {BinaryTreeNodeId} id - The id parameter is the identifier of the binary tree node. It is used to uniquely
* identify each node in the binary tree.
* @param {N} val - The value to be inserted into the binary tree.
* @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the
* value should be inserted into the binary tree. If not provided, it defaults to 1.
* @returns The function `add` returns a `N` object if a new node is inserted, or `null` if no new node
* is inserted, or `undefined` if the insertion fails.
* The `add` function adds a new node to a binary tree, updating the size and count properties accordingly, and
* balancing the tree if necessary.
* @param {BinaryTreeNodeId} id - The id parameter represents the identifier of the binary tree node that we want to
* add. It is of type BinaryTreeNodeId.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. If no value is
* provided, it will default to `undefined`.
* @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the node
* with the given `id` should be added to the binary tree. If the `count` parameter is not provided, it defaults to 1.
* @returns The `add` method returns the inserted node (`N`), `null`, or `undefined`.
*/
// override add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null | undefined {
// count = count ?? 1;
//
// 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) {
// const inserted = this.addTo(newNode, cur);
// if (inserted !== undefined) return inserted;
// if (cur.left) queue.push(cur.left);
// if (cur.right) queue.push(cur.right);
// } else return;
// }
// return;
// };
//
// let inserted: N | null | undefined;
// const needInsert = val !== null ? this.createNode(id, val, count) : null;
// const existNode = val !== null ? this.get(id, 'id') : null;
// if (this.root) {
// if (existNode) {
// existNode.count += count;
// existNode.val = val ?? id;
// if (needInsert !== null) {
// this._setCount(this.count + count);
// inserted = existNode;
// }
// } else {
// inserted = _bfs(this.root, needInsert);
// }
// } else {
// this._setRoot(val !== null ? this.createNode(id, val, count) : null);
// if (needInsert !== null) {
// this._setSize(1);
// this._setCount(count);
// }
// inserted = this.root;
// }
// return inserted;
// }
override add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null | undefined {
count = count ?? 1;
let inserted: N | null = null;
@ -268,7 +248,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
continue;
}
// TODO will this cause an issue?
const count = this.isMergeDuplicatedVal ? map.get(nodeOrId) : 1;
let newId: BinaryTreeNodeId;
@ -365,12 +344,11 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
}
/**
* The function calculates the size and count of a subtree in a binary tree using either recursive or iterative
* traversal.
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter is the root node of a binary
* tree.
* @returns The function `getSubTreeSizeAndCount` returns an array `[number, number]`. The first element of the array
* represents the size of the subtree, and the second element represents the count of the nodes in the subtree.
* The function `getSubTreeCount` calculates the number of nodes and the sum of their counts in a subtree, using either
* recursive or iterative traversal.
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a
* binary tree.
* @returns The function `getSubTreeCount` returns an array `[number, number]`.
*/
getSubTreeCount(subTreeRoot: N | null | undefined) {
const res: [number, number] = [0, 0];
@ -401,6 +379,14 @@ 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
* `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');
@ -409,7 +395,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
let sum = 0;
if (this.loopType === LoopType.RECURSIVE) {
const _traverse = (cur: N): void => {
sum += cur.count;
@ -474,6 +459,16 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
return true;
}
/**
* 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
* `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[] {
if (!this.root) return [];
const result: N[] = [];
@ -511,28 +506,68 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
return result;
}
/**
* The BFSCount function returns an array of counts from a breadth-first search of nodes.
* @returns The BFSCount() function returns an array of numbers, specifically the count property of each node in the
* BFS traversal.
*/
BFSCount(): number[] {
const nodes = super.BFS('node');
return nodes.map(node => node.count);
}
/**
* The function "listLevelsCount" takes a node and returns an array of arrays, where each inner array contains the
* count property of each node at that level.
* @param {N | null} node - The parameter `node` is of type `N | null`. This means that it can either be an instance of
* the class `N` or `null`.
* @returns a 2D array of numbers. Each inner array represents a level in the binary tree, and each number in the inner
* array represents the count property of a node in that level.
*/
listLevelsCount(node: N | null): number[][] {
const levels = super.listLevels(node, 'node');
return levels.map(level => level.map(node => node.count));
}
/**
* The `morrisCount` function returns an array of counts for each node in a binary tree, based on a specified traversal
* pattern.
* @param {'in' | 'pre' | 'post'} [pattern] - The `pattern` parameter is an optional parameter that specifies the
* traversal pattern for the Morris traversal algorithm. It can have one of three values: 'in', 'pre', or 'post'.
* @returns The function `morrisCount` returns an array of numbers.
*/
morrisCount(pattern?: 'in' | 'pre' | 'post'): number[] {
pattern = pattern || 'in';
const nodes = super.morris(pattern, 'node');
return nodes.map(node => node.count);
}
/**
* The function DFSIterativeCount performs a depth-first search iteratively and returns an array of count values for
* each node.
* @param {'in' | 'pre' | 'post'} [pattern] - The "pattern" parameter is a string that specifies the traversal order
* for the Depth-First Search (DFS) algorithm. It can have one of three values: 'in', 'pre', or 'post'.
* @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that
* specifies whether to return the nodes or the property names during the depth-first search traversal. If it is set to
* `'node'`, the function will return the nodes. If it is set to `'property'`, the function will return the property
* @returns The DFSIterativeCount method returns an array of numbers.
*/
DFSIterativeCount(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): number[] {
pattern = pattern ?? 'in';
const nodes = super.DFSIterative(pattern, 'node');
return nodes.map(node => node.count);
}
/**
* The DFSCount function returns an array of counts for each node in a depth-first search traversal.
* @param {DFSOrderPattern} [pattern] - The `pattern` parameter is an optional parameter that specifies the order in
* which the Depth-First Search (DFS) algorithm should traverse the nodes. It can have one of the following values:
* @param [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is used to specify whether you want to retrieve the
* nodes themselves or a specific property of the nodes. If you pass `'count'` as the value for `nodeOrPropertyName`,
* the function will return an array of the `count` property of each node.
* @returns The DFSCount method returns an array of numbers representing the count property of each node in the DFS
* traversal.
*/
DFSCount(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[] {
pattern = pattern ?? 'in';
const nodes = super.DFS(pattern, 'node');
@ -540,6 +575,12 @@ 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:
* @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');
if (!beginNode) return 0;
@ -591,6 +632,14 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
return sum;
}
/**
* 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 {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');
if (!node) return false;
@ -626,14 +675,20 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
}
}
override clear() {
this._setRoot(null);
this._setSize(0);
/**
* The clear() function clears the data and sets the count to 0.
*/
clear() {
super.clear();
this._setCount(0);
this._setMaxId(-1);
}
/**
* The function "_setCount" is used to set the value of the "_count" property.
* @param {number} v - number
*/
protected _setCount(v: number) {
this._count = v;
}
}
}

View file

@ -12,6 +12,13 @@ import {IAbstractGraph} from '../interfaces';
export abstract class AbstractVertex<T = number> {
/**
* 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
* used to uniquely identify the vertex object.
* @param {T} [val] - The parameter "val" is an optional parameter of type T. 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?: T) {
this._id = id;
this._val = val;
@ -36,18 +43,19 @@ export abstract class AbstractVertex<T = number> {
set val(value: T | undefined) {
this._val = value;
}
// /**
// * 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 val
// */
// abstract createVertex(id: VertexId, val?: T): AbstractVertex<T>;
}
export abstract class AbstractEdge<T = number> {
/**
* The above function is a protected constructor that initializes the weight, value, and hash code properties of an
* object.
* @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the object. If
* a value is provided, it will be assigned to the `_weight` property. If no value is provided, the default value of 1
* will be assigned.
* @param {T} [val] - The `val` parameter is of type `T`, which means it can be any type. It is an optional parameter,
* meaning it can be omitted when creating an instance of the class.
*/
protected constructor(weight?: number, val?: T) {
this._weight = weight !== undefined ? weight : 1;
this._val = val;
@ -80,22 +88,21 @@ export abstract class AbstractEdge<T = number> {
return this._hashCode;
}
// /**
// * 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 srcOrV1
// * @param destOrV2
// * @param weight
// * @param val
// */
// abstract createEdge(srcOrV1: VertexId | string, destOrV2: VertexId | string, weight?: number, val?: E): E;
/**
* 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.
*/
/**
* The function sets the value of the _hashCode property to the provided string.
* @param {string} v - The parameter "v" is of type string and represents the value that will be assigned to the
* "_hashCode" property.
*/
protected _setHashCode(v: string) {
this._hashCode = v;
}
}
// Connected Component === Largest Connected Sub-Graph
export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends AbstractEdge<any>> implements IAbstractGraph<V, E> {
private _vertices: Map<VertexId, V> = new Map<VertexId, V>();
@ -122,23 +129,41 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
abstract createEdge(srcOrV1: VertexId | string, destOrV2: VertexId | string, weight?: number, val?: E): E;
abstract removeEdge(edge: E): E | null;
abstract getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
abstract degreeOf(vertexOrId: V | VertexId): number;
abstract edgeSet(): E[];
abstract edgesOf(vertexOrId: V | VertexId): E[];
abstract getNeighbors(vertexOrId: V | VertexId): V[];
abstract getEndsOfEdge(edge: E): [V, V] | null;
protected abstract _addEdgeOnly(edge: E): boolean;
/**
* 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
* the `_vertices` map.
* @returns The method `getVertex` returns the vertex with the specified `vertexId` 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;
}
/**
* The function checks if a vertex exists in a graph.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can accept either a vertex object (`V`) or a vertex ID
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
* (`VertexId`).
* @returns The method `hasVertex` returns a boolean value.
* @returns a boolean value.
*/
hasVertex(vertexOrId: V | VertexId): boolean {
return this._vertices.has(this._getVertexId(vertexOrId));
}
abstract getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
addVertex(vertex: V): boolean
addVertex(id: VertexId, val?: V['val']): boolean
addVertex(idOrVertex: VertexId | V, val?: V['val']): boolean {
@ -155,7 +180,7 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
* 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`).
* @returns The method `removeVertex` returns a boolean value.
* @returns The method is returning a boolean value.
*/
removeVertex(vertexOrId: V | VertexId): boolean {
const vertexId = this._getVertexId(vertexOrId);
@ -177,20 +202,13 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
return removed.length > 0;
}
abstract degreeOf(vertexOrId: V | VertexId): number;
abstract edgeSet(): E[];
abstract edgesOf(vertexOrId: V | VertexId): E[];
/**
* The function checks if there is an edge between two vertices in a graph.
* @param {VertexId | V} v1 - The parameter v1 can be either a VertexId or a V. A VertexId represents the identifier of
* a vertex in a graph, while V represents the type of the vertex itself.
* @param {VertexId | V} v2 - The parameter `v2` represents the second vertex in an edge. It can be either a `VertexId`
* or a `V` type.
* @returns The function `hasEdge` returns a boolean value. It returns `true` if there is an edge between the
* vertices `v1` and `v2`, and `false` otherwise.
* 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
* 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.
* @returns A boolean value is being returned.
*/
hasEdge(v1: VertexId | V, v2: VertexId | V): boolean {
const edge = this.getEdge(v1, v2);
@ -238,16 +256,13 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
}
}
abstract getNeighbors(vertexOrId: V | VertexId): V[];
/**
* 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`).
* It is the starting vertex for finding paths.
* @param {V | VertexId} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex that we
* want to find paths to from the starting vertex `v1`.
* @returns an array of arrays of vertices (V[][]). Each inner array represents a path between the given vertices (v1
* and v2).
* @param {V | VertexId} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
* @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`V[][]`).
*/
getAllPathsBetween(v1: V | VertexId, v2: V | VertexId): V[][] {
const paths: V[][] = [];
@ -296,16 +311,16 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
/**
* 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 vertex ID of the graph.
* @param {V | VertexId} v2 - The parameter `v2` represents the second vertex in the graph. It can be either a vertex
* object or a vertex ID.
* @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
* 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
* the edges. If isWeight is set to false or not provided, the function will calculate the
* @returns The function `getMinCostBetween` returns a number representing the minimum cost between two vertices (`v1`
* and `v2`) in a graph. If the `isWeight` parameter is `true`, it calculates the minimum weight between the vertices.
* If `isWeight` is `false` or not provided, it calculates the minimum number of edges between the vertices. If the
* vertices are not
* and `v2`). If the `isWeight` parameter is `true`, it calculates the minimum weight among all paths between the
* 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 {
if (isWeight === undefined) isWeight = false;
@ -355,14 +370,15 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
/**
* 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 or its ID.
* @param {V | VertexId} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex that we
* want to find the minimum path to from the source vertex `v1`.
* @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
* 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
* to false, the function will use breadth-first search (BFS) to find the minimum path. If
* to false, the function will use breadth-first search (BFS) to find the minimum path.
* @returns The function `getMinPathBetween` returns an array of vertices (`V[]`) representing the minimum path between
* two vertices (`v1` and `v2`). If no path is found, it returns `null`.
* 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 {
if (isWeight === undefined) isWeight = false;
@ -416,6 +432,10 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
}
/**
* Dijkstra algorithm time: O(VE) space: O(V + E)
* /
/**
* 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.
@ -543,6 +563,14 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
/**
* Dijkstra algorithm time: O(logVE) space: O(V + E)
*
* Dijkstra's algorithm only solves the single-source shortest path problem, while the Bellman-Ford algorithm and Floyd-Warshall algorithm can address shortest paths between all pairs of nodes.
* Dijkstra's algorithm is suitable for graphs with non-negative edge weights, whereas the Bellman-Ford algorithm and Floyd-Warshall algorithm can handle negative-weight edges.
* The time complexity of Dijkstra's algorithm and the Bellman-Ford algorithm depends on the size of the graph, while the time complexity of the Floyd-Warshall algorithm is O(V^3), where V is the number of nodes. For dense graphs, Floyd-Warshall might become slower.
*
* /
/**
* 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.
@ -645,7 +673,6 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
}
}
if (getMinDist) {
distMap.forEach((d, v) => {
if (v !== srcVertex) {
@ -657,23 +684,42 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
});
}
if (genPaths) {
getPaths(minDest);
}
return {distMap, preMap, seen, paths, minDist, minPath};
}
/**
* Dijkstra algorithm time: O(logVE) space: O(V + E)
* /
/**
* Dijkstra algorithm time: O(logVE) space: O(V + E)
* 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.
*/
abstract getEndsOfEdge(edge: E): [V, V] | null;
/**
* BellmanFord time:O(VE) space:O(V)
* one to rest pairs
* 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
*/
/**
* Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle
* all pairs
* The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes.
*/
/**
* BellmanFord time:O(VE) space:O(V)
* one to rest pairs
* /
/**
* BellmanFord time:O(VE) space:O(V)
* one to rest pairs
* 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.
@ -778,6 +824,11 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
}
/**
* Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle
* all pairs
* /
/**
* Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle
* all pairs
* The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes.
@ -825,6 +876,14 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
}
/**
* Tarjan is an algorithm based on DFS,which is used to solve the connectivity problem of graphs.
* Tarjan can find cycles in directed or undirected graph
* Tarjan can find the articulation points and bridges(critical edges) of undirected graphs in linear time,
* Tarjan solve the bi-connected components of undirected graphs;
* Tarjan can find the SSC(strongly connected components), articulation points, and bridges of directed graphs.
* /
/**
* Tarjan is an algorithm based on DFS,which is used to solve the connectivity problem of graphs.
* Tarjan can find cycles in directed or undirected graph
* Tarjan can find the articulation points and bridges(critical edges) of undirected graphs in linear time,
@ -948,11 +1007,6 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
return {dfnMap, lowMap, bridges, articulationPoints, SCCs, cycles};
}
/**
* Dijkstra's algorithm only solves the single-source shortest path problem, while the Bellman-Ford algorithm and Floyd-Warshall algorithm can address shortest paths between all pairs of nodes.
* Dijkstra's algorithm is suitable for graphs with non-negative edge weights, whereas the Bellman-Ford algorithm and Floyd-Warshall algorithm can handle negative-weight edges.
* The time complexity of Dijkstra's algorithm and the Bellman-Ford algorithm depends on the size of the graph, while the time complexity of the Floyd-Warshall algorithm is O(V^3), where V is the number of nodes. For dense graphs, Floyd-Warshall might become slower.
*/
protected _addVertexOnly(newVertex: V): boolean {
if (this.hasVertex(newVertex)) {
@ -963,41 +1017,16 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
return true;
}
protected abstract _addEdgeOnly(edge: E): boolean;
/**
* BellmanFord time:O(VE) space:O(V)
* one to rest pairs
* 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
*/
protected _getVertex(vertexOrId: VertexId | V): V | null {
const vertexId = this._getVertexId(vertexOrId);
return this._vertices.get(vertexId) || null;
}
/**
* Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle
* all pairs
* The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes.
*/
protected _getVertexId(vertexOrId: V | VertexId): VertexId {
return vertexOrId instanceof AbstractVertex ? vertexOrId.id : vertexOrId;
}
/**--- start find cycles --- */
protected _setVertices(value: Map<VertexId, V>) {
this._vertices = value;
}
// unionFind() {}
/**--- end find cycles --- */
// Minimum Spanning Tree
}

View file

@ -13,18 +13,14 @@ import {IDirectedGraph} from '../interfaces';
export class DirectedVertex<T = number> extends AbstractVertex<T> {
/**
* The constructor function initializes a vertex with an optional value.
* @param {VertexId} id - The `id` parameter is the identifier for the vertex. It is of type `VertexId`, which is
* typically a unique identifier for each vertex in a graph.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It is used to specify the value
* associated with the vertex.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
* used to uniquely identify the vertex within a graph or data structure.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. 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?: T) {
super(id, val);
}
// createVertex(id: VertexId, val?: T): DirectedVertex<T> {
// return new DirectedVertex<T>(id, val);
// }
}
export class DirectedEdge<T = number> extends AbstractEdge<T> {
@ -34,11 +30,10 @@ export class DirectedEdge<T = number> extends AbstractEdge<T> {
* and value.
* @param {VertexId} 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 {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.
* If the weight is not provided, it will default to `undefined`.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It represents the value associated with
* @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 {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
* @param {T} [val] - The `val` parameter is an optional parameter of type `T`. It represents the value associated with
* the edge.
*/
constructor(src: VertexId, dest: VertexId, weight?: number, val?: T) {
@ -66,16 +61,13 @@ export class DirectedEdge<T = number> extends AbstractEdge<T> {
set dest(v: VertexId) {
this._dest = v;
}
// createEdge(src: VertexId, dest: VertexId, weight?: number, val?: T): DirectedEdge<T> {
// if (weight === undefined || weight === null) weight = 1;
// return new DirectedEdge(src, dest, weight, val);
// }
}
// Strongly connected, One direction connected, Weakly connected
export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E extends DirectedEdge<any> = DirectedEdge> extends AbstractGraph<V, E> implements IDirectedGraph<V, E> {
/**
* The constructor function initializes an instance of a class.
*/
constructor() {
super();
}
@ -95,8 +87,16 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* 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 val
*/
/**
* 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
* 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
* @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;
@ -105,22 +105,30 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
/**
* 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 src
* @param dest
* @param weight
* @param val
*/
/**
* 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 {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 {
return new DirectedEdge(src, dest, weight ?? 1, val) as E;
}
/**
* The function `getEdge` returns the directed edge between two vertices, given their source and destination.
* @param {V | null | VertexId} srcOrId - The source vertex or its ID. It can be either a
* DirectedVertex object or a VertexId.
* @param {V | null | VertexId} destOrId - The `destOrId` parameter is the destination vertex or its
* ID. It can be either a `DirectedVertex` object or a `VertexId` value.
* @returns a E object or null.
* 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
* 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 {
let edges: E[] = [];
@ -141,14 +149,10 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The `removeEdgeBetween` function removes an edge between two vertices in a directed graph and returns the removed
* edge, or null if the edge was not found.
* @param {V | VertexId} srcOrId - The `srcOrId` parameter represents either a `V`
* object or a `VertexId` value. It is used to specify the source vertex of the edge that you want to remove.
* @param {V | VertexId} destOrId - The `destOrId` parameter represents the destination vertex of the
* edge that you want to remove. It can be either a `V` object or a `VertexId` value.
* @returns The function `removeEdgeBetween` returns the removed edge (`E`) if it exists, or `null` if
* the edge does not exist.
* 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.
* @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 {
@ -172,12 +176,10 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The `removeEdge` function removes a directed edge from a graph and returns the removed edge, or null if the edge was
* not found.
* @param edge - The `edge` parameter is an object of type `E`, which represents a directed edge in a
* graph. It has two properties:
* @returns The function `removeEdge` returns a `E` object if an edge is successfully removed, or `null`
* if no edge is removed.
* The function removes an edge from a graph and returns the removed edge, or null if the edge was not found.
* @param {E} edge - The `edge` parameter is an object that represents an edge in a graph. It has two properties: `src`
* and `dest`, which represent the source and destination vertices of the edge, respectively.
* @returns The method `removeEdge` returns the removed edge (`E`) if it exists, or `null` if the edge does not exist.
*/
removeEdge(edge: E): E | null {
let removed: E | null = null;
@ -200,12 +202,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function removes all edges between two vertices and returns the removed edges.
* @param {VertexId | V} v1 - The parameter `v1` represents either a `VertexId` or a `V` object. It is used to identify
* the first vertex in the graph.
* @param {VertexId | V} v2 - The parameter `v2` represents either a `VertexId` or a `V`. It is used to identify the
* second vertex involved in the edges that need to be removed.
* @returns The function `removeEdgesBetween` returns an array of removed edges (`E[]`).
* 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
* 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
* 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[] {
const removed: E[] = [];
@ -222,10 +224,10 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function returns an array of incoming edges of a given vertex or vertex ID.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a `V`
* object or a `VertexId`.
* @returns The method `incomingEdgesOf` returns an array of `E` objects.
* 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`).
* @returns The method `incomingEdgesOf` returns an array of edges (`E[]`).
*/
incomingEdgesOf(vertexOrId: V | VertexId): E[] {
const target = this._getVertex(vertexOrId);
@ -236,10 +238,10 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function `outgoingEdgesOf` returns an array of outgoing directed edges from a given vertex or vertex ID.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a `V`
* object or a `VertexId`.
* @returns The method `outgoingEdgesOf` returns an array of `E` objects.
* 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`).
* @returns The method `outgoingEdgesOf` returns an array of edges (`E[]`).
*/
outgoingEdgesOf(vertexOrId: V | VertexId): E[] {
const target = this._getVertex(vertexOrId);
@ -250,20 +252,17 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function "degreeOf" returns the total degree of a vertex in a directed graph, 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`.
* @returns The sum of the out-degree and in-degree of the given vertex or vertex ID.
* 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`.
* @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);
}
/**
* The function "inDegreeOf" returns the number of incoming edges for a given vertex or vertex ID in a directed graph.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a
* `V`.
* 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`.
* @returns The number of incoming edges of the specified vertex or vertex ID.
*/
inDegreeOf(vertexOrId: VertexId | V): number {
@ -271,9 +270,8 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* 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`.
* 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`.
* @returns The number of outgoing edges from the specified vertex or vertex ID.
*/
outDegreeOf(vertexOrId: VertexId | V): number {
@ -281,39 +279,37 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function "edgesOf" returns an array of both outgoing and incoming directed edges of a given vertex or vertex ID.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a
* `V`.
* @returns an array of directed edges.
* 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`.
* @returns The function `edgesOf` returns an array of edges.
*/
edgesOf(vertexOrId: VertexId | V): E[] {
return [...this.outgoingEdgesOf(vertexOrId), ...this.incomingEdgesOf(vertexOrId)];
}
/**
* The function "getEdgeSrc" returns the source vertex of a directed edge, or null if the edge does not exist.
* @param e - A directed edge object of type E.
* @returns either a DirectedVertex object or null.
* The function "getEdgeSrc" returns the source vertex of an edge, or null if the edge does not exist.
* @param {E} e - The parameter "e" is of type E, which represents an edge in a graph.
* @returns either a vertex object (V) or null.
*/
getEdgeSrc(e: E): V | null {
return this._getVertex(e.src);
}
/**
* The function "getEdgeDest" returns the destination vertex of a directed edge.
* @param e - E - This is an object representing a directed edge in a graph. It contains information
* about the source vertex, destination vertex, and any associated data.
* @returns either a DirectedVertex object or null.
* The function "getEdgeDest" returns the destination vertex of an edge.
* @param {E} e - The parameter "e" is of type "E", which represents an edge in a graph.
* @returns either a vertex object of type V or null.
*/
getEdgeDest(e: E): V | null {
return this._getVertex(e.dest);
}
/**
* The function `getDestinations` returns an array of directed vertices that are the destinations of outgoing edges
* from a given vertex.
* @param {V | VertexId | null} vertex - The `vertex` parameter can be one of the following:
* @returns an array of DirectedVertex objects.
* 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`.
* @returns an array of vertices (V[]).
*/
getDestinations(vertex: V | VertexId | null): V[] {
if (vertex === null) {
@ -330,14 +326,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
return destinations;
}
/**
* 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
* @returns an array of vertices or vertex IDs in topological order, or null if there is a cycle in the graph.
* @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';
@ -378,8 +373,8 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The `edgeSet` function returns an array of all directed edges in the graph.
* @returns The `edgeSet()` method returns an array of `E` objects.
* The `edgeSet` function returns an array of all the edges in the graph.
* @returns The `edgeSet()` method returns an array of edges (`E[]`).
*/
edgeSet(): E[] {
let edges: E[] = [];
@ -390,10 +385,10 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
/**
* The function `getNeighbors` returns an array of neighboring vertices of a given vertex in a directed graph.
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a `V`
* object or a `VertexId`.
* @returns an array of DirectedVertex objects.
* 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`).
* @returns an array of vertices (V[]).
*/
getNeighbors(vertexOrId: V | VertexId): V[] {
const neighbors: V[] = [];
@ -411,14 +406,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
return neighbors;
}
/**--- start find cycles --- */
/**
* The function "getEndsOfEdge" returns the source and destination vertices of a directed edge if it exists in the
* graph, otherwise it returns null.
* @param edge - A directed edge object with a generic type E.
* @returns an array containing the starting and ending vertices of the given directed edge, or null if the edge does
* not exist in the graph.
* The function "getEndsOfEdge" returns the source and destination vertices of an edge if it exists in the graph,
* otherwise it returns null.
* @param {E} edge - The parameter `edge` is of type `E`, which represents an edge in a graph.
* @returns The function `getEndsOfEdge` returns an array containing two vertices `[V, V]` if the edge exists in the
* graph. If the edge does not exist, it returns `null`.
*/
getEndsOfEdge(edge: E): [V, V] | null {
if (!this.hasEdge(edge.src, edge.dest)) {
@ -433,14 +426,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
}
}
/**--- end find cycles --- */
/**
* The `_addEdgeOnly` function adds a directed edge to a graph if the source and destination vertices exist.
* @param edge - The parameter `edge` is of type `E`, which represents a directed edge in a graph. It
* contains two properties:
* @returns The method `_addEdgeOnly` returns a boolean value. It returns `true` if the edge was successfully added to the
* graph, and `false` if either the source or destination vertex of the edge is not present in the graph.
* The function `_addEdgeOnly` adds an edge to a graph if the source and destination vertices exist.
* @param {E} edge - The parameter `edge` is of type `E`, which represents an edge in a graph. It is the edge that
* needs to be added to the graph.
* @returns a boolean value. It returns true if the edge was successfully added to the graph, and false if either the
* source or destination vertex does not exist in the graph.
*/
protected _addEdgeOnly(edge: E): boolean {
if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) {

View file

@ -13,8 +13,8 @@ import {IUNDirectedGraph} from '../interfaces';
export class UndirectedVertex<T = number> extends AbstractVertex<T> {
/**
* The constructor function initializes a vertex with an optional value.
* @param {VertexId} id - The `id` parameter is the identifier for the vertex. It is of type `VertexId`, which is
* typically a unique identifier for each vertex in a graph.
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
* used to uniquely identify the vertex within a graph or network.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It is used to initialize the value of the
* vertex. If no value is provided, the vertex will be initialized with a default value.
*/
@ -25,14 +25,14 @@ export class UndirectedVertex<T = number> extends AbstractVertex<T> {
export class UndirectedEdge<T = number> extends AbstractEdge<T> {
/**
* The constructor function initializes an instance of a class with two vertex IDs, an optional weight, and an optional
* The constructor function creates an instance of a class with two vertex IDs, an optional weight, and an optional
* value.
* @param {VertexId} v1 - The parameter `v1` is of type `VertexId` and represents the first vertex in the edge.
* @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
* graph edge.
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It represents the value associated with
* the edge.
* @param {T} [val] - The "val" parameter is an optional parameter of type T. It is used to store a value associated
* with the edge.
*/
constructor(v1: VertexId, v2: VertexId, weight?: number, val?: T) {
super(weight, val);
@ -52,6 +52,9 @@ export class UndirectedEdge<T = number> extends AbstractEdge<T> {
export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex, E extends UndirectedEdge<any> = UndirectedEdge> extends AbstractGraph<V, E> implements IUNDirectedGraph<V, E> {
/**
* The constructor initializes a new Map object to store edges.
*/
constructor() {
super();
this._edges = new Map<V, E[]>();
@ -64,40 +67,39 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* 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 val
* 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
* 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
* 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;
}
/**
* The function createEdge 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. It is of type `VertexId`, which
* could be a unique identifier or label for the vertex.
* @param {VertexId} v2 - The parameter `v2` represents the second vertex of the edge. It is of type `VertexId`, which
* is typically 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. If no
* weight is provided, the default value is 1.
* 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 {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 an instance of the UndirectedEdge class, casted as type E.
* @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 {
return new UndirectedEdge(v1, v2, weight ?? 1, val) as E;
}
/**
* The function `getEdge` returns the first undirected edge that connects two given vertices, or null if no such edge
* exists.
* @param {V | null | VertexId} v1 - The parameter `v1` represents either an `V`
* object, `null`, or a `VertexId`. It is used to specify one of the vertices of the edge.
* @param {V | null | VertexId} v2 - The parameter `v2` represents either an `UndirectedVertex`
* object or a `VertexId` (identifier) of an undirected vertex.
* @returns an instance of `E` or `null`.
* 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).
* @returns an edge (E) or null.
*/
getEdge(v1: V | null | VertexId, v2: V | null | VertexId): E | null {
let edges: E[] | undefined = [];
@ -115,15 +117,11 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function removes an edge between two vertices in an undirected graph.
* @param {V | VertexId} v1 - The parameter `v1` represents either an `V` object or
* a `VertexId`. It is used to specify one of the vertices of the edge that needs to be removed.
* @param {V | VertexId} v2 - The parameter `v2` represents either an instance of the
* `UndirectedVertex` class or a `VertexId`. It is used to identify the second vertex of the edge that needs to be
* removed.
* @returns The function `removeEdgeBetween` returns an `E` object if an edge is successfully removed
* between the two vertices `v1` and `v2`. If either `v1` or `v2` is not found in the graph, or if there is no edge
* between them, the function returns `null`.
* 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.
* @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 {
@ -147,20 +145,20 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The removeEdge function removes an edge between two vertices in an undirected graph.
* @param edge - An object representing an undirected edge. It has a property called "vertices" which is an array
* containing the two vertices connected by the edge.
* @returns The method is returning an UndirectedEdge object or null.
* The removeEdge function removes an edge between two vertices in a graph.
* @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph.
* @returns The method is returning either the removed edge (of type E) or null if the edge was not found.
*/
removeEdge(edge: E): E | null {
return this.removeEdgeBetween(edge.vertices[0], edge.vertices[1]);
}
/**
* The function "degreeOf" returns the degree of a given vertex in an undirected graph.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or an
* `V`.
* @returns the degree of the vertex.
* 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`.
* @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);
@ -172,10 +170,10 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function "edgesOf" returns an array of undirected edges connected to a given vertex or vertex ID.
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or an
* `V`.
* @returns an array of UndirectedEdge objects.
* 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
* 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);
@ -187,8 +185,8 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function "edgeSet" returns an array of unique undirected edges from a set of edges.
* @returns The method `edgeSet()` returns an array of `E` objects.
* The function "edgeSet" returns an array of unique edges from a set of edges.
* @returns The method `edgeSet()` returns an array of type `E[]`.
*/
edgeSet(): E[] {
const edgeSet: Set<E> = new Set();
@ -201,10 +199,10 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function `getNeighbors` returns an array of neighboring vertices of a given vertex in an undirected graph.
* @param {V | VertexId} vertexOrId - The `vertexOrId` parameter can be either an
* `V` object or a `VertexId`. It represents the vertex for which we want to find the neighbors.
* @returns an array of UndirectedVertex objects.
* 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`).
* @returns an array of vertices (V[]).
*/
getNeighbors(vertexOrId: V | VertexId): V[] {
const neighbors: V[] = [];
@ -222,12 +220,11 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function "getEndsOfEdge" returns the two vertices that form the ends of a given undirected edge, or null if the
* edge does not exist in the graph.
* @param edge - An object representing an undirected edge in a graph. It has a property called "vertices" which is an
* array containing two vertices that the edge connects.
* @returns The function `getEndsOfEdge` returns an array containing the two ends of the given `edge` if the edge
* exists in the graph. If the edge does not exist, it returns `null`.
* The function "getEndsOfEdge" returns the vertices at the ends of an edge if the edge exists in the graph, otherwise
* it returns null.
* @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph.
* @returns The function `getEndsOfEdge` returns an array containing two vertices `[V, V]` if the edge exists in the
* graph. If the edge does not exist, it returns `null`.
*/
getEndsOfEdge(edge: E): [V, V] | null {
if (!this.hasEdge(edge.vertices[0], edge.vertices[1])) {
@ -243,9 +240,8 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
}
/**
* The function adds an undirected edge to a graph by updating the adjacency list.
* @param edge - An object representing an undirected edge in a graph. It has a property called "vertices" which is an
* array of two vertices connected by the edge.
* The function adds an edge to the graph by updating the adjacency list with the vertices of the edge.
* @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph.
* @returns a boolean value.
*/
protected _addEdgeOnly(edge: E): boolean {
@ -264,6 +260,10 @@ export class UndirectedGraph<V extends UndirectedVertex<any> = UndirectedVertex,
return true;
}
/**
* The function sets the edges of a graph.
* @param v - A map where the keys are of type V and the values are arrays of type E.
*/
protected _setEdges(v: Map<V, E[]>) {
this._edges = v;
}

View file

@ -11,7 +11,7 @@ import {
} from '../types';
import {AbstractBinaryTreeNode} from '../binary-tree';
export interface IAbstractBinaryTreeNode<T, FAMILY extends IAbstractBinaryTreeNode<T, FAMILY>> {
export interface IAbstractBinaryTreeNode<T, NEIGHBOR extends IAbstractBinaryTreeNode<T, NEIGHBOR>> {
get id(): BinaryTreeNodeId
@ -21,17 +21,17 @@ export interface IAbstractBinaryTreeNode<T, FAMILY extends IAbstractBinaryTreeNo
set val(v: T | undefined)
get left(): FAMILY | null | undefined
get left(): NEIGHBOR | null | undefined
set left(v: FAMILY | null | undefined)
set left(v: NEIGHBOR | null | undefined)
get right(): FAMILY | null | undefined
get right(): NEIGHBOR | null | undefined
set right(v: FAMILY | null | undefined)
set right(v: NEIGHBOR | null | undefined)
get parent(): FAMILY | null | undefined
get parent(): NEIGHBOR | null | undefined
set parent(v: FAMILY | null | undefined)
set parent(v: NEIGHBOR | null | undefined)
get familyPosition(): FamilyPosition

View file

@ -2,7 +2,7 @@ import {AVLTreeNode} from '../binary-tree';
import {IBST, IBSTNode} from './bst';
import {BinaryTreeDeletedResult, BinaryTreeNodeId} from '../types';
export interface IAVLTreeNode<T, FAMILY extends IAVLTreeNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
export interface IAVLTreeNode<T, NEIGHBOR extends IAVLTreeNode<T, NEIGHBOR>> extends IBSTNode<T, NEIGHBOR> {
}

View file

@ -1,7 +1,7 @@
import {BinaryTreeNode} from '../binary-tree';
import {IAbstractBinaryTree, IAbstractBinaryTreeNode} from './abstract-binary-tree';
export interface IBinaryTreeNode<T, FAMILY extends IBinaryTreeNode<T, FAMILY>> extends IAbstractBinaryTreeNode<T, FAMILY> {
export interface IBinaryTreeNode<T, NEIGHBOR extends IBinaryTreeNode<T, NEIGHBOR>> extends IAbstractBinaryTreeNode<T, NEIGHBOR> {
}
export interface IBinaryTree<N extends BinaryTreeNode<N['val'], N>> extends IAbstractBinaryTree<N> {

View file

@ -2,7 +2,7 @@ import {BSTNode} from '../binary-tree';
import {IBinaryTree, IBinaryTreeNode} from './binary-tree';
import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types';
export interface IBSTNode<T, FAMILY extends IBSTNode<T, FAMILY>> extends IBinaryTreeNode<T, FAMILY> {
export interface IBSTNode<T, NEIGHBOR extends IBSTNode<T, NEIGHBOR>> extends IBinaryTreeNode<T, NEIGHBOR> {
}
export interface IBST<N extends BSTNode<N['val'], N>> extends IBinaryTree<N> {

View file

@ -2,7 +2,7 @@ import {RBTreeNode} from '../binary-tree';
import {IBST, IBSTNode} from './bst';
import {BinaryTreeNodeId} from '../types';
export interface IRBTreeNode<T, FAMILY extends IRBTreeNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
export interface IRBTreeNode<T, NEIGHBOR extends IRBTreeNode<T, NEIGHBOR>> extends IBSTNode<T, NEIGHBOR> {
}
export interface IRBTree<N extends RBTreeNode<N['val'], N>> extends IBST<N> {

View file

@ -2,7 +2,7 @@ import {TreeMultisetNode} from '../binary-tree';
import {IBSTNode} from './bst';
import {IAVLTree} from './avl-tree';
export interface ITreeMultisetNode<T, FAMILY extends ITreeMultisetNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
export interface ITreeMultisetNode<T, NEIGHBOR extends ITreeMultisetNode<T, NEIGHBOR>> extends IBSTNode<T, NEIGHBOR> {
}

View file

@ -24,15 +24,17 @@ export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
export type DFSOrderPattern = 'in' | 'pre' | 'post';
export type BinaryTreeNodeId = number;
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined, needBalanced: N | null };
export type AVLTreeDeletedResult<N> = { deleted: N | null | undefined };
export type AbstractBinaryTreeNodeProperty<N extends AbstractBinaryTreeNode<N['val'], N>> =
N['val']
| N
| number
| BinaryTreeNodeId;
export type AbstractBinaryTreeNodeProperties<N extends AbstractBinaryTreeNode<N['val'], N>> = AbstractBinaryTreeNodeProperty<N>[];
export type AbstractBinaryTreeNodeNested<T> = AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type AbstractBinaryTreeOptions = {
loopType?: LoopType,
autoIncrementId?: boolean,

View file

@ -4,7 +4,6 @@ describe('TreeMultiset operations test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const treeMultiset = new TreeMultiset();
expect(treeMultiset instanceof TreeMultiset);
treeMultiset.add(11);
treeMultiset.add(3);
@ -13,36 +12,36 @@ describe('TreeMultiset operations test', () => {
if (treeMultiset.root) expect(treeMultiset.root.id == 11);
expect(treeMultiset.size === 16);
expect(treeMultiset.count === 18);
expect(treeMultiset.size).toBe(16);
expect(treeMultiset.count).toBe(18);
expect(treeMultiset.BFS('id'))
expect(treeMultiset.has(6));
expect(treeMultiset.getHeight(6) === 3);
expect(treeMultiset.getDepth(6) === 1);
expect(treeMultiset.getHeight(6)).toBe(3);
expect(treeMultiset.getDepth(6)).toBe(1);
const nodeId10 = treeMultiset.get(10);
expect(nodeId10?.id === 10);
expect(nodeId10?.id).toBe(10);
const nodeVal9 = treeMultiset.get(9, 'val');
expect(nodeVal9?.id === 9);
expect(nodeVal9?.id).toBe(9);
const nodesByCount1 = treeMultiset.getNodesByCount(1);
expect(nodesByCount1.length === 14);
expect(nodesByCount1.length).toBe(14);
const nodesByCount2 = treeMultiset.getNodesByCount(2);
expect(nodesByCount2.length === 2);
expect(nodesByCount2.length).toBe(2);
const leftMost = treeMultiset.getLeftMost();
expect(leftMost?.id === 1);
expect(leftMost?.id).toBe(1);
const node15 = treeMultiset.get(15);
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
expect(minNodeBySpecificNode?.id === 12);
expect(minNodeBySpecificNode?.id).toBe(12);
const subTreeSum = node15 && treeMultiset.subTreeSum(15);
expect(subTreeSum === 70);
expect(subTreeSum).toBe(70);
const lesserSum = treeMultiset.lesserSum(10);
expect(lesserSum === 45);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultisetNode);
@ -58,149 +57,149 @@ describe('TreeMultiset operations test', () => {
}
const dfsInorderNodes = treeMultiset.DFS('in', 'node');
expect(dfsInorderNodes[0].id === 1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id === 16);
expect(treeMultiset.isPerfectlyBalanced() === false);
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
expect(treeMultiset.isPerfectlyBalanced()).toBe(false);
treeMultiset.perfectlyBalance();
expect(treeMultiset.isPerfectlyBalanced() === true);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.isPerfectlyBalanced()).toBe(true);
expect(treeMultiset.isAVLBalanced()).toBe(true);
const bfsNodesAfterBalanced = treeMultiset.BFS('node');
expect(bfsNodesAfterBalanced[0].id === 8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id === 16);
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).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 === 11);
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight(15) === 1);
expect(treeMultiset.getHeight(15)).toBe(1);
const removed1 = treeMultiset.remove(1, true);
expect(removed1 instanceof Array);
expect(removed1[0]);
expect(removed1[0].deleted);
if (removed1[0].deleted) expect(removed1[0].deleted.id === 1);
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight() === 4);
expect(treeMultiset.getHeight()).toBe(4);
const removed4 = treeMultiset.remove(4, true);
expect(removed4 instanceof Array);
expect(removed4[0]);
expect(removed4[0].deleted);
if (removed4[0].deleted) expect(removed4[0].deleted.id === 4);
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 4);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(4);
const removed10 = treeMultiset.remove(10, true);
expect(removed10 instanceof Array);
expect(removed10[0]);
expect(removed10[0].deleted);
if (removed10[0].deleted) expect(removed10[0].deleted.id === 10);
expect(treeMultiset.isAVLBalanced() === true);
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight() === 3);
expect(treeMultiset.getHeight()).toBe(3);
const removed15 = treeMultiset.remove(15, true);
expect(removed15 instanceof Array);
expect(removed15[0]);
expect(removed15[0].deleted);
if (removed15[0].deleted) expect(removed15[0].deleted.id === 15);
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 3);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed5 = treeMultiset.remove(5, true);
expect(removed5 instanceof Array);
expect(removed5[0]);
expect(removed5[0].deleted);
if (removed5[0].deleted) expect(removed5[0].deleted.id === 5);
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 3);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed13 = treeMultiset.remove(13, true);
expect(removed13 instanceof Array);
expect(removed13[0]);
expect(removed13[0].deleted);
if (removed13[0].deleted) expect(removed13[0].deleted.id === 13);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 3);
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed3 = treeMultiset.remove(3, true);
expect(removed3 instanceof Array);
expect(removed3[0]);
expect(removed3[0].deleted);
if (removed3[0].deleted) expect(removed3[0].deleted.id === 3);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 3);
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed8 = treeMultiset.remove(8, true);
expect(removed8 instanceof Array);
expect(removed8[0]);
expect(removed8[0].deleted);
if (removed8[0].deleted) expect(removed8[0].deleted.id === 8);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 3);
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed6 = treeMultiset.remove(6, true);
expect(removed6 instanceof Array);
expect(removed6[0]);
expect(removed6[0].deleted);
if (removed6[0].deleted) expect(removed6[0].deleted.id === 6);
expect(treeMultiset.remove(6, true).length === 0);
expect(treeMultiset.isAVLBalanced() === true);
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
expect(treeMultiset.remove(6, true).length).toBe(0);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight() === 2);
expect(treeMultiset.getHeight()).toBe(2);
const removed7 = treeMultiset.remove(7, true);
expect(removed7 instanceof Array);
expect(removed7[0]);
expect(removed7[0].deleted);
if (removed7[0].deleted) expect(removed7[0].deleted.id === 7);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 2);
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
const removed9 = treeMultiset.remove(9, true);
expect(removed9 instanceof Array);
expect(removed9[0]);
expect(removed9[0].deleted);
if (removed9[0].deleted) expect(removed9[0].deleted.id === 9);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 2);
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
const removed14 = treeMultiset.remove(14, true);
expect(removed14 instanceof Array);
expect(removed14[0]);
expect(removed14[0].deleted);
if (removed14[0].deleted) expect(removed14[0].deleted.id === 14);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.getHeight() === 1);
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(1);
expect(treeMultiset.isAVLBalanced() === true);
expect(treeMultiset.isAVLBalanced()).toBe(true);
const bfsIDs = treeMultiset.BFS();
expect(bfsIDs[0] === 12);
expect(bfsIDs[1] === 2);
expect(bfsIDs[2] === 16);
expect(bfsIDs[0]).toBe(12);
expect(bfsIDs[1]).toBe(2);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = treeMultiset.BFS('node');
expect(bfsNodes[0].id === 12);
expect(bfsNodes[1].id === 2);
expect(bfsNodes[2].id === 16);
expect(bfsNodes[0].id).toBe(12);
expect(bfsNodes[1].id).toBe(2);
expect(bfsNodes[2].id).toBe(16);
expect(treeMultiset.count === 3);
expect(treeMultiset.count).toBe(3);
});
it('should perform various operations on a Binary Search Tree with object values', () => {