mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-09-20 07:43:04 +08:00
Implements Khan's topological sorting algorithm as described on wikipedia: https://en.wikipedia.org/wiki/Topological_sorting
This commit is contained in:
parent
5e0e571a5c
commit
89c86e76fc
@ -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));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user