refactor: In Graph data structures, only use 'undefined' and abandon the design where both 'null' and 'undefined' coexist.

This commit is contained in:
Revone 2023-11-26 20:11:29 +08:00
parent 3dc0454c24
commit f3df66eef3
8 changed files with 157 additions and 167 deletions

View file

@ -8,38 +8,28 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.47.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.47.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes
- Rbtree [`#31`](https://github.com/zrwusa/data-structure-typed/pull/31)
- [graph test] edge cases enriched [`#30`](https://github.com/zrwusa/data-structure-typed/pull/30)
- [graph] Modify the data structure design of the graph to change the
g… [`#29`](https://github.com/zrwusa/data-structure-typed/pull/29)
- [graph] Modify the data structure design of the graph to change the g… [`#29`](https://github.com/zrwusa/data-structure-typed/pull/29)
- Optimization [`#23`](https://github.com/zrwusa/data-structure-typed/pull/23)
- Optimization [`#20`](https://github.com/zrwusa/data-structure-typed/pull/20)
- [binary-tree, graph] Replace all code that uses Arrays as makeshift
Q… [`#18`](https://github.com/zrwusa/data-structure-typed/pull/18)
-
1. No need for dfsIterative; integrate it directly into the dfs
metho… [`#17`](https://github.com/zrwusa/data-structure-typed/pull/17)
- [heap] fibonacci heap implemented. [test] big O estimate. [project]
n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15)
- [binary-tree, graph] Replace all code that uses Arrays as makeshift Q… [`#18`](https://github.com/zrwusa/data-structure-typed/pull/18)
- 1. No need for dfsIterative; integrate it directly into the dfs metho… [`#17`](https://github.com/zrwusa/data-structure-typed/pull/17)
- [heap] fibonacci heap implemented. [test] big O estimate. [project] n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15)
- [rbtree] implemented, but with bugs [`#13`](https://github.com/zrwusa/data-structure-typed/pull/13)
- [trie] renamed ambiguous methods and add comments to all
methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12)
- [binarytree] modified the getDepth method to adhere to the proper
def… [`#11`](https://github.com/zrwusa/data-structure-typed/pull/11)
- [trie] renamed ambiguous methods and add comments to all methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12)
- [binarytree] modified the getDepth method to adhere to the proper def… [`#11`](https://github.com/zrwusa/data-structure-typed/pull/11)
- Trie [`#10`](https://github.com/zrwusa/data-structure-typed/pull/10)
- [tree] getHeight returns faulty height bug fixed [`#9`](https://github.com/zrwusa/data-structure-typed/pull/9)
- [trie] support casesensitivity. getWords bug fixed [`#8`](https://github.com/zrwusa/data-structure-typed/pull/8)
- [binary-tree, graph] In order to optimize the design of Binary
Trees,… [`#7`](https://github.com/zrwusa/data-structure-typed/pull/7)
- [BinaryTree, Heap] In abstract classes, only retain abstract
methods.… [`#6`](https://github.com/zrwusa/data-structure-typed/pull/6)
- [binary-tree, graph] In order to optimize the design of Binary Trees,… [`#7`](https://github.com/zrwusa/data-structure-typed/pull/7)
- [BinaryTree, Heap] In abstract classes, only retain abstract methods.… [`#6`](https://github.com/zrwusa/data-structure-typed/pull/6)
- [heap] test [`#5`](https://github.com/zrwusa/data-structure-typed/pull/5)
- [heap, priority queue] Heap improved. References #123:
redesigned [`#4`](https://github.com/zrwusa/data-structure-typed/pull/4)
- [heap, priority queue] Heap improved. References #123: redesigned [`#4`](https://github.com/zrwusa/data-structure-typed/pull/4)
- test [`#3`](https://github.com/zrwusa/data-structure-typed/pull/3)
## [v1.35.0](https://github.com/zrwusa/data-structure-typed/compare/v1.34.1...v1.35.0) (11 October 2023)

View file

@ -89,9 +89,9 @@ export abstract class AbstractGraph<
*/
abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, value?: E): EO;
abstract deleteEdge(edge: EO): EO | null;
abstract deleteEdge(edge: EO): EO | undefined;
abstract getEdge(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | null;
abstract getEdge(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | undefined;
abstract degreeOf(vertexOrKey: VO | VertexKey): number;
@ -101,7 +101,7 @@ export abstract class AbstractGraph<
abstract getNeighbors(vertexOrKey: VO | VertexKey): VO[];
abstract getEndsOfEdge(edge: EO): [VO, VO] | null;
abstract getEndsOfEdge(edge: EO): [VO, VO] | undefined;
/**
* Time Complexity: O(1) - Constant time for Map lookup.
@ -112,14 +112,14 @@ export abstract class AbstractGraph<
* Time Complexity: O(1) - Constant time for Map lookup.
* Space Complexity: O(1) - Constant space, as it creates only a few variables.
*
* The function "getVertex" returns the vertex with the specified ID or null if it doesn't exist.
* The function "getVertex" returns the vertex with the specified ID or undefined if it doesn't exist.
* @param {VertexKey} vertexKey - The `vertexKey` parameter is the identifier of the vertex that you want to retrieve from
* the `_vertices` map.
* @returns The method `getVertex` returns the vertex with the specified `vertexKey` if it exists in the `_vertices`
* map. If the vertex does not exist, it returns `null`.
* map. If the vertex does not exist, it returns `undefined`.
*/
getVertex(vertexKey: VertexKey): VO | null {
return this._vertices.get(vertexKey) || null;
getVertex(vertexKey: VertexKey): VO | undefined {
return this._vertices.get(vertexKey) || undefined;
}
/**
@ -365,7 +365,7 @@ export abstract class AbstractGraph<
* vertices. If `isWeight` is `false` or not provided, it uses a breadth-first search (BFS) algorithm to calculate the
* minimum number of
*/
getMinCostBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): number | null {
getMinCostBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): number | undefined {
if (isWeight === undefined) isWeight = false;
if (isWeight) {
@ -380,7 +380,7 @@ export abstract class AbstractGraph<
const vertex2 = this._getVertex(v2);
const vertex1 = this._getVertex(v1);
if (!(vertex1 && vertex2)) {
return null;
return undefined;
}
const visited: Map<VO, boolean> = new Map();
@ -406,7 +406,7 @@ export abstract class AbstractGraph<
}
cost++;
}
return null;
return undefined;
}
}
@ -432,9 +432,9 @@ export abstract class AbstractGraph<
* followed by iterative computation of the shortest path. This approach may result in exponential time complexity,
* so the default method is to use the Dijkstra algorithm to obtain the shortest weighted path.
* @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between
* two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
* two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `undefined`.
*/
getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS = false): VO[] | null {
getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS = false): VO[] | undefined {
if (isWeight === undefined) isWeight = false;
if (isWeight) {
@ -451,7 +451,7 @@ export abstract class AbstractGraph<
}
index++;
}
return allPaths[minIndex] || null;
return allPaths[minIndex] || undefined;
} else {
return this.dijkstra(v1, v2, true, true)?.minPath ?? [];
}
@ -503,9 +503,9 @@ export abstract class AbstractGraph<
* a graph without using a heap data structure.
* @param {VO | VertexKey} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a
* vertex object or a vertex ID.
* @param {VO | VertexKey | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
* @param {VO | VertexKey | undefined} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
* parameter that specifies the destination vertex for the Dijkstra algorithm. It can be either a vertex object or its
* identifier. If no destination is provided, the value is set to `null`.
* identifier. If no destination is provided, the value is set to `undefined`.
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
* distance from the source vertex to the destination vertex should be calculated and returned in the result. If
* `getMinDist` is set to `true`, the `minDist` property in the result will contain the minimum distance
@ -516,29 +516,29 @@ export abstract class AbstractGraph<
*/
dijkstraWithoutHeap(
src: VO | VertexKey,
dest?: VO | VertexKey | null,
dest?: VO | VertexKey | undefined,
getMinDist?: boolean,
genPaths?: boolean
): DijkstraResult<VO> {
if (getMinDist === undefined) getMinDist = false;
if (genPaths === undefined) genPaths = false;
if (dest === undefined) dest = null;
if (dest === undefined) dest = undefined;
let minDist = Infinity;
let minDest: VO | null = null;
let minDest: VO | undefined = undefined;
let minPath: VO[] = [];
const paths: VO[][] = [];
const vertices = this._vertices;
const distMap: Map<VO, number> = new Map();
const seen: Set<VO> = new Set();
const preMap: Map<VO, VO | null> = new Map(); // predecessor
const preMap: Map<VO, VO | undefined> = new Map(); // predecessor
const srcVertex = this._getVertex(src);
const destVertex = dest ? this._getVertex(dest) : null;
const destVertex = dest ? this._getVertex(dest) : undefined;
if (!srcVertex) {
return null;
return undefined;
}
for (const vertex of vertices) {
@ -546,11 +546,11 @@ export abstract class AbstractGraph<
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
}
distMap.set(srcVertex, 0);
preMap.set(srcVertex, null);
preMap.set(srcVertex, undefined);
const getMinOfNoSeen = () => {
let min = Infinity;
let minV: VO | null = null;
let minV: VO | undefined = undefined;
for (const [key, value] of distMap) {
if (!seen.has(key)) {
if (value < min) {
@ -562,7 +562,7 @@ export abstract class AbstractGraph<
return minV;
};
const getPaths = (minV: VO | null) => {
const getPaths = (minV: VO | undefined) => {
for (const vertex of vertices) {
const vertexOrKey = vertex[1];
@ -600,7 +600,7 @@ export abstract class AbstractGraph<
if (edge) {
const curFromMap = distMap.get(cur);
const neighborFromMap = distMap.get(neighbor);
// TODO after no-non-null-assertion not ensure the logic
// TODO after no-non-undefined-assertion not ensure the logic
if (curFromMap !== undefined && neighborFromMap !== undefined) {
if (edge.weight + curFromMap < neighborFromMap) {
distMap.set(neighbor, edge.weight + curFromMap);
@ -651,7 +651,7 @@ export abstract class AbstractGraph<
* optional destination vertex, and optionally returns the minimum distance, the paths, and other information.
* @param {VO | VertexKey} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will
* start. It can be either a vertex object or a vertex ID.
* @param {VO | VertexKey | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
* @param {VO | VertexKey | undefined} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
* vertex to which the shortest path is calculated from the source vertex. If no destination is provided, the algorithm
* will calculate the shortest paths to all other vertices from the source vertex.
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
@ -664,27 +664,27 @@ export abstract class AbstractGraph<
*/
dijkstra(
src: VO | VertexKey,
dest?: VO | VertexKey | null,
dest?: VO | VertexKey | undefined,
getMinDist?: boolean,
genPaths?: boolean
): DijkstraResult<VO> {
if (getMinDist === undefined) getMinDist = false;
if (genPaths === undefined) genPaths = false;
if (dest === undefined) dest = null;
if (dest === undefined) dest = undefined;
let minDist = Infinity;
let minDest: VO | null = null;
let minDest: VO | undefined = undefined;
let minPath: VO[] = [];
const paths: VO[][] = [];
const vertices = this._vertices;
const distMap: Map<VO, number> = new Map();
const seen: Set<VO> = new Set();
const preMap: Map<VO, VO | null> = new Map(); // predecessor
const preMap: Map<VO, VO | undefined> = new Map(); // predecessor
const srcVertex = this._getVertex(src);
const destVertex = dest ? this._getVertex(dest) : null;
const destVertex = dest ? this._getVertex(dest) : undefined;
if (!srcVertex) return null;
if (!srcVertex) return undefined;
for (const vertex of vertices) {
const vertexOrKey = vertex[1];
@ -695,14 +695,14 @@ export abstract class AbstractGraph<
heap.add({ key: 0, value: srcVertex });
distMap.set(srcVertex, 0);
preMap.set(srcVertex, null);
preMap.set(srcVertex, undefined);
/**
* The function `getPaths` retrieves all paths from vertices to a specified minimum vertex.
* @param {VO | null} minV - The parameter `minV` is of type `VO | null`. It represents the minimum vertex value or
* null.
* @param {VO | undefined} minV - The parameter `minV` is of type `VO | undefined`. It represents the minimum vertex value or
* undefined.
*/
const getPaths = (minV: VO | null) => {
const getPaths = (minV: VO | undefined) => {
for (const vertex of vertices) {
const vertexOrKey = vertex[1];
if (vertexOrKey instanceof AbstractVertex) {
@ -841,7 +841,7 @@ export abstract class AbstractGraph<
}
}
let minDest: VO | null = null;
let minDest: VO | undefined = undefined;
if (getMin) {
distMap.forEach((d, v) => {
if (v !== srcVertex) {
@ -920,22 +920,22 @@ export abstract class AbstractGraph<
* graph.
* @returns The function `floydWarshall()` returns an object with two properties: `costs` and `predecessor`. The `costs`
* property is a 2D array of numbers representing the shortest path costs between vertices in a graph. The
* `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest
* `predecessor` property is a 2D array of vertices (or `undefined`) representing the predecessor vertices in the shortest
* path between vertices in the
*/
floydWarshall(): { costs: number[][]; predecessor: (VO | null)[][] } {
floydWarshall(): { costs: number[][]; predecessor: (VO | undefined)[][] } {
const idAndVertices = [...this._vertices];
const n = idAndVertices.length;
const costs: number[][] = [];
const predecessor: (VO | null)[][] = [];
const predecessor: (VO | undefined)[][] = [];
// successors
for (let i = 0; i < n; i++) {
costs[i] = [];
predecessor[i] = [];
for (let j = 0; j < n; j++) {
predecessor[i][j] = null;
predecessor[i][j] = undefined;
}
}
@ -1021,7 +1021,7 @@ export abstract class AbstractGraph<
const cutVertexes: VO[] = [];
const bridges: EO[] = [];
let dfn = 0;
const dfs = (cur: VO, parent: VO | null) => {
const dfs = (cur: VO, parent: VO | undefined) => {
dfn++;
dfnMap.set(cur, dfn);
lowMap.set(cur, dfn);
@ -1036,7 +1036,7 @@ export abstract class AbstractGraph<
}
const childLow = lowMap.get(neighbor);
const curLow = lowMap.get(cur);
// TODO after no-non-null-assertion not ensure the logic
// TODO after no-non-undefined-assertion not ensure the logic
if (curLow !== undefined && childLow !== undefined) {
lowMap.set(cur, Math.min(curLow, childLow));
}
@ -1062,7 +1062,7 @@ export abstract class AbstractGraph<
}
};
dfs(root, null);
dfs(root, undefined);
let SCCs: Map<number, VO[]> = new Map();
@ -1170,9 +1170,9 @@ export abstract class AbstractGraph<
return true;
}
protected _getVertex(vertexOrKey: VertexKey | VO): VO | null {
protected _getVertex(vertexOrKey: VertexKey | VO): VO | undefined {
const vertexKey = this._getVertexKey(vertexOrKey);
return this._vertices.get(vertexKey) || null;
return this._vertices.get(vertexKey) || undefined;
}
protected _getVertexKey(vertexOrKey: VO | VertexKey): VertexKey {

View file

@ -119,18 +119,18 @@ export class DirectedGraph<
* Space Complexity: O(1)
*
* The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs.
* @param {VO | VertexKey | null} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID.
* @param {VO | VertexKey | null} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the
* destination vertex of the edge. It can be either a vertex object (`VO`), a vertex ID (`VertexKey`), or `null` if the
* @param {VO | VertexKey | undefined} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID.
* @param {VO | VertexKey | undefined} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the
* destination vertex of the edge. It can be either a vertex object (`VO`), a vertex ID (`VertexKey`), or `undefined` 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.
* @returns the first edge found between the source and destination vertices, or undefined if no such edge is found.
*/
getEdge(srcOrKey: VO | VertexKey | null, destOrKey: VO | VertexKey | null): EO | null {
getEdge(srcOrKey: VO | VertexKey | undefined, destOrKey: VO | VertexKey | undefined): EO | undefined {
let edges: EO[] = [];
if (srcOrKey !== null && destOrKey !== null) {
const src: VO | null = this._getVertex(srcOrKey);
const dest: VO | null = this._getVertex(destOrKey);
if (srcOrKey !== undefined && destOrKey !== undefined) {
const src: VO | undefined = this._getVertex(srcOrKey);
const dest: VO | undefined = this._getVertex(destOrKey);
if (src && dest) {
const srcOutEdges = this._outEdgeMap.get(src);
@ -140,7 +140,7 @@ export class DirectedGraph<
}
}
return edges[0] || null;
return edges[0] || undefined;
}
/**
@ -155,14 +155,14 @@ export class DirectedGraph<
* The function removes an edge between two vertices in a graph and returns the removed edge.
* @param {VO | VertexKey} srcOrKey - The source vertex or its ID.
* @param {VO | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID.
* @returns the removed edge (EO) if it exists, or null if either the source or destination vertex does not exist.
* @returns the removed edge (EO) if it exists, or undefined if either the source or destination vertex does not exist.
*/
deleteEdgeSrcToDest(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | null {
const src: VO | null = this._getVertex(srcOrKey);
const dest: VO | null = this._getVertex(destOrKey);
let removed: EO | null = null;
deleteEdgeSrcToDest(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | undefined {
const src: VO | undefined = this._getVertex(srcOrKey);
const dest: VO | undefined = this._getVertex(destOrKey);
let removed: EO | undefined = undefined;
if (!src || !dest) {
return null;
return undefined;
}
const srcOutEdges = this._outEdgeMap.get(src);
@ -172,7 +172,7 @@ export class DirectedGraph<
const destInEdges = this._inEdgeMap.get(dest);
if (destInEdges) {
removed = arrayRemove<EO>(destInEdges, (edge: EO) => edge.src === src.key)[0] || null;
removed = arrayRemove<EO>(destInEdges, (edge: EO) => edge.src === src.key)[0] || undefined;
}
return removed;
}
@ -186,13 +186,13 @@ export class DirectedGraph<
* Time Complexity: O(|E|) where |E| is the number of edges
* Space Complexity: O(1)
*
* The function removes an edge from a graph and returns the removed edge, or null if the edge was not found.
* The function removes an edge from a graph and returns the removed edge, or undefined if the edge was not found.
* @param {EO} 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 `deleteEdge` returns the removed edge (`EO`) if it exists, or `null` if the edge does not exist.
* @returns The method `deleteEdge` returns the removed edge (`EO`) if it exists, or `undefined` if the edge does not exist.
*/
deleteEdge(edge: EO): EO | null {
let removed: EO | null = null;
deleteEdge(edge: EO): EO | undefined {
let removed: EO | undefined = undefined;
const src = this._getVertex(edge.src);
const dest = this._getVertex(edge.dest);
if (src && dest) {
@ -361,11 +361,11 @@ export class DirectedGraph<
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function "getEdgeSrc" returns the source vertex of an edge, or null if the edge does not exist.
* The function "getEdgeSrc" returns the source vertex of an edge, or undefined if the edge does not exist.
* @param {EO} e - The parameter "e" is of type EO, which represents an edge in a graph.
* @returns either a vertex object (VO) or null.
* @returns either a vertex object (VO) or undefined.
*/
getEdgeSrc(e: EO): VO | null {
getEdgeSrc(e: EO): VO | undefined {
return this._getVertex(e.src);
}
@ -380,9 +380,9 @@ export class DirectedGraph<
*
* The function "getEdgeDest" returns the destination vertex of an edge.
* @param {EO} e - The parameter "e" is of type "EO", which represents an edge in a graph.
* @returns either a vertex object of type VO or null.
* @returns either a vertex object of type VO or undefined.
*/
getEdgeDest(e: EO): VO | null {
getEdgeDest(e: EO): VO | undefined {
return this._getVertex(e.dest);
}
@ -396,12 +396,12 @@ export class DirectedGraph<
* Space Complexity: O(1)
*
* The function `getDestinations` returns an array of destination vertices connected to a given vertex.
* @param {VO | VertexKey | null} vertex - The `vertex` parameter represents the starting vertex from which we want to
* find the destinations. It can be either a `VO` object, a `VertexKey` value, or `null`.
* @param {VO | VertexKey | undefined} vertex - The `vertex` parameter represents the starting vertex from which we want to
* find the destinations. It can be either a `VO` object, a `VertexKey` value, or `undefined`.
* @returns an array of vertices (VO[]).
*/
getDestinations(vertex: VO | VertexKey | null): VO[] {
if (vertex === null) {
getDestinations(vertex: VO | VertexKey | undefined): VO[] {
if (vertex === undefined) {
return [];
}
const destinations: VO[] = [];
@ -425,13 +425,13 @@ export class DirectedGraph<
* Space Complexity: O(|V|)
*
* 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.
* in the sorted order, or undefined if the graph contains a cycle.
* @param {'vertex' | 'key'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'key'. If 'vertex' is
* specified, the vertices themselves will be used for sorting. If 'key' is specified, the ids of
* @returns an array of vertices or vertex IDs in topological order. If there is a cycle in the graph, it returns null.
* @returns an array of vertices or vertex IDs in topological order. If there is a cycle in the graph, it returns undefined.
*/
topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | null {
topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | undefined {
propertyName = propertyName ?? 'key';
// When judging whether there is a cycle in the undirected graph, all nodes with degree of **<= 1** are enqueued
// When judging whether there is a cycle in the directed graph, all nodes with **in degree = 0** are enqueued
@ -463,7 +463,7 @@ export class DirectedGraph<
}
}
if (hasCycle) return null;
if (hasCycle) return undefined;
if (propertyName === 'key') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.key : vertex));
return sorted.reverse();
@ -510,7 +510,7 @@ export class DirectedGraph<
const outEdges = this.outgoingEdgesOf(vertex);
for (const outEdge of outEdges) {
const neighbor = this._getVertex(outEdge.dest);
// TODO after no-non-null-assertion not ensure the logic
// TODO after no-non-undefined-assertion not ensure the logic
if (neighbor) {
neighbors.push(neighbor);
}
@ -529,21 +529,21 @@ export class DirectedGraph<
* Space Complexity: O(1)
*
* The function "getEndsOfEdge" returns the source and destination vertices of an edge if it exists in the graph,
* otherwise it returns null.
* otherwise it returns undefined.
* @param {EO} edge - The parameter `edge` is of type `EO`, which represents an edge in a graph.
* @returns The function `getEndsOfEdge` returns an array containing two vertices `[VO, VO]` if the edge exists in the
* graph. If the edge does not exist, it returns `null`.
* graph. If the edge does not exist, it returns `undefined`.
*/
getEndsOfEdge(edge: EO): [VO, VO] | null {
getEndsOfEdge(edge: EO): [VO, VO] | undefined {
if (!this.hasEdge(edge.src, edge.dest)) {
return null;
return undefined;
}
const v1 = this._getVertex(edge.src);
const v2 = this._getVertex(edge.dest);
if (v1 && v2) {
return [v1, v2];
} else {
return null;
return undefined;
}
}
@ -570,7 +570,7 @@ export class DirectedGraph<
const srcVertex = this._getVertex(edge.src);
const destVertex = this._getVertex(edge.dest);
// TODO after no-non-null-assertion not ensure the logic
// TODO after no-non-undefined-assertion not ensure the logic
if (srcVertex && destVertex) {
const srcOutEdges = this._outEdgeMap.get(srcVertex);
if (srcOutEdges) {

View file

@ -100,26 +100,26 @@ export class UndirectedGraph<
* Time Complexity: O(|E|), where |E| is the number of edges incident to the given vertex.
* Space Complexity: O(1)
*
* The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists.
* @param {VO | VertexKey | null} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex
* object), `null`, or `VertexKey` (a string or number representing the ID of a vertex).
* @param {VO | VertexKey | null} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex
* object), `null`, or `VertexKey` (vertex ID).
* @returns an edge (EO) or null.
* The function `getEdge` returns the first edge that connects two vertices, or undefined if no such edge exists.
* @param {VO | VertexKey | undefined} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex
* object), `undefined`, or `VertexKey` (a string or number representing the ID of a vertex).
* @param {VO | VertexKey | undefined} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex
* object), `undefined`, or `VertexKey` (vertex ID).
* @returns an edge (EO) or undefined.
*/
getEdge(v1: VO | VertexKey | null, v2: VO | VertexKey | null): EO | null {
getEdge(v1: VO | VertexKey | undefined, v2: VO | VertexKey | undefined): EO | undefined {
let edges: EO[] | undefined = [];
if (v1 !== null && v2 !== null) {
const vertex1: VO | null = this._getVertex(v1);
const vertex2: VO | null = this._getVertex(v2);
if (v1 !== undefined && v2 !== undefined) {
const vertex1: VO | undefined = this._getVertex(v1);
const vertex2: VO | undefined = this._getVertex(v2);
if (vertex1 && vertex2) {
edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.key));
}
}
return edges ? edges[0] || null : null;
return edges ? edges[0] || undefined : undefined;
}
/**
@ -135,20 +135,20 @@ export class UndirectedGraph<
* @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
* @param {VO | VertexKey} v2 - VO | VertexKey - This parameter can be either a vertex object (VO) or a vertex ID
* (VertexKey). It represents the second vertex of the edge that needs to be removed.
* @returns the removed edge (EO) if it exists, or null if either of the vertices (VO) does not exist.
* @returns the removed edge (EO) if it exists, or undefined if either of the vertices (VO) does not exist.
*/
deleteEdgeBetween(v1: VO | VertexKey, v2: VO | VertexKey): EO | null {
const vertex1: VO | null = this._getVertex(v1);
const vertex2: VO | null = this._getVertex(v2);
deleteEdgeBetween(v1: VO | VertexKey, v2: VO | VertexKey): EO | undefined {
const vertex1: VO | undefined = this._getVertex(v1);
const vertex2: VO | undefined = this._getVertex(v2);
if (!vertex1 || !vertex2) {
return null;
return undefined;
}
const v1Edges = this._edges.get(vertex1);
let removed: EO | null = null;
let removed: EO | undefined = undefined;
if (v1Edges) {
removed = arrayRemove<EO>(v1Edges, (e: EO) => e.vertices.includes(vertex2.key))[0] || null;
removed = arrayRemove<EO>(v1Edges, (e: EO) => e.vertices.includes(vertex2.key))[0] || undefined;
}
const v2Edges = this._edges.get(vertex2);
if (v2Edges) {
@ -168,9 +168,9 @@ export class UndirectedGraph<
*
* The deleteEdge function removes an edge between two vertices in a graph.
* @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph.
* @returns The method is returning either the removed edge (of type EO) or null if the edge was not found.
* @returns The method is returning either the removed edge (of type EO) or undefined if the edge was not found.
*/
deleteEdge(edge: EO): EO | null {
deleteEdge(edge: EO): EO | undefined {
return this.deleteEdgeBetween(edge.vertices[0], edge.vertices[1]);
}
@ -282,21 +282,21 @@ export class UndirectedGraph<
* Space Complexity: O(1)
*
* The function "getEndsOfEdge" returns the vertices at the ends of an edge if the edge exists in the graph, otherwise
* it returns null.
* it returns undefined.
* @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph.
* @returns The function `getEndsOfEdge` returns an array containing two vertices `[VO, VO]` if the edge exists in the
* graph. If the edge does not exist, it returns `null`.
* graph. If the edge does not exist, it returns `undefined`.
*/
getEndsOfEdge(edge: EO): [VO, VO] | null {
getEndsOfEdge(edge: EO): [VO, VO] | undefined {
if (!this.hasEdge(edge.vertices[0], edge.vertices[1])) {
return null;
return undefined;
}
const v1 = this._getVertex(edge.vertices[0]);
const v2 = this._getVertex(edge.vertices[1]);
if (v1 && v2) {
return [v1, v2];
} else {
return null;
return undefined;
}
}
@ -316,7 +316,7 @@ export class UndirectedGraph<
protected _addEdgeOnly(edge: EO): boolean {
for (const end of edge.vertices) {
const endVertex = this._getVertex(end);
if (endVertex === null) return false;
if (endVertex === undefined) return false;
if (endVertex) {
const edges = this._edges.get(endVertex);
if (edges) {

View file

@ -3,9 +3,9 @@ export type VertexKey = string | number;
export type DijkstraResult<V> = {
distMap: Map<V, number>;
distPaths?: Map<V, V[]>;
preMap: Map<V, V | null>;
preMap: Map<V, V | undefined>;
seen: Set<V>;
paths: V[][];
minDist: number;
minPath: V[];
} | null;
} | undefined;

View file

@ -4,8 +4,8 @@
<meta charset='UTF-8'>
<title>CDN Test</title>
<!-- <script src="../../dist/umd/data-structure-typed.min.js"></script>-->
<script src="../../dist/umd/data-structure-typed.js"></script>
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>-->
<!-- <script src="../../dist/umd/data-structure-typed.js"></script>-->
<script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.42.2/dist/umd/data-structure-typed.min.js'></script>-->
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.43.3/dist/umd/data-structure-typed.min.js'></script>-->
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.44.0/dist/umd/data-structure-typed.min.js'></script>-->
@ -215,25 +215,25 @@
} catch (e) {
console.error(e);
}
try {
const {
const {
AVLTree,
BinaryTree,
BST,
Deque,
DoublyLinkedList,
HashMap,
Heap,
MaxPriorityQueue,
MinHeap,
MinPriorityQueue,
Queue,
RedBlackTree,
SinglyLinkedList,
Stack,
TreeMultimap,
Trie
BinaryTree,
BST,
Deque,
DoublyLinkedList,
HashMap,
Heap,
MaxPriorityQueue,
MinHeap,
MinPriorityQueue,
Queue,
RedBlackTree,
SinglyLinkedList,
Stack,
TreeMultimap,
Trie
} = dataStructureTyped;
const orgArr = [6, 1, 2, 7, 5, 3, 4, 9, 8];
const orgStrArr = ["trie", "trial", "trick", "trip", "tree", "trend", "triangle", "track", "trace", "transmit"];
@ -299,7 +299,7 @@
const entries2 = dq2.map((el, i) => [i, el]);
const avl2 = new AVLTree(entries2);
avl2.print();
} catch (e) {
} catch (e) {
console.error(e);
}
</script>

View file

@ -196,7 +196,7 @@ describe('Inherit from DirectedGraph and perform operations', () => {
expect(edge1).toBeInstanceOf(MyEdge);
expect(edge1.src).toBe(1);
expect(edge1).toEqual(edge2);
expect(edge3).toBeNull();
expect(edge3).toBe(undefined);
}
});
@ -217,7 +217,7 @@ describe('Inherit from DirectedGraph and perform operations', () => {
removedEdge && expect(removedEdge.value).toBe('edge-data1-2');
removedEdge && expect(removedEdge.src).toBe(1);
}
expect(edgeAfterRemoval).toBeNull();
expect(edgeAfterRemoval).toBe(undefined);
});
it('Topological sort', () => {
@ -303,7 +303,7 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
myGraph.addEdge(new MyEdge(7, 3, 73, 'edge-data7-3'));
const topologicalSorted = myGraph.topologicalSort();
expect(topologicalSorted).toBeNull();
expect(topologicalSorted).toBe(undefined);
const minPath1to7 = myGraph.getMinPathBetween(1, 7);
@ -378,11 +378,11 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
expect(predecessor).toBeInstanceOf(Array);
expect(predecessor.length).toBe(9);
expect(predecessor[0]).toEqual([vertex2, null, vertex2, null, vertex3, null, vertex4, null, null]);
expect(predecessor[1]).toEqual([null, vertex1, null, vertex1, vertex3, null, vertex4, null, vertex1]);
expect(predecessor[5]).toEqual([null, null, null, null, null, null, null, null, null]);
expect(predecessor[7]).toEqual([null, null, null, null, null, null, null, null, null]);
expect(predecessor[8]).toEqual([vertex7, vertex7, vertex7, vertex7, vertex7, null, null, null, vertex7]);
expect(predecessor[0]).toEqual([vertex2, undefined, vertex2, undefined, vertex3, undefined, vertex4, undefined, undefined]);
expect(predecessor[1]).toEqual([undefined, vertex1, undefined, vertex1, vertex3, undefined, vertex4, undefined, vertex1]);
expect(predecessor[5]).toEqual([undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]);
expect(predecessor[7]).toEqual([undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]);
expect(predecessor[8]).toEqual([vertex7, vertex7, vertex7, vertex7, vertex7, undefined, undefined, undefined, vertex7]);
}
const dijkstraRes12tt = myGraph.dijkstra(1, 2, true, true);
@ -436,7 +436,7 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
expect(paths[8][1]).toBe(vertex9);
}
const dijkstraRes1ntt = myGraph.dijkstra(1, null, true, true);
const dijkstraRes1ntt = myGraph.dijkstra(1, undefined, true, true);
expect(dijkstraRes1ntt).toBeTruthy();
if (dijkstraRes1ntt) {
@ -499,7 +499,7 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
expect(paths[8][1]).toBe(vertex9);
}
const dijkstraWithoutHeapRes1ntt = myGraph.dijkstraWithoutHeap(1, null, true, true);
const dijkstraWithoutHeapRes1ntt = myGraph.dijkstraWithoutHeap(1, undefined, true, true);
expect(dijkstraWithoutHeapRes1ntt).toBeTruthy();
if (dijkstraWithoutHeapRes1ntt) {
const { distMap, minDist, minPath, paths } = dijkstraWithoutHeapRes1ntt;

View file

@ -10,11 +10,11 @@ describe('UndirectedGraph Operation Test', () => {
});
it('should edge cases', () => {
expect(graph.deleteEdge(new UndirectedEdge('c', 'd'))).toBe(null);
expect(graph.deleteEdgeBetween('c', 'd')).toBe(null);
expect(graph.deleteEdge(new UndirectedEdge('c', 'd'))).toBe(undefined);
expect(graph.deleteEdgeBetween('c', 'd')).toBe(undefined);
expect(graph.degreeOf('c')).toBe(0);
expect(graph.edgesOf('c').length).toBe(0);
expect(graph.getEndsOfEdge(new UndirectedEdge('c', 'd'))).toBe(null);
expect(graph.getEndsOfEdge(new UndirectedEdge('c', 'd'))).toBe(undefined);
});
it('should add vertices', () => {