diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index d8fc433..8e516ae 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -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) diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index b11665b..8246a2d 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -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); } /** diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index ab4a16c..acbc7bf 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -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); + }) }); diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 0d966f1..d6b99cc 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -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', () => {