diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index c65ca36..889c652 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -1086,15 +1086,33 @@ export abstract class AbstractGraph< } const cycles: Map = new Map(); - if (needCycles) { - let SCCs: Map = new Map(); - if (SCCs.size < 1) { - SCCs = getSCCs(); - } - SCCs.forEach((SCC, low) => { - if (SCC.length > 1) { - cycles.set(low, SCC); + if (needCycles) { + const visitedMap: Map = new Map(); + const stack: VO[] = []; + const findCyclesDFS = (cur: VO, parent: VO | undefined) => { + visitedMap.set(cur, true); + stack.push(cur); + + const neighbors = this.getNeighbors(cur); + + for (const neighbor of neighbors) { + if (!visitedMap.get(neighbor)) { + findCyclesDFS(neighbor, cur); + } else if (stack.includes(neighbor) && neighbor !== parent) { + const cycleStartIndex = stack.indexOf(neighbor); + const cycle = stack.slice(cycleStartIndex); + const cycleLow = Math.min(...cycle.map(v => dfnMap.get(v) || Infinity)); + cycles.set(cycleLow, cycle); + } + } + + stack.pop(); + }; + + vertexMap.forEach(v => { + if (!visitedMap.get(v)) { + findCyclesDFS(v, undefined); } }); } diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 775b237..60cf520 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -411,6 +411,13 @@ export class LinkedHashMap extends IterableEntryBase { } } + hasValue(value: V): boolean { + for (const [, elementValue] of this) { + if (elementValue === value) return true; + } + return false; + } + setMany(entries: Iterable<[K, V]>): void { for (const entry of entries) { const [key, value] = entry; diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index b4fc023..7e9b664 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -188,7 +188,7 @@ export class Queue extends IterableElementBase { * @param {E} value - The value parameter represents the value that you want to add to the queue. */ enqueue(value: E) { - this.push(value); + return this.push(value); } /** diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index f03da34..8559b49 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -588,7 +588,7 @@ describe('cycles, strongly connected components, bridges, articular points in Di const cutVertexes = graph.getCutVertexes(); const dfnMap = graph.getDFNMap(); const lowMap = graph.getLowMap(); - expect(cycles.size).toBe(1); + expect(cycles.size).toBe(2); expect(scCs.size).toBe(5); expect(bridges.length).toBe(4); expect(cutVertexes.length).toBe(4); @@ -673,3 +673,24 @@ describe('DirectedGraph iterative Methods', () => { }) }); +describe('DirectedGraph getCycles', () => { + test('should getCycles return correct result', () => { + const graph = new DirectedGraph(); + graph.addVertex('A'); + graph.addVertex('B'); + graph.addVertex('C'); + graph.addVertex('D'); + graph.addVertex('E'); + graph.addEdge('A', 'B'); + graph.addEdge('A', 'C'); + graph.addEdge('B', 'D'); + graph.addEdge('C', 'D'); + graph.addEdge('D', 'E'); + graph.addEdge('E', 'B'); + const cycles = graph.getCycles(); + expect(cycles.size).toBe(1); + + console.log(Array.from(cycles.values())); + }) +}) + diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 5292545..4624eb4 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -237,7 +237,7 @@ describe('cycles, strongly connected components, bridges, articular points in Un const cutVertexes = graph.getCutVertexes(); const dfnMap = graph.getDFNMap(); const lowMap = graph.getLowMap(); - expect(cycles.size).toBe(1); + expect(cycles.size).toBe(2); expect(scCs.size).toBe(5); expect(bridges.length).toBe(4); expect(cutVertexes.length).toBe(4); @@ -260,4 +260,24 @@ it("Should return Infinity if dest is not found", () => { const minCost01 = graph.getMinCostBetween(0, 1, true); expect(minCost01).toBe(1); -}); \ No newline at end of file +}); + +describe('UndirectedGraph getCycles', () => { + test('should getCycles return correct result', () => { + const graph = new UndirectedGraph(); + graph.addVertex('A'); + graph.addVertex('B'); + graph.addVertex('C'); + graph.addVertex('D'); + graph.addVertex('E'); + graph.addEdge('A', 'B'); + graph.addEdge('A', 'C'); + graph.addEdge('B', 'D'); + graph.addEdge('C', 'D'); + graph.addEdge('D', 'E'); + graph.addEdge('E', 'B'); + const cycles = graph.getCycles(); + expect(cycles.size).toBe(2); + console.log(Array.from(cycles.values())); + }) +}) \ No newline at end of file