diff --git a/Graphs/TopoSortIterative.js b/Graphs/TopoSortIterative.js new file mode 100644 index 0000000000..1501009a86 --- /dev/null +++ b/Graphs/TopoSortIterative.js @@ -0,0 +1,47 @@ +import Queue from '../Data-Structures/Queue/Queue' +/** + * @author {RaviSadam} + * @name TopoSortIterative + * @description - + * Topological sorting algorithm implementation in JavaScript(Khan's Algorithm) + * @summary + * Topological sorting for Directed Acyclic Graph is a linear ordering of vertices + * such that for every directed edge u-v, vertex u comes before v in the ordering. + * + * @param graph - Graph (adjacency list) + * @returns {Array} - Gives null if graph has cycle otherwise result array + * + */ + +export function TopoSortIterative(graph) { + const n = graph.length + const inDegree = Array(n).fill(0) + const queue = new Queue() + const result = Array(n).fill(0) + let index = 0 + + for (const neighbors of graph) { + for (const neighbor of neighbors) { + inDegree[neighbor] += 1 + } + } + + for (let i = 0; i < n; i++) { + if (inDegree[i] === 0) { + queue.enqueue(i) + } + } + while (queue.length !== 0) { + const node = queue.dequeue() + result[index] = node + index += 1 + for (let neighbor of graph[node]) { + inDegree[neighbor] -= 1 + if (inDegree[neighbor] === 0) { + queue.enqueue(neighbor) + } + } + } + if (index !== n) return null + return result +} diff --git a/Graphs/TopoSortRecursive.js b/Graphs/TopoSortRecursive.js new file mode 100644 index 0000000000..1d77543b74 --- /dev/null +++ b/Graphs/TopoSortRecursive.js @@ -0,0 +1,59 @@ +function TopoSortRecursiveFunction(graph, visited, stack, path, vertex) { + //marking current vertex as visited + visited.add(vertex) + + //marking current vertex as being part of current path + path[vertex] = 1 + if (graph[vertex] && graph[vertex].length !== 0) { + for (const neighbor of graph[vertex]) { + //if neighbor is not visited then visit else continue + if (!visited.has(neighbor)) { + TopoSortRecursiveFunction(graph, visited, stack, path, neighbor) + } else if (path[neighbor] == 1) return + } + } + + //unmarking vertex + path[vertex] = 0 + + //visited all vertex coming after the current vertex + //so added to stack + stack.push(vertex) +} + +/** + * + * @author {RaviSadam} + * @name TopoSortRecursive + * @description - + * Topological sorting algorithm implementation in JavaScript + * @summary + * Topological sorting for Directed Acyclic Graph is a linear ordering of vertices + * such that for every directed edge u-v, vertex u comes before v in the ordering. + * + * @param graph - Graph (adjacency list) + * @returns {Array} - Gives null if graph has cycle otherwise result array + * + */ +export function TopoSortRecursive(graph) { + const n = graph.length + const stack = [] + //visited set for keep tracking of visited vertises + const visited = new Set() + + //path array for keep tacking of vertices + //visited in current path + + const path = Array(n).fill(0) + for (let i = 0; i < n; i++) { + if (!visited.has(i)) { + TopoSortRecursiveFunction(graph, visited, stack, path, i) + } + } + for (const value of path) { + if (value === 1) return null + } + //reverse the stack for getting exact topological order + stack.reverse() + return stack +} diff --git a/Graphs/test/TopoSortIterative.test.js b/Graphs/test/TopoSortIterative.test.js new file mode 100644 index 0000000000..b029580c84 --- /dev/null +++ b/Graphs/test/TopoSortIterative.test.js @@ -0,0 +1,14 @@ +import { TopoSortIterative } from '../TopoSortIterative' + +describe('Iterative Topological Sorting', () => { + test('Graph without cycle', () => { + const graph = [[], [], [3], [1], [0, 1], [0, 2]] + + expect(TopoSortIterative(graph, 6)).toEqual([4, 5, 0, 2, 3, 1]) + }) + test('Graph with cycle', () => { + const graph = [[2], [], [3, 5], [0, 1], [0, 2]] + + expect(TopoSortIterative(graph, 6)).toBe(null) + }) +}) diff --git a/Graphs/test/TopoSortRecursive.test.js b/Graphs/test/TopoSortRecursive.test.js new file mode 100644 index 0000000000..6f94f32368 --- /dev/null +++ b/Graphs/test/TopoSortRecursive.test.js @@ -0,0 +1,18 @@ +import { TopoSortRecursive } from '../TopoSortRecursive' + +describe('Recursive Topological Sorting', () => { + test('Graph without cycle', () => { + const graph = [[], [], [3], [1], [0, 1], [0, 2]] + + expect(TopoSortRecursive(graph, 6)).toEqual([5, 4, 2, 3, 1, 0]) + }) + test('Graph with cycle', () => { + const graph = [[2], [], [3, 5], [0, 1], [0, 2]] + + expect(TopoSortRecursive(graph, 6)).toBe(null) + }) + test('Graph with disconnected components', () => { + const graph = [[1, 2], [3], [3], [], [5], []] + expect(TopoSortRecursive(graph, 6)).toEqual([4, 5, 0, 2, 1, 3]) + }) +})