定义
设
G=(V,{E})
是一个具有
n
个顶点的有向图,
拓扑排序:对一个有向图构造拓扑序列的过程。
AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称之为 AOV网。(Activity On Vertex Network)
构造拓扑序列,如果网的全部顶点都被输出,则说明这个网是不存在环(回路)的AOV网;如果输出顶点少了,说明这个网存在环(回路),不是AOV网。
基本思想
- 在有向图中选一个入度为0 (没有前驱)的顶点输出;
- 从图中删除该顶点和所有以它为尾的弧(即:删除所有指向它的边);
- 重复上述两步,直至所有顶点输出,或者当前图中不存在入度为0(没有前驱)的顶点为止,后者说明有向图有环。
因此,也可以通过拓扑排序来判断一个图是否有环。
实现
构造图类
构造:
在拓扑排序中,需要删除顶点,用邻接表更方便。
function Graph(v) {
this.v = [];
for (var i in v) {
this.v[i] = {
data: v[i],
in: 0 /* 增加一个入度属性 */
}
}
this.e = [];
for (var i = 0; i < this.v.length; i++) {
this.e[i] = [];
}
}
Graph.prototype.addEdge = function (v1, v2) {
this.v[v2].in++; /* 弧尾顶点的入度加一 */
this.e[v1].push(v2);
}
测试代码:
构建一个如下图所示的有向图
var v= [0,1,2,3,4,5,6,7,8,9,10,11,12,13];
var g = new Graph(v);
g.addEdge(0,11);g.addEdge(0,5);g.addEdge(0,4);
g.addEdge(1,8);g.addEdge(1,4);g.addEdge(1,2);
g.addEdge(2,9);g.addEdge(2,6);g.addEdge(2,5);
g.addEdge(3,13);g.addEdge(3,2);
g.addEdge(4,7);
g.addEdge(5,12);g.addEdge(5,8);
g.addEdge(6,5);
g.addEdge(8,7);
g.addEdge(9,11);g.addEdge(9,10);
g.addEdge(10,13);
g.addEdge(12,9);
console.log(g);
结果:
拓扑排序算法
需要一个栈来存储处理过程中入度为 0 的顶点。(目的:避免每个查找时都要去遍历顶点表找没有入度为 0 的顶点)
算法:
Graph.prototype.TopoSort= function () {
var count = 0; /* 统计输出顶点的个数 */
var stack = []; /* 建栈存储入度为 0 的顶点*/
for(var i in this.v){
if(this.v[i].in === 0){
stack.push(this.v[i].data); /* 将入度为 0 的顶点入栈*/
}
}
console.group("输出顶点序列如下:");
while(stack.length!=0){
var gettop = stack.pop();
console.log(this.v[gettop].data); /* 打印出栈顶点 */
count++; /* 统计输出顶点数 */
for(var i in this.e[gettop]){ /* 对此顶点弧表遍历 */
var k = this.e[gettop][i];
if(!(--this.v[k].in)){ /* 将 k 顶点邻接点入度减一 */
stack.push(k); /* 若为 0 则入栈 */
}
}
}
console.groupEnd();
if(count<this.v.length){
console.log("此有向图有环。");
}else{
console.log("此有向图无环。");
}
}
测试代码:
g.TopoSort();
结果: