图的拓扑排序

相关概念

AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网(Activity On Vertex)。
AVO网不存在环路

拓扑序列:设G=(V,E)是一个具有n个顶点的有向图,V中顶点序列V1,V2,......,Vn,满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前,则这样的顶点序列称为一个拓扑序列。
拓扑序列并不唯一

拓扑排序就是构造拓扑序列的过程,当AOV网中不存在环路时,全部顶点都会被输出。

拓扑排序算法

思想:从AOV网中选择一个入度为0的顶点输出,然后删除此顶点,并删除一次顶点为尾的弧,继续重复该步骤,直至输出全部顶点或者AOV网中不存在入度为0的顶点为止。

由于拓扑排序需要删除顶点,所以使用邻接表的方式存储图会较为方便

邻接表结构

邻接表结构图.png

邻接表的结构不局限于此,可以根据实际情况添加字段,如在拓扑排序中可以在顶点表中增加入度字段,用于统计每个顶点的入度情况。在带权图中可以在边表中添加weight字段,用于表示每条边的权值。

测试图:


测试图.png

对应的邻接表结构:


邻接表.png

源代码

顶点表类

/**
 * 顶点表结点类
 * 
 * @author Shaw
 *
 */
class VertexNode {
    // 顶点入度
    private int in;
    // 顶点域
    private String data;
    // 指向边表
    private EdgeNode firstEdge;

    public VertexNode(int in, String data, EdgeNode firstEdge) {
        super();
        this.in = in;
        this.data = data;
        this.firstEdge = firstEdge;
    }

    public int getIn() {
        return in;
    }

    public void setIn(int in) {
        this.in = in;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public EdgeNode getFirstEdge() {
        return firstEdge;
    }

    public void setFirstEdge(EdgeNode firstEdge) {
        this.firstEdge = firstEdge;
    }
}

边集表类:

/**
 * 拓扑排序
 * 
 * @author Shaw
 *
 */
public class Topological {
    private List<VertexNode> verList;

    //建图
    public void buildAovGraph() {
        VertexNode v0 = new VertexNode(0, "v0", null);

        EdgeNode v0e1 = new EdgeNode(11, 0, null);
        EdgeNode v0e2 = new EdgeNode(5, 0, null);
        EdgeNode v0e3 = new EdgeNode(4, 0, null);

        v0.setFirstEdge(v0e1);
        v0e1.setNext(v0e2);
        v0e2.setNext(v0e3);

        VertexNode v1 = new VertexNode(0, "v1", null);

        EdgeNode v1e1 = new EdgeNode(8, 0, null);
        EdgeNode v1e2 = new EdgeNode(4, 0, null);
        EdgeNode v1e3 = new EdgeNode(2, 0, null);

        v1.setFirstEdge(v1e1);
        v1e1.setNext(v1e2);
        v1e2.setNext(v1e3);

        VertexNode v2 = new VertexNode(0, "v2", null);

        EdgeNode v2e1 = new EdgeNode(9, 0, null);
        EdgeNode v2e2 = new EdgeNode(6, 0, null);
        EdgeNode v2e3 = new EdgeNode(5, 0, null);

        v2.setFirstEdge(v2e1);
        v2e1.setNext(v2e2);
        v2e2.setNext(v2e3);

        VertexNode v3 = new VertexNode(0, "v3", null);

        EdgeNode v3e1 = new EdgeNode(13, 0, null);
        EdgeNode v3e2 = new EdgeNode(2, 0, null);

        v3.setFirstEdge(v3e1);
        v3e1.setNext(v3e2);

        VertexNode v4 = new VertexNode(0, "v4", null);

        EdgeNode v4e1 = new EdgeNode(7, 0, null);

        v4.setFirstEdge(v4e1);

        VertexNode v5 = new VertexNode(0, "v5", null);

        EdgeNode v5e1 = new EdgeNode(12, 0, null);
        EdgeNode v5e2 = new EdgeNode(8, 0, null);

        v5.setFirstEdge(v5e1);
        v5e1.setNext(v5e2);

        VertexNode v6 = new VertexNode(0, "v6", null);

        EdgeNode v6e1 = new EdgeNode(5, 0, null);

        v6.setFirstEdge(v6e1);

        VertexNode v7 = new VertexNode(0, "v7", null);

        VertexNode v8 = new VertexNode(0, "v8", null);

        EdgeNode v8e1 = new EdgeNode(7, 0, null);

        v8.setFirstEdge(v8e1);

        VertexNode v9 = new VertexNode(0, "v9", null);

        EdgeNode v9e1 = new EdgeNode(11, 0, null);
        EdgeNode v9e2 = new EdgeNode(10, 0, null);

        v9.setFirstEdge(v9e1);
        v9e1.setNext(v9e2);

        VertexNode v10 = new VertexNode(0, "v10", null);

        EdgeNode v10e1 = new EdgeNode(13, 0, null);

        v10.setFirstEdge(v10e1);

        VertexNode v11 = new VertexNode(0, "v11", null);

        VertexNode v12 = new VertexNode(0, "v12", null);

        EdgeNode v12e1 = new EdgeNode(9, 0, null);

        v12.setFirstEdge(v12e1);

        VertexNode v13 = new VertexNode(0, "v13", null);

        verList = new ArrayList<>();
        verList.add(v0);
        verList.add(v1);
        verList.add(v2);
        verList.add(v3);
        verList.add(v4);
        verList.add(v5);
        verList.add(v6);
        verList.add(v7);
        verList.add(v8);
        verList.add(v9);
        verList.add(v10);
        verList.add(v11);
        verList.add(v12);
        verList.add(v13);

    }

