数据结构——拓扑排序(2)
拓扑排序
在实际生活中,许多任务之间存在依赖关系——比如“先修完基础课才能修专业课”“先完成零件生产才能组装产品”。这些依赖关系可以用“有向图”表示,其中顶点代表任务,有向边(u,v)(u, v)(u,v)表示“任务uuu完成后才能开始任务vvv”。拓扑排序就是对这种图的顶点进行排序,使得所有依赖关系都得到满足:对于任意有向边(u,v)(u, v)(u,v),uuu在排序结果中一定位于vvv之前。需要注意的是,只有有向无环图(DAG) 才能进行拓扑排序;若图中存在环(如“任务A依赖任务B,任务B依赖任务A”),则无法完成排序。
1. 拓扑排序的基本思想
拓扑排序的核心逻辑可以概括为“反复挑选没有前置依赖的任务,完成后移除其对后续任务的依赖”。具体来说,就是从图中找到“入度为0”的顶点(入度指指向该顶点的边的数量,入度为0表示没有前置任务),将其加入排序结果;然后删除该顶点及其所有出边(即移除它对后续任务的依赖),更新后续顶点的入度;重复这一过程,直到所有顶点都被加入排序结果,或确认图中存在环(此时仍有顶点未被加入)。
这个过程类似“剥洋葱”:最外层的“无依赖顶点”先被“剥下”,然后内层的顶点因依赖被移除而成为新的“无依赖顶点”,直到整个“洋葱”被剥完(或发现中间有无法剥下的部分,即环)。
2. 拓扑排序的过程(结合图示)
我们用一个具体的有向无环图来演示拓扑排序的过程。假设图中包含6个顶点V1V_1V1到V6V_6V6,有向边表示依赖关系:V1→V2V_1→V_2V1→V2、V1→V3V_1→V_3V1→V3、V2→V4V_2→V_4V2→V4、V3→V4V_3→V_4V3→V4、V4→V5V_4→V_5V4→V5、V4→V6V_4→V_6V4→V6(用mermaid绘制如下)。初始时,各顶点的入度为:V1V_1V1入度0,V2V_2V2入度1(受V1V_1V1依赖),V3V_3V3入度1(受V1V_1V1依赖),V4V_4V4入度2(受V2、V3V_2、V_3V2、V3依赖),V5V_5V5入度1(受V4V_4V4依赖),V6V_6V6入度1(受V4V_4V4依赖)。