diff --git a/src/data-structures/binary-tree/abstract-binary-tree.ts b/src/data-structures/binary-tree/abstract-binary-tree.ts index 35e0899..d3a7977 100644 --- a/src/data-structures/binary-tree/abstract-binary-tree.ts +++ b/src/data-structures/binary-tree/abstract-binary-tree.ts @@ -31,7 +31,7 @@ export abstract class AbstractBinaryTreeNode { @@ -320,7 +320,7 @@ export abstract class AbstractBinaryTree = new Map(); if (this.isMergeDuplicatedVal) { - for (const nodeOrVal of data) map.set(nodeOrVal, (map.get(nodeOrVal) ?? 0) + 1); + for (const nodeOrId of data) map.set(nodeOrId, (map.get(nodeOrId) ?? 0) + 1); } - for (const nodeOrVal of data) { + for (const nodeOrId of data) { - if (nodeOrVal instanceof AbstractBinaryTreeNode) { - inserted.push(this.add(nodeOrVal.val, nodeOrVal.id, nodeOrVal.count)); + if (nodeOrId instanceof AbstractBinaryTreeNode) { + inserted.push(this.add(nodeOrId.id, nodeOrId.val, nodeOrId.count)); continue; } - if (nodeOrVal === null) { - inserted.push(this.add(null, NaN, 0)); + if (nodeOrId === null) { + inserted.push(this.add(NaN, null, 0)); continue; } // TODO will this cause an issue? - const count = this.isMergeDuplicatedVal ? map.get(nodeOrVal) : 1; + const count = this.isMergeDuplicatedVal ? map.get(nodeOrId) : 1; let newId: BinaryTreeNodeId; - if (typeof nodeOrVal === 'number') { - newId = this.autoIncrementId ? this.maxId + 1 : nodeOrVal; - } else if (nodeOrVal instanceof Object) { + if (typeof nodeOrId === 'number') { + newId = this.autoIncrementId ? this.maxId + 1 : nodeOrId; + } else if (nodeOrId instanceof Object) { if (this.autoIncrementId) { newId = this.maxId + 1; } else { - if (Object.keys(nodeOrVal).includes('id')) { - newId = (nodeOrVal as ObjectWithNumberId).id; + if (Object.keys(nodeOrId).includes('id')) { + newId = (nodeOrId as ObjectWithNumberId).id; } else { - console.warn(nodeOrVal, 'Object value must has an id property when the autoIncrementId is false'); + console.warn(nodeOrId, 'Object value must has an id property when the autoIncrementId is false'); continue; } } } else { - console.warn(nodeOrVal, ` is not added`); + console.warn(nodeOrId, ` is not added`); continue; } if (this.isMergeDuplicatedVal) { - if (map.has(nodeOrVal)) { - inserted.push(this.add(nodeOrVal, newId, count)); - map.delete(nodeOrVal); + if (map.has(nodeOrId)) { + inserted.push(this.add(newId, nodeOrId, count)); + map.delete(nodeOrId); } } else { - inserted.push(this.add(nodeOrVal, newId, 1)); + inserted.push(this.add(newId, nodeOrId, 1)); } this._setMaxId(newId); diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 7ce3dec..2647f7f 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -10,8 +10,8 @@ import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryT import {IAVLTree, IAVLTreeNode} from '../interfaces'; export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode implements IAVLTreeNode { - override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY { - return new AVLTreeNode(val, id, count) as FAMILY; + override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY { + return new AVLTreeNode(id, val, count) as FAMILY; } } @@ -20,8 +20,8 @@ export class AVLTree = AVLTreeNode> extends B super(options); } - override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N { - return new AVLTreeNode(val, id, count) as N; + override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N { + return new AVLTreeNode(id, val, count) as N; } /** @@ -36,8 +36,8 @@ export class AVLTree = AVLTreeNode> extends B * to `1`, indicating that the value should be inserted once. * @returns The method is returning either an N object or null. */ - override add(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null { - const inserted = super.add(val, id, count); + override add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null { + const inserted = super.add(id, val, count); if (inserted) this.balancePath(inserted); return inserted; } diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index ba4b271..a006695 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -23,8 +23,8 @@ export class BinaryTreeNode = * appears in the binary tree node. * @returns a new instance of the BinaryTreeNode class, casted as the FAMILY type. */ - createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY { - return new BinaryTreeNode(val, id, count) as FAMILY; + createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY { + return new BinaryTreeNode(id, val, count) as FAMILY; } } @@ -52,8 +52,8 @@ export class BinaryTree = BinaryTreeNode> * 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. */ - createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N { - return new BinaryTreeNode(val, id, count) as N; + createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N { + return new BinaryTreeNode(id, val, count) 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 55ad60a..84dd1d6 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -21,8 +21,8 @@ export class BSTNode = BSTNodeNested< * search tree node. It is an optional parameter, so it can be omitted when calling the `createNode` method. * @returns The method is returning a new instance of the BSTNode class, casted as the FAMILY type. */ - override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY { - return new BSTNode(val, id, count) as FAMILY; + override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY { + return new BSTNode(id, val, count) as FAMILY; } } @@ -51,8 +51,8 @@ export class BST = BSTNode> extends BinaryTree * of a particular value in the binary search tree node. * @returns a new instance of the BSTNode class, casted as type N. */ - override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N { - return new BSTNode(val, id, count) as N; + override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N { + return new BSTNode(id, val, count) as N; } /** @@ -67,9 +67,9 @@ export class BST = BSTNode> extends BinaryTree * inserted once. * @returns The method `add` returns a `N` object or `null`. */ - override add(val: N['val'], id: BinaryTreeNodeId, count: number = 1): N | null { + override add(id: BinaryTreeNodeId, val?: N['val'], count: number = 1): N | null { let inserted: N | null = null; - const newNode = this.createNode(val, id, count); + const newNode = this.createNode(id, val, count); if (this.root === null) { this._setRoot(newNode); this._setSize(this.size + 1); @@ -364,7 +364,7 @@ export class BST = BSTNode> extends BinaryTree if (l > r) return; const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.val, midNode.id, midNode.count); + this.add(midNode.id, midNode.val, midNode.count); buildBalanceBST(l, m - 1); buildBalanceBST(m + 1, r); }; @@ -380,7 +380,7 @@ export class BST = BSTNode> extends BinaryTree if (l <= r) { const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.val, midNode.id, midNode.count); + this.add(midNode.id, midNode.val, midNode.count); stack.push([m + 1, r]); stack.push([l, m - 1]); } diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index e76c7f4..d384c58 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -4,8 +4,8 @@ import {BST, BSTNode} from './bst'; export class RBTreeNode = RBTreeNodeNested> extends BSTNode implements IRBTreeNode { - constructor(val: T, id: BinaryTreeNodeId, count?: number) { - super(val, id, count); + constructor(id: BinaryTreeNodeId, val?: T, count?: number) { + super(id, val, count); } private _color: RBColor = RBColor.RED; @@ -28,8 +28,8 @@ export class RBTreeNode = RBTreeNo * node. * @returns The method is returning a new instance of the RBTreeNode class, casted as a FAMILY type. */ - override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY { - return new RBTreeNode(val, id, count) as FAMILY; + override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY { + return new RBTreeNode(id, val, count) as FAMILY; } // private override _parent: RBNode | null; @@ -71,8 +71,8 @@ export class RBTree = RBTreeNode> extends BST< super(options); } - override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N { - return new RBTreeNode(val, id, count) as N; + override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N { + return new RBTreeNode(id, val, count) as N; } // private override _root: BinaryTreeNode | null = null; @@ -81,7 +81,7 @@ export class RBTree = RBTreeNode> extends BST< // return this._root; // } - insert(id: number, val: N | null) { + insert(id: number, val?: N | null) { } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index cc8626c..e454055 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -20,8 +20,8 @@ export class TreeMultiSetNode = TreeMultiSet * occurrences of the value in the binary search tree node. If not provided, the count will default to 1. * @returns A new instance of the BSTNode class with the specified id, value, and count (if provided). */ - override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N { - return new TreeMultiSetNode(val, id, count) as N; + override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N { + return new TreeMultiSetNode(id, val, count) as N; } } diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 2420232..59a0370 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -140,7 +140,7 @@ export abstract class AbstractGraph, E extends Abs abstract getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null; addVertex(vertex: V): boolean - addVertex(id: VertexId , val?: V['val']): boolean + addVertex(id: VertexId, val?: V['val']): boolean addVertex(idOrVertex: VertexId | V, val?: V['val']): boolean { if (idOrVertex instanceof AbstractVertex) { return this._addVertexOnly(idOrVertex); @@ -151,15 +151,6 @@ export abstract class AbstractGraph, E extends Abs } } - protected _addVertexOnly(newVertex: V): boolean { - if (this.hasVertex(newVertex)) { - return false; - // throw (new Error('Duplicated vertex id is not allowed')); - } - this._vertices.set(newVertex.id, newVertex); - return true; - } - /** * 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 @@ -207,7 +198,9 @@ export abstract class AbstractGraph, E extends Abs } addEdge(edge: E): boolean + addEdge(src: V | VertexId, dest: V | VertexId, weight: number, val?: E['val']): boolean + addEdge(srcOrEdge: V | VertexId | E, dest?: V | VertexId, weight?: number, val?: E['val']): boolean { if (srcOrEdge instanceof AbstractEdge) { return this._addEdgeOnly(srcOrEdge); @@ -224,8 +217,6 @@ export abstract class AbstractGraph, E extends Abs } } - protected abstract _addEdgeOnly(edge: E): boolean; - /** * The function sets the weight of an edge between two vertices in a graph. * @param {VertexId | V} srcOrId - The `srcOrId` parameter can be either a `VertexId` or a `V` object. It represents @@ -786,12 +777,6 @@ export abstract class AbstractGraph, E extends Abs return {hasNegativeCycle, distMap, preMap, paths, min, minPath}; } - /** - * 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. - */ - /** * Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle * all pairs @@ -963,6 +948,23 @@ 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)) { + return false; + // throw (new Error('Duplicated vertex id is not allowed')); + } + this._vertices.set(newVertex.id, newVertex); + return true; + } + + protected abstract _addEdgeOnly(edge: E): boolean; + /** * BellmanFord time:O(VE) space:O(V) * one to rest pairs diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 2eae676..e149748 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -140,42 +140,6 @@ export class DirectedGraph = DirectedVertex, E ext return edges[0] || null; } - /** - * 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. - */ - protected _addEdgeOnly(edge: E): boolean { - if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) { - return false; - } - - const srcVertex = this._getVertex(edge.src); - const destVertex = this._getVertex(edge.dest); - - // TODO after no-non-null-assertion not ensure the logic - if (srcVertex && destVertex) { - const srcOutEdges = this._outEdgeMap.get(srcVertex); - if (srcOutEdges) { - srcOutEdges.push(edge); - } else { - this._outEdgeMap.set(srcVertex, [edge]); - } - - const destInEdges = this._inEdgeMap.get(destVertex); - if (destInEdges) { - destInEdges.push(edge); - } else { - this._inEdgeMap.set(destVertex, [edge]); - } - return true; - } else { - return false; - } - } - /** * 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. @@ -420,8 +384,6 @@ export class DirectedGraph = DirectedVertex, E ext return edges; } - /**--- start find cycles --- */ - /** * 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` @@ -444,7 +406,7 @@ export class DirectedGraph = DirectedVertex, E ext return neighbors; } - /**--- end find cycles --- */ + /**--- start find cycles --- */ /** * The function "getEndsOfEdge" returns the source and destination vertices of a directed edge if it exists in the @@ -466,6 +428,44 @@ 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. + */ + protected _addEdgeOnly(edge: E): boolean { + if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) { + return false; + } + + const srcVertex = this._getVertex(edge.src); + const destVertex = this._getVertex(edge.dest); + + // TODO after no-non-null-assertion not ensure the logic + if (srcVertex && destVertex) { + const srcOutEdges = this._outEdgeMap.get(srcVertex); + if (srcOutEdges) { + srcOutEdges.push(edge); + } else { + this._outEdgeMap.set(srcVertex, [edge]); + } + + const destInEdges = this._inEdgeMap.get(destVertex); + if (destInEdges) { + destInEdges.push(edge); + } else { + this._inEdgeMap.set(destVertex, [edge]); + } + return true; + } else { + return false; + } + } + protected _setOutEdgeMap(value: Map) { this._outEdgeMap = value; } diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 6257a58..0d7e987 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -114,28 +114,6 @@ export class UndirectedGraph = UndirectedVertex, return edges ? edges[0] || null : null; } - /** - * 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. - * @returns a boolean value. - */ - protected _addEdgeOnly(edge: E): boolean { - for (const end of edge.vertices) { - const endVertex = this._getVertex(end); - if (endVertex === null) return false; - if (endVertex) { - const edges = this._edges.get(endVertex); - if (edges) { - edges.push(edge); - } else { - this._edges.set(endVertex, [edge]); - } - } - } - return true; - } - /** * 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 @@ -222,7 +200,6 @@ export class UndirectedGraph = UndirectedVertex, return [...edgeSet]; } - /** * 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 @@ -265,6 +242,28 @@ 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. + * @returns a boolean value. + */ + protected _addEdgeOnly(edge: E): boolean { + for (const end of edge.vertices) { + const endVertex = this._getVertex(end); + if (endVertex === null) return false; + if (endVertex) { + const edges = this._edges.get(endVertex); + if (edges) { + edges.push(edge); + } else { + this._edges.set(endVertex, [edge]); + } + } + } + return true; + } + 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 63457fc..391b1bd 100644 --- a/src/data-structures/interfaces/abstract-binary-tree.ts +++ b/src/data-structures/interfaces/abstract-binary-tree.ts @@ -13,7 +13,7 @@ import {AbstractBinaryTreeNode} from '../binary-tree'; export interface IAbstractBinaryTreeNode> { - createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY; + createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY; get id(): BinaryTreeNodeId @@ -51,7 +51,7 @@ export interface IAbstractBinaryTreeNode> { - createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null + createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null get loopType(): LoopType @@ -81,7 +81,7 @@ export interface IAbstractBinaryTree> extends export interface IAVLTree> extends IBST { - add(id: BinaryTreeNodeId, val: N['val'] | null, count?: number): N | null + add(id: BinaryTreeNodeId, val?: N['val'] | null, count?: number): N | null remove(id: BinaryTreeNodeId, isUpdateAllLeftSum?: boolean): BinaryTreeDeletedResult[] diff --git a/src/data-structures/interfaces/bst.ts b/src/data-structures/interfaces/bst.ts index c1f102f..5b14952 100644 --- a/src/data-structures/interfaces/bst.ts +++ b/src/data-structures/interfaces/bst.ts @@ -3,13 +3,13 @@ import {IBinaryTree, IBinaryTreeNode} from './binary-tree'; import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types'; export interface IBSTNode> extends IBinaryTreeNode { - createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY + createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY } export interface IBST> extends IBinaryTree { - createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N + createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N - add(id: BinaryTreeNodeId, val: N['val'] | null, count: number): N | null + add(id: BinaryTreeNodeId, val?: N['val'] | null, count?: number): N | null get(nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName): N | null diff --git a/src/data-structures/interfaces/rb-tree.ts b/src/data-structures/interfaces/rb-tree.ts index 848eb3d..35db390 100644 --- a/src/data-structures/interfaces/rb-tree.ts +++ b/src/data-structures/interfaces/rb-tree.ts @@ -3,10 +3,10 @@ import {IBST, IBSTNode} from './bst'; import {BinaryTreeNodeId} from '../types'; export interface IRBTreeNode> extends IBSTNode { - createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY + createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY } export interface IRBTree> extends IBST { - createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N + createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N } \ No newline at end of file