美文网首页
拓扑排序

拓扑排序

作者: lxr_ | 来源:发表于2022-09-03 16:25 被阅读0次

拓扑排序:

  • 前面说的是有环的图的应用,下面介绍有向无环图的应用,简称DAG图(Directed Acycline Graph),如下图所示。
    有向无环图
  • 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网(Activity On Vertex Network)。
  • 设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,……,vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必须在vj之前,称这样的序列为拓扑序列
  • 所谓拓扑排序,其实就是对一个有向图构造拓扑序列的过程。如果此网的全部顶点都被输出,则说明它是不存在环的AOV网,如果输出顶点少了,说明这个网存在环,不是AOV网。
  • 算法:从AOV网中选择一个入度为0的顶点输出,然后删除此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。

代码示例

由于需要删除顶点,故采用邻接表结构较为方便,且在原来的顶点结构中添加一个入度域记录该顶点的入度。
ALGraph.h

#pragma once

#define MAXVEX 100
typedef char VertexType;        //顶点类型
typedef int EdgeType;           //边上的权值类型

struct EdgeNode                 //边表结点
{
    int adjvex;                 //邻接点域,存储该节点对应的下标

    EdgeType weight;            //存储权值,非网图不需要
    EdgeNode* next;             //下一个邻接点
};

typedef struct VertexNode
{
    int in;                     //添加一个入度域
    VertexType data;            //顶点

    EdgeNode* firstEdge;        //边表头指针
}AdjList[MAXVEX];               //顶点数组

struct GraphAdjList
{
    AdjList adjList;            //顶点数组
    int numVertexes, numEdges;  //实际图中顶点数和边数
};

//建立有向图的邻接表结构
void CreateALGraph(GraphAdjList& G);

//根据顶点名称查找其下标
int locateVertex(GraphAdjList G, VertexType v);

//拓扑排序
void TopologicalSort(GraphAdjList G);

ALGraph.cpp

#include "ALGraph.h"

#include <iostream>
#include <stack>

using namespace std;

//建立有向无环图的邻接表结构
void CreateALGraph(GraphAdjList& G)
{
    cout << "请输入顶点个数和边个数:" << endl;
    cin >> G.numVertexes >> G.numEdges;

    cout << "请输入" << G.numVertexes << "个顶点:" << endl;
    for (int i = 0; i < G.numVertexes; i++)
    {
        cin >> G.adjList[i].data;
        G.adjList[i].in = 0;
        G.adjList[i].firstEdge = NULL;
    }

    cout << "请输入" << G.numEdges << "条边:" << endl;

    VertexType vertex1, vertex2;
    int m, n;
    int edge;
    for (int i = 0; i < G.numEdges; i++)
    {
        cin >> vertex1 >> vertex2 >> edge;      //输入边及其依附的两个顶点

        m = locateVertex(G, vertex1);           //弧的起点
        n = locateVertex(G, vertex2);           //弧的终点

        if (m >= 0 && n >= 0)
        {
            //创建一个新的边结点
            EdgeNode* e = new EdgeNode;
            e->weight = edge;
            e->adjvex = n;
            e->next = G.adjList[m].firstEdge;   //头插法插入顶点的firstedge
            G.adjList[m].firstEdge = e;
            G.adjList[n].in++;                  //更新入度

        }
    }
}

//根据顶点名称查找其下标
int locateVertex(GraphAdjList G, VertexType v)
{
    for (int i = 0; i < G.numVertexes; i++)
    {
        if (v == G.adjList[i].data)
        {
            return i;
        }
    }
    return -1;
}

//拓扑排序
void TopologicalSort(GraphAdjList G)
{
    stack<int> s;                                   //存放入度为0的顶点,只对该栈中的顶点进行操作
    for (int i = 0; i < G.numVertexes; i++)
    {
        if (G.adjList[i].in == 0)
        {
            s.push(i);
        }
    }

    int count = 0;                                  //统计输出顶点个数
    while (!s.empty())                              //栈不为空则继续
    {
        int x = s.top();
        cout << G.adjList[x].data << " ";           //输出顶点
        count++;
        s.pop();                                    //出栈然后删除此顶点及对应的边

        EdgeNode* e = G.adjList[x].firstEdge;       //第一条边
        while (e)
        {
            if (!(--G.adjList[e->adjvex].in))       //要删除的边对应的顶点入度减一,如果为0,则入栈
            {
                s.push(e->adjvex);
            }

            e = e->next;
        }
    }

    if (count != G.numVertexes)
    {
        cout << "Sort Error" << endl;
    }
    else
    {
        cout << "Sort Success" << endl;
    }
}

main.cpp

#include "ALGraph.h"

#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
    GraphAdjList ALG;
    CreateALGraph(ALG);                 //创建有向无环图
    TopologicalSort(ALG);

    /*
    B A 1
    C B 1
    D B 1
    C D 1
    */
    return 0;
}

相关文章

网友评论

      本文标题:拓扑排序

      本文链接:https://www.haomeiwen.com/subject/pzpynrtx.html