Implements Khan's topological sorting algorithm as described on wikipedia: https://en.wikipedia.org/wiki/Topological_sorting

This commit is contained in:
max tang 2018-11-13 18:21:49 +13:00
parent 5e0e571a5c
commit 89c86e76fc
2 changed files with 89 additions and 0 deletions

View File

@ -0,0 +1,44 @@
import GraphVertex from '../../../../data-structures/graph/GraphVertex';
import GraphEdge from '../../../../data-structures/graph/GraphEdge';
import Graph from '../../../../data-structures/graph/Graph';
import topologicalSort from '../topologicalSortByCounting';
describe('topologicalSortByCounting', () => {
it('should do topological sorting on graph', () => {
const vertexNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
const edges = [
{ start: 'A', end: 'C' },
{ start: 'A', end: 'G' },
{ start: 'A', end: 'I' },
{ start: 'B', end: 'C' },
{ start: 'B', end: 'D' },
{ start: 'C', end: 'E' },
{ start: 'D', end: 'F' },
{ start: 'E', end: 'F' },
{ start: 'E', end: 'H' },
{ start: 'F', end: 'G' },
];
const nameToVertex = {};
const graph = new Graph(true);
vertexNames.forEach((name) => {
const vertex = new GraphVertex(name);
nameToVertex[name] = vertex;
});
edges.forEach((edge) => {
const startVertex = nameToVertex[edge.start];
const endVertex = nameToVertex[edge.end];
graph.addEdge(new GraphEdge(startVertex, endVertex));
});
const sortedVertices = topologicalSort(graph);
expect(sortedVertices).toBeDefined();
expect(sortedVertices.length).toBe(graph.getAllVertices().length);
graph.getAllEdges().forEach((edge) => {
expect(sortedVertices.indexOf(edge.startVertex))
.toBeLessThan(sortedVertices.indexOf(edge.endVertex));
});
});
});

View File

@ -0,0 +1,45 @@
import PriorityQueue from '../../../data-structures/priority-queue/PriorityQueue';
/**
* @param {Graph} graph
* Implements Khan's algorithms
*/
export default function topologicalSort(graph) {
// Count the preceders for all ndoes.
const precederCounts = {};
// Order nodes by number of preceders.
const priorityQueue = new PriorityQueue();
// The resulting sorted list.
const sortedStack = [];
// Initialize the counter array.
graph.getAllVertices().forEach((vertex) => {
precederCounts[vertex.getKey()] = 0;
});
// Count preceders for all nodes.
graph.getAllEdges().forEach((edge) => {
precederCounts[edge.endVertex.getKey()] = precederCounts[edge.endVertex.getKey()] + 1;
});
graph.getAllVertices().forEach((vertex) => {
priorityQueue.add(vertex, precederCounts[vertex.getKey()]);
});
while (!priorityQueue.isEmpty()) {
const vertex = priorityQueue.poll();
sortedStack.push(vertex);
vertex.getEdges().forEach((edge) => {
// Decrease counter for all child nodes.
precederCounts[edge.endVertex.getKey()] = precederCounts[edge.endVertex.getKey()] - 1;
// Update the information in priority queue.
priorityQueue.changePriority(edge.endVertex, precederCounts[edge.endVertex.getKey()]);
});
}
return sortedStack;
}