算法图解
拓扑排序是对DAG(有向无环图)上的节点进行排序。
拓扑排序最经典的算法是Kahn算法。首先,先拿出所有入度为0的点排在前面,并在原图中将它们删除:

代码实现
/*** @param {number} numCourses* @param {number[][]} prerequisites 邻接二维数组* @return {boolean}*/var canFinish = function (numCourses, prerequisites) {// 入度数组const inDegree = new Array(numCourses).fill(0);// 邻接表const map = {};for (let i = 0; i < prerequisites.length; i++) {// 求课的初始入度值inDegree[prerequisites[i][0]]++;// 当前课已经存在于邻接表if (map[prerequisites[i][1]]) {// 添加依赖它的后续课map[prerequisites[i][1]].push(prerequisites[i][0]);} else {// 当前课不存在于邻接表map[prerequisites[i][1]] = [prerequisites[i][0]];}}const queue = [];// 所有入度为0的课入列for (let i = 0; i < inDegree.length; i++) {if (inDegree[i] == 0) queue.push(i);}let count = 0;while (queue.length) {// 当前选的课,出列const selected = queue.shift();// 选课数+1count++;// 获取这门课对应的后续课const toEnQueue = map[selected];// 确实有后续课if (toEnQueue && toEnQueue.length) {for (let i = 0; i < toEnQueue.length; i++) {// 依赖它的后续课的入度-1inDegree[toEnQueue[i]]--;// 如果因此减为0,入列if (inDegree[toEnQueue[i]] == 0) {queue.push(toEnQueue[i]);}}}}// 选了的课等于总课数,true,否则falsereturn count == numCourses;};let numCourses = 2, prerequisites = [[1,0],[2,1]];let res = canFinish(numCourses, prerequisites);console.log(res);
返回值为是否成功进行拓扑排序,也即是否存在环。也就是说拓扑排序是可以用来简单地判环的。有时会要求输出字典序最小的方案这时把queue改成priority_queue即可,复杂度会多一个log。