    public void topological_sort() {
        Stack<Integer> stack = new Stack<>();
        int count = 0;
        // 初始化所有顶点表结点的入度值
        for (int i = 0; i < verList.size(); i++) {
            EdgeNode edgeNode = verList.get(i).getFirstEdge();
            while (edgeNode != null) {
                //边集表中出现的下标(adjvex)所对应的顶点入度加1
                VertexNode vertexNode = verList.get(edgeNode.getAdjvex());
                vertexNode.setIn(vertexNode.getIn() + 1);
                edgeNode = edgeNode.getNext();
            }
        }
        // 将所有入度为0的顶点入栈
        for (int i = 0; i < verList.size(); i++) {
            if (verList.get(i).getIn() == 0) {
                stack.push(i);
            }
        }

        while (!stack.isEmpty()) {
            // 从栈中弹出一个入度为0的顶点
            int vertex = stack.pop();
            System.out.print(verList.get(vertex).getData() + " -> ");
            count++;
            // 获取弹出的顶点指向的第一个边结点
            EdgeNode edgeNode = verList.get(vertex).getFirstEdge();
            while (edgeNode != null) {
                // 获取边表结点的Adjvex值,该值存储对应顶点表结点的下标值
                int adjvex = edgeNode.getAdjvex();
                // 获取边表结点指向的顶点表结点
                VertexNode vertexNode = verList.get(adjvex);
                // 删除边结点,也就是将对应的顶点表结点的入度减1
                vertexNode.setIn(vertexNode.getIn() - 1);
                // 如果该顶点表结点入度为0时压栈
                if (vertexNode.getIn() == 0) {
                    stack.push(adjvex);
                }
                // 获取下一个边表结点的值
                edgeNode = edgeNode.getNext();
            }
        }
    }
}

测试程序:

public class TopologicalMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Topological topological = new Topological();
        topological.buildAovGraph();
        topological.topological_sort();
    }

}

测试结果:


拓扑排序结果图.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 引言 工程中尝尝氛围很多步骤完成,有些步骤可以同步进行,而有些步骤需要某些步骤完成后才能进行,如何安排它们的流程是...
    kakaxicm阅读 1,023评论 0 0
  • 拓扑排序:对一个有向图构造拓扑序列的过程。 关键概念定义 拓扑序列:设G=(V,E)是一个具有n个顶点的有向图,V...
    lkmc2阅读 1,121评论 0 1
  • 1. 图的定义和基本术语 线性结构中,元素仅有线性关系,每个元素只有一个直接前驱和直接后继;树形结构中,数据元素(...
    yinxmm阅读 5,435评论 0 3
  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,760评论 0 19
  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,708评论 0 13