diff --git a/src/data-structures/binary-tree/abstract-binary-tree.ts b/src/data-structures/binary-tree/abstract-binary-tree.ts index fffa6e3..03dc5a8 100644 --- a/src/data-structures/binary-tree/abstract-binary-tree.ts +++ b/src/data-structures/binary-tree/abstract-binary-tree.ts @@ -20,16 +20,15 @@ import type { import {AbstractBinaryTreeOptions, FamilyPosition, LoopType} from '../types'; import {IAbstractBinaryTree, IAbstractBinaryTreeNode} from '../interfaces'; -export abstract class AbstractBinaryTreeNode = AbstractBinaryTreeNodeNested> implements IAbstractBinaryTreeNode { +export abstract class AbstractBinaryTreeNode = AbstractBinaryTreeNodeNested> implements IAbstractBinaryTreeNode { + /** - * 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 { const queue: Array = [root]; while (queue.length > 0) { @@ -311,13 +314,13 @@ export abstract class AbstractBinaryTree} 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 | null | undefined)[] { // TODO not sure addMany not be run multi times @@ -376,7 +379,6 @@ export abstract class AbstractBinaryTree} 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): boolean { this.clear(); @@ -427,10 +429,11 @@ export abstract class AbstractBinaryTree` objects. */ remove(nodeOrId: N | BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult[] { @@ -443,7 +446,6 @@ export abstract class AbstractBinaryTree`. + * 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 { nodeOrPropertyName = nodeOrPropertyName ?? 'id'; @@ -993,16 +986,15 @@ export abstract class AbstractBinaryTree`. + * 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 { pattern = pattern ?? 'in'; @@ -1032,6 +1024,9 @@ export abstract class AbstractBinaryTree. */ DFSIterative(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties { pattern = pattern || 'in'; @@ -1225,19 +1224,22 @@ export abstract class AbstractBinaryTree`. + * 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 objects. */ morris(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties { if (this.root === null) return []; @@ -1325,42 +1327,86 @@ export abstract class AbstractBinaryTree) { 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`. + * can accept either a `NodeOrPropertyName` type or be undefined. + * @returns The method `_getResultByPropertyName` returns an instance of `AbstractBinaryTreeNodeProperties`. */ protected _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties { nodeOrPropertyName = nodeOrPropertyName ?? 'id'; diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 862903e..8a436e0 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -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 = AVLTreeNodeNested> extends BSTNode implements IAVLTreeNode { +export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode implements IAVLTreeNode { } export class AVLTree = AVLTreeNode> extends BST implements IAVLTree { + /** + * 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(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); diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 6b780e2..604b564 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -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 = BinaryTreeNodeNested> extends AbstractBinaryTreeNode implements IBinaryTreeNode { +export class BinaryTreeNode = BinaryTreeNodeNested> extends AbstractBinaryTreeNode implements IBinaryTreeNode { } export class BinaryTree = BinaryTreeNode> extends AbstractBinaryTree implements IBinaryTree { /** - * 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(id, val) as N; } - } \ No newline at end of file diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 684e4f1..ec9ebd7 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -5,18 +5,19 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @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 = BSTNodeNested> extends BinaryTreeNode implements IBSTNode { +export class BSTNode = BSTNodeNested> extends BinaryTreeNode implements IBSTNode { + } export class BST = BSTNode> extends BinaryTree implements IBST { /** - * 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 = BSTNode> extends BinaryTree } /** - * 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(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 = BSTNode> extends BinaryTree } /** - * 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 = BSTNode> extends BinaryTree /** * 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 = BSTNode> extends BinaryTree } /** - * 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 = BSTNode> extends BinaryTree // --- 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 = BSTNode> extends BinaryTree } /** - * 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 = BSTNode> extends BinaryTree /** - * 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 = BSTNode> extends BinaryTree } /** - * 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; diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 960dc95..fcfb570 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -3,7 +3,7 @@ import {IRBTree, IRBTreeNode} from '../interfaces/rb-tree'; import {BST, BSTNode} from './bst'; -export class RBTreeNode = RBTreeNodeNested> extends BSTNode implements IRBTreeNode { +export class RBTreeNode = RBTreeNodeNested> extends BSTNode implements IRBTreeNode { constructor(id: BinaryTreeNodeId, color: RBColor, val?: T) { super(id, val); this._color = color; diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 43d2735..e9e9c35 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -11,7 +11,18 @@ import {ITreeMultiset, ITreeMultisetNode} from '../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; import {ObjectWithNumberId} from '../../utils'; -export class TreeMultisetNode = TreeMultisetNodeNested> extends AVLTreeNode implements ITreeMultisetNode { +export class TreeMultisetNode = TreeMultisetNodeNested> extends AVLTreeNode implements ITreeMultisetNode { + + /** + * 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 = TreeMultisetNode> extends AVLTree implements ITreeMultiset { + + /** + * 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 = 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 = 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 = 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 = [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 = 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 = 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 = 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 = TreeMultiset let sum = 0; - if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N): void => { sum += cur.count; @@ -474,6 +459,16 @@ export class TreeMultiset = 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 = 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 = 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 = 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 = 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; } -} + +} \ No newline at end of file diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index fed9e8d..313ea51 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -12,6 +12,13 @@ import {IAbstractGraph} from '../interfaces'; export abstract class AbstractVertex { + /** + * 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 { 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; } export abstract class AbstractEdge { + /** + * 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 { 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, E extends AbstractEdge> implements IAbstractGraph { private _vertices: Map = new Map(); @@ -122,23 +129,41 @@ export abstract class AbstractGraph, 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, 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, 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, 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, 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, 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, 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, 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, E extends Abs } } - if (getMinDist) { distMap.forEach((d, v) => { if (v !== srcVertex) { @@ -657,23 +684,42 @@ export abstract class AbstractGraph, 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, 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, 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, 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, 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) { this._vertices = value; } - - - // unionFind() {} - - /**--- end find cycles --- */ - - - // Minimum Spanning Tree } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 2a7255f..0fdae40 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -13,18 +13,14 @@ import {IDirectedGraph} from '../interfaces'; export class DirectedVertex extends AbstractVertex { /** * 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 { - // return new DirectedVertex(id, val); - // } } export class DirectedEdge extends AbstractEdge { @@ -34,11 +30,10 @@ export class DirectedEdge extends AbstractEdge { * 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 extends AbstractEdge { set dest(v: VertexId) { this._dest = v; } - - // createEdge(src: VertexId, dest: VertexId, weight?: number, val?: T): DirectedEdge { - // if (weight === undefined || weight === null) weight = 1; - // return new DirectedEdge(src, dest, weight, val); - // } } -// Strongly connected, One direction connected, Weakly connected export class DirectedGraph = DirectedVertex, E extends DirectedEdge = DirectedEdge> extends AbstractGraph implements IDirectedGraph { + /** + * The constructor function initializes an instance of a class. + */ constructor() { super(); } @@ -95,8 +87,16 @@ export class DirectedGraph = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 | null { propertyName = propertyName ?? 'id'; @@ -378,8 +373,8 @@ export class DirectedGraph = 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 = 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 = 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 = 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))) { diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 0d7e987..bd05ada 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -13,8 +13,8 @@ import {IUNDirectedGraph} from '../interfaces'; export class UndirectedVertex extends AbstractVertex { /** * 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 extends AbstractVertex { export class UndirectedEdge extends AbstractEdge { /** - * 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 extends AbstractEdge { export class UndirectedGraph = UndirectedVertex, E extends UndirectedEdge = UndirectedEdge> extends AbstractGraph implements IUNDirectedGraph { + /** + * The constructor initializes a new Map object to store edges. + */ constructor() { super(); this._edges = new Map(); @@ -64,40 +67,39 @@ export class UndirectedGraph = 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 = 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 = 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 = 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 = 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 = new Set(); @@ -201,10 +199,10 @@ export class UndirectedGraph = 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 = 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 = 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 = 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) { this._edges = v; } diff --git a/src/data-structures/interfaces/abstract-binary-tree.ts b/src/data-structures/interfaces/abstract-binary-tree.ts index 6ec2d45..04bc077 100644 --- a/src/data-structures/interfaces/abstract-binary-tree.ts +++ b/src/data-structures/interfaces/abstract-binary-tree.ts @@ -11,7 +11,7 @@ import { } from '../types'; import {AbstractBinaryTreeNode} from '../binary-tree'; -export interface IAbstractBinaryTreeNode> { +export interface IAbstractBinaryTreeNode> { get id(): BinaryTreeNodeId @@ -21,17 +21,17 @@ export interface IAbstractBinaryTreeNode> extends IBSTNode { +export interface IAVLTreeNode> extends IBSTNode { } diff --git a/src/data-structures/interfaces/binary-tree.ts b/src/data-structures/interfaces/binary-tree.ts index 0ca7ff2..d78f3a9 100644 --- a/src/data-structures/interfaces/binary-tree.ts +++ b/src/data-structures/interfaces/binary-tree.ts @@ -1,7 +1,7 @@ import {BinaryTreeNode} from '../binary-tree'; import {IAbstractBinaryTree, IAbstractBinaryTreeNode} from './abstract-binary-tree'; -export interface IBinaryTreeNode> extends IAbstractBinaryTreeNode { +export interface IBinaryTreeNode> extends IAbstractBinaryTreeNode { } export interface IBinaryTree> extends IAbstractBinaryTree { diff --git a/src/data-structures/interfaces/bst.ts b/src/data-structures/interfaces/bst.ts index fe61950..43c8c0a 100644 --- a/src/data-structures/interfaces/bst.ts +++ b/src/data-structures/interfaces/bst.ts @@ -2,7 +2,7 @@ import {BSTNode} from '../binary-tree'; import {IBinaryTree, IBinaryTreeNode} from './binary-tree'; import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types'; -export interface IBSTNode> extends IBinaryTreeNode { +export interface IBSTNode> extends IBinaryTreeNode { } export interface IBST> extends IBinaryTree { diff --git a/src/data-structures/interfaces/rb-tree.ts b/src/data-structures/interfaces/rb-tree.ts index afb7559..a2dc2a3 100644 --- a/src/data-structures/interfaces/rb-tree.ts +++ b/src/data-structures/interfaces/rb-tree.ts @@ -2,7 +2,7 @@ import {RBTreeNode} from '../binary-tree'; import {IBST, IBSTNode} from './bst'; import {BinaryTreeNodeId} from '../types'; -export interface IRBTreeNode> extends IBSTNode { +export interface IRBTreeNode> extends IBSTNode { } export interface IRBTree> extends IBST { diff --git a/src/data-structures/interfaces/tree-multiset.ts b/src/data-structures/interfaces/tree-multiset.ts index 32fe4dd..f9c83e1 100644 --- a/src/data-structures/interfaces/tree-multiset.ts +++ b/src/data-structures/interfaces/tree-multiset.ts @@ -2,7 +2,7 @@ import {TreeMultisetNode} from '../binary-tree'; import {IBSTNode} from './bst'; import {IAVLTree} from './avl-tree'; -export interface ITreeMultisetNode> extends IBSTNode { +export interface ITreeMultisetNode> extends IBSTNode { } diff --git a/src/data-structures/types/abstract-binary-tree.ts b/src/data-structures/types/abstract-binary-tree.ts index 54ab2e6..c5df456 100644 --- a/src/data-structures/types/abstract-binary-tree.ts +++ b/src/data-structures/types/abstract-binary-tree.ts @@ -24,15 +24,17 @@ export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; export type DFSOrderPattern = 'in' | 'pre' | 'post'; export type BinaryTreeNodeId = number; export type BinaryTreeDeletedResult = { deleted: N | null | undefined, needBalanced: N | null }; -export type AVLTreeDeletedResult = { deleted: N | null | undefined }; export type AbstractBinaryTreeNodeProperty> = N['val'] | N | number | BinaryTreeNodeId; + export type AbstractBinaryTreeNodeProperties> = AbstractBinaryTreeNodeProperty[]; + export type AbstractBinaryTreeNodeNested = AbstractBinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + export type AbstractBinaryTreeOptions = { loopType?: LoopType, autoIncrementId?: boolean, diff --git a/tests/unit/data-structures/binary-tree/tree-multiset.test.ts b/tests/unit/data-structures/binary-tree/tree-multiset.test.ts index 3263d9f..6aae1a4 100644 --- a/tests/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/tests/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -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', () => {