【图】拓扑排序

定义

G=(V,{E}) 是一个具有 n 个顶点的有向图,V中的顶点序列 v1,v2,...,vn 满足若从顶点 vi vj 有一条路径,则在顶点序列中顶点 vi 必在顶点 vj 之前。则称这样的顶点序列为一个拓扑序列

拓扑排序:对一个有向图构造拓扑序列的过程。
AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称之为 AOV网。(Activity On Vertex Network)

构造拓扑序列,如果网的全部顶点都被输出,则说明这个网是不存在环(回路)的AOV网;如果输出顶点少了,说明这个网存在环(回路),不是AOV网。

基本思想

  1. 在有向图中选一个入度为0 (没有前驱)的顶点输出;
  2. 从图中删除该顶点和所有以它为尾的弧(即:删除所有指向它的边);
  3. 重复上述两步,直至所有顶点输出,或者当前图中不存在入度为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();

结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值