fix: bug fix for #51 . Removing a vertex from a DirectedGraph doesn't remove it's edges

This commit is contained in:
Revone 2023-12-06 10:36:00 +08:00
parent 241cb26a6f
commit 6cc250606b
4 changed files with 155 additions and 2 deletions

View file

@ -226,6 +226,39 @@ export class DirectedGraph<
return removed;
}
/**
* Time Complexity: O(1) - Constant time for Map operations.
* Space Complexity: O(1) - Constant space, as it creates only a few variables.
*/
/**
* Time Complexity: O(1) - Constant time for Map operations.
* Space Complexity: O(1) - Constant space, as it creates only a few variables.
*
* The `deleteVertex` function removes a vertex from a graph by its ID or by the vertex object itself.
* @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID
* (`VertexKey`).
* @returns The method is returning a boolean value.
*/
override deleteVertex(vertexOrKey: VO | VertexKey): boolean {
let vertexKey: VertexKey;
let vertex: VO | undefined;
if (this.isVertexKey(vertexOrKey)) {
vertex = this.getVertex(vertexOrKey);
vertexKey = vertexOrKey;
} else {
vertex = vertexOrKey;
vertexKey = this._getVertexKey(vertexOrKey)
}
if (vertex) {
this._outEdgeMap.delete(vertex)
this._inEdgeMap.delete(vertex)
}
return this._vertices.delete(vertexKey);
}
/**
* Time Complexity: O(|E|) where |E| is the number of edges
* Space Complexity: O(1)

View file

@ -170,8 +170,70 @@ export class UndirectedGraph<
* @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 undefined if the edge was not found.
*/
deleteEdge(edge: EO): EO | undefined {
return this.deleteEdgeBetween(edge.vertices[0], edge.vertices[1]);
deleteEdge(edgeOrOneSideVertexKey: EO | VertexKey, otherSideVertexKey?: VertexKey): EO | undefined {
let oneSide: VO | undefined, otherSide: VO | undefined;
if (this.isVertexKey(edgeOrOneSideVertexKey)) {
if (this.isVertexKey(otherSideVertexKey)) {
oneSide = this._getVertex(edgeOrOneSideVertexKey);
otherSide = this._getVertex(otherSideVertexKey);
} else {
return;
}
} else {
oneSide = this._getVertex(edgeOrOneSideVertexKey.vertices[0]);
otherSide = this._getVertex(edgeOrOneSideVertexKey.vertices[1]);
}
if (oneSide && otherSide) {
return this.deleteEdgeBetween(oneSide, otherSide);
} else {
return;
}
}
/**
* Time Complexity: O(1) - Constant time for Map operations.
* Space Complexity: O(1) - Constant space, as it creates only a few variables.
*/
/**
* Time Complexity: O(1) - Constant time for Map operations.
* Space Complexity: O(1) - Constant space, as it creates only a few variables.
*
* The `deleteVertex` function removes a vertex from a graph by its ID or by the vertex object itself.
* @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID
* (`VertexKey`).
* @returns The method is returning a boolean value.
*/
override deleteVertex(vertexOrKey: VO | VertexKey): boolean {
let vertexKey: VertexKey;
let vertex: VO | undefined;
if (this.isVertexKey(vertexOrKey)) {
vertex = this.getVertex(vertexOrKey);
vertexKey = vertexOrKey;
} else {
vertex = vertexOrKey;
vertexKey = this._getVertexKey(vertexOrKey)
}
const neighbors = this.getNeighbors(vertexOrKey)
if (vertex) {
neighbors.forEach(neighbor => {
const neighborEdges = this._edges.get(neighbor);
if (neighborEdges) {
const restEdges = neighborEdges.filter(edge => {
return !edge.vertices.includes(vertexKey);
});
this._edges.set(neighbor, restEdges);
}
})
this._edges.delete(vertex);
}
return this._vertices.delete(vertexKey);
}
/**

View file

@ -650,5 +650,26 @@ describe('DirectedGraph iterative Methods', () => {
expect(dg.getEdge('hello', 'hi')).toBe(undefined)
expect(dg.getEdge('hello', 'hey')).toBeInstanceOf(DirectedEdge)
});
test('Removing a vertex from a UndirectedGraph should remove its edges', () => {
const dg = new DirectedGraph();
dg.addVertex('hello')
dg.addVertex('world')
dg.addVertex('earth')
dg.addEdge('hello', 'world')
dg.addEdge('hello', 'earth')
dg.addEdge('world', 'earth')
expect(dg.getEdge('hello', 'world')?.src).toBe('hello');
expect(dg.edgeSet().length).toBe(3)
expect(dg.edgeSet()[0].dest).toBe('world')
dg.deleteVertex('hello')
expect(dg.edgeSet().length).toBe(1)
expect(dg.edgeSet()?.[0].src).toBe('world')
expect(dg.getEdge('hello', 'world')).toBe(undefined);
})
});

View file

@ -173,6 +173,43 @@ describe('UndirectedGraph', () => {
expect(minWeightedPath?.minPath?.[3]?.key).toBe('Intersection_4');
expect(minWeightedPath?.minPath?.[4]?.key).toBe('Intersection_5');
});
test('Removing an edge of a UndirectedGraph should not delete additional edges', () => {
const dg = new UndirectedGraph();
dg.addVertex('hello')
dg.addVertex('hi')
dg.addVertex('hey')
dg.addEdge('hello', 'hi')
dg.addEdge('hello', 'hey')
expect(dg.getEdge('hello', 'hi')?.vertices[0]).toBe('hello')
expect(dg.getEdge('hello', 'hi')?.vertices[1]).toBe('hi')
expect(dg.getEdge('hello', 'hey')?.vertices[0]).toBe('hello')
expect(dg.getEdge('hello', 'hey')?.vertices[1]).toBe('hey')
dg.deleteEdge('hello', 'hi')
expect(dg.getEdge('hello', 'hi')).toBe(undefined)
expect(dg.getEdge('hello', 'hey')).toBeInstanceOf(UndirectedEdge)
});
test('Removing a vertex from a UndirectedGraph should remove its edges', () => {
const dg = new UndirectedGraph();
dg.addVertex('hello')
dg.addVertex('world')
dg.addVertex('earth')
dg.addEdge('hello', 'world')
dg.addEdge('hello', 'earth')
dg.addEdge('world', 'earth')
expect(dg.getEdge('hello', 'world')?.vertices[0]).toBe('hello');
expect(dg.edgeSet().length).toBe(3)
expect(dg.edgeSet()[0].vertices).toEqual(['hello', 'world'])
dg.deleteVertex('hello')
expect(dg.edgeSet().length).toBe(1)
expect(dg.edgeSet()?.[0].vertices[0]).toBe('world')
expect(dg.getEdge('hello', 'world')).toBe(undefined);
})
});
describe('cycles, strongly connected components, bridges, articular points in UndirectedGraph', () => {