[graph test] edge cases enriched

This commit is contained in:
Revone 2023-10-30 20:08:25 +08:00
parent 3aea9fc046
commit fcec29f32c
7 changed files with 130 additions and 15 deletions

View file

@ -45,7 +45,7 @@ export abstract class AbstractVertex<V = any> {
}
}
export abstract class AbstractEdge<VO = any> {
export abstract class AbstractEdge<E = any> {
/**
* The above function is a protected constructor that initializes the weight, value, and hash code properties of an
* object.
@ -55,19 +55,19 @@ export abstract class AbstractEdge<VO = any> {
* @param {VO} [val] - The `val` parameter is of type `VO`, 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?: VO) {
protected constructor(weight?: number, val?: E) {
this._weight = weight !== undefined ? weight : 1;
this._val = val;
this._hashCode = uuidV4();
}
private _val: VO | undefined;
private _val: E | undefined;
get val(): VO | undefined {
get val(): E | undefined {
return this._val;
}
set val(value: VO | undefined) {
set val(value: E | undefined) {
this._val = value;
}
@ -131,7 +131,7 @@ export abstract class AbstractGraph<
* @param weight
* @param val
*/
abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO;
abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO;
abstract deleteEdge(edge: EO): EO | null;

View file

@ -129,13 +129,13 @@ export class DirectedGraph<
/**
* The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs.
* @param {VO | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID.
* @param {VO | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the
* @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
* destination is not specified.
* @returns the first edge found between the source and destination vertices, or null if no such edge is found.
*/
getEdge(srcOrKey: VO | null | VertexKey, destOrKey: VO | null | VertexKey): EO | null {
getEdge(srcOrKey: VO | VertexKey | null, destOrKey: VO | VertexKey | null): EO | null {
let edges: EO[] = [];
if (srcOrKey !== null && destOrKey !== null) {

View file

@ -102,13 +102,13 @@ export class UndirectedGraph<
/**
* The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists.
* @param {VO | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex
* @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 | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (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.
*/
getEdge(v1: VO | null | VertexKey, v2: VO | null | VertexKey): EO | null {
getEdge(v1: VO | VertexKey | null, v2: VO | VertexKey | null): EO | null {
let edges: EO[] | undefined = [];
if (v1 !== null && v2 !== null) {

View file

@ -3,5 +3,5 @@ import {VertexKey} from '../types';
export interface IGraph<V, E, VO, EO> {
createVertex(key: VertexKey, val?: V): VO;
createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO;
createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO;
}

View file

@ -1,5 +1,102 @@
import {AbstractEdge, AbstractGraph, AbstractVertex, VertexKey} from '../../../../src';
class MyVertex<V = any> extends AbstractVertex<V> {
data?: V;
constructor(key: VertexKey, val?: V) {
super(key, val);
this.data = val;
}
}
class MyEdge<E = any> extends AbstractEdge<E> {
data?: E;
src: VertexKey;
dest: VertexKey;
constructor(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E) {
super(weight, val);
this.src = srcOrV1;
this.dest = destOrV2;
this.data = val;
this._setHashCode('');
}
}
class MyGraph<
V = any,
E = any,
VO extends MyVertex<V> = MyVertex<V>,
EO extends MyEdge<E> = MyEdge<E>
> extends AbstractGraph<V, E, VO, EO> {
createVertex(key: VertexKey, val?: V): VO {
return new MyVertex(key, val) as VO;
}
createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO {
return new MyEdge(srcOrV1, destOrV2, weight, val) as EO;
}
deleteEdge(edge: EO): EO | null {
return edge;
}
getEdge(srcOrKey: VertexKey, destOrKey: VertexKey): EO | null {
return new MyEdge(srcOrKey, destOrKey) as EO;
}
degreeOf(vertexOrKey: VO | VertexKey): number {
return 1 ?? Number(vertexOrKey);
}
edgeSet(): EO[] {
return [new MyEdge('a', 'b') as EO];
}
edgesOf(vertexOrKey: VO | VertexKey): EO[] {
const a = typeof vertexOrKey === "string" ? vertexOrKey : "a";
return [new MyEdge(a, 'b') as EO];
}
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
const a = typeof vertexOrKey === "string" ? vertexOrKey : "a";
return [new MyVertex(a, 'b') as VO];
}
getEndsOfEdge(edge: EO): [VO, VO] | null {
return edge ? null : null;
}
protected _addEdgeOnly(edge: EO): boolean {
return edge ? true : true;
}
}
describe('AbstractGraph Operation Test', () => {
it('should xxx', function () {
expect(true).toBe(true);
const myGraph: MyGraph<number, string> = new MyGraph<number, string>();
beforeEach(() => {
});
it('should edge cases', function () {
myGraph.addVertex('A', 1);
myGraph.addVertex('B', 2);
myGraph.addVertex('C', 3);
myGraph.addVertex('D', 4);
const vA = myGraph.getVertex('A');
// const vB = myGraph.getVertex('B');
// const vC = myGraph.getVertex('C');
// const vD = myGraph.getVertex('D');
const eAB = new MyEdge('A', 'B');
// const eBC = new MyEdge('B', 'C');
// const eCD = new MyEdge('C', 'D');
vA!.key = vA?.key || 1;
vA!.val = vA?.val ?? 2;
eAB!.val = eAB.val;
const hs = eAB.hashCode;
expect(hs).toBe('');
});
});

View file

@ -139,6 +139,14 @@ class MyDirectedGraph<
createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO {
return new MyEdge(src, dest, weight ?? 1, val) as EO;
}
setInEdgeMap(value: Map<VO, EO[]>) {
super._setInEdgeMap(value);
}
setOutEdgeMap(value: Map<VO, EO[]>) {
super._setOutEdgeMap(value);
}
}
describe('Inherit from DirectedGraph and perform operations', () => {
@ -164,6 +172,8 @@ describe('Inherit from DirectedGraph and perform operations', () => {
myGraph.addVertex(2, 'data2');
myGraph.addEdge(1, 2, 10, 'edge-data1-2');
myGraph.addEdge(new MyEdge(2, 1, 20, 'edge-data2-1'));
myGraph.setInEdgeMap(myGraph.inEdgeMap);
myGraph.setOutEdgeMap(myGraph.outEdgeMap);
expect(myGraph.edgeSet().length).toBe(2);
// TODO

View file

@ -7,6 +7,14 @@ describe('UndirectedGraph Operation Test', () => {
graph = new UndirectedGraph();
});
it('should edge cases', () => {
expect(graph.deleteEdge(new UndirectedEdge('c', 'd'))).toBe(null);
expect(graph.deleteEdgeBetween('c', 'd')).toBe(null);
expect(graph.degreeOf('c')).toBe(0);
expect(graph.edgesOf('c').length).toBe(0);
expect(graph.getEndsOfEdge(new UndirectedEdge('c', 'd'))).toBe(null);
});
it('should add vertices', () => {
const vertex1 = new UndirectedVertex('A');
const vertex2 = new UndirectedVertex('B');