拓扑排序

1.AOV网

  如果用图中的顶点表示活动,边表示活动之间的先后关系,比如从顶点Vi到Vj之间存在有向边<Vi,Vj>,则表示活动活动Vi必须在活动Vj之前进行,这样用弧表示优先关系的有向图称为顶点表示活动的网(Activity On Vertex NetWork),简称AOV网。

  如下图:

  

  

  说明:AOV网中不含回路,因为存在回路意味着某项活动应以自己为先决条件,显然这是荒谬的。你想嘛,一件事必须等该件事做完了才开始做,那这件事到底什么时候做呢?答案是无穷无尽的等待,死循环。

2.拓扑排序

  对于一个AOV网,其所有顶点可以排成一个线性序列Vi1,Vi2,Vi3,...,Vin,该线性序列具有以下性质:如果在AOV网中,从顶点Vi到顶点Vj存在一条路径,则在该序列中顶点Vi一定排在顶点Vj之前,具有这种性质的线性序列称为拓扑序列,构造拓扑序列的操作称之为拓扑排序。

  那么如何进行拓扑排序呢?

  ①在有向图中选取一个没有前驱的顶点并输出

  ②从图中删除该顶点和所有以它为尾的弧

 

 
 AOV网,初始状态
                              输出V1之后
                      输出V2之后
                 输出V3之后(V3和V4都满足入度为零的条件,所以先选哪个都没关系)
                             输出V4之后

 

  

3.编码实现

  采用邻接表存储有向图:

  arcNode结构体存储为以adjvex为弧头的弧的相关信息

  vNode存储节点信息并指向第一个出边

  topoSequence存储拓扑排序中输出的顶点

  findIndegree查找所有顶点的入度:从第0号位置开始查找,遇到以adjvex为弧头的弧对应的indegree就加一,这样查找完后,indegree中就记录了每个顶点的入读

  topologicalSort进行拓扑排序

  

  

#include<stdio.h>
#include<stdlib.h>
typedef struct _arcNode
{
    int adjvex;
    int weight;
    struct _arcNode *nextarc;
}arcNode;
typedef struct  _vNode
{
    char data;
    arcNode *firstarc;
}vNode;
#define  MaxVertexNum 100
typedef vNode adjList[MaxVertexNum];
typedef struct _adjGraph
{
    adjList ver;
    int e, n;
}adjGraph;
void createAdjGraph(adjGraph *G)
{
    scanf("%d,%d", &G->n, &G->e);
    getchar();
    for (int i = 0; i < G->n; i++)
    {
        scanf("%c ", &G->ver[i].data);
        G->ver[i].firstarc = NULL;
    }
    int a, b, w;
    for (int i = 0; i < G->e; i++)
    {
        scanf("%d,%d,%d", &a, &b, &w);
        arcNode *tmp = (arcNode*)malloc(sizeof(arcNode));
        tmp->weight = w;
        if (G->ver[a].firstarc == NULL)
        {
            tmp->adjvex = b;
            tmp->nextarc = NULL;
            G->ver[a].firstarc = tmp;
        }
        else
        {
            tmp->adjvex = b;
            tmp->nextarc = G->ver[a].firstarc;
            G->ver[a].firstarc = tmp;
        }
    }
}
typedef struct  _topoSequenceS
{
    char data[MaxVertexNum];
    int top;
}topoSequenceS;
topoSequenceS *topoS = (topoSequenceS*)malloc(sizeof(topoSequenceS));
void findInDegree(adjGraph *G, int *indegree)
{
    for (int i = 0; i < G->n; i++)
    {
        arcNode *arcPos = G->ver[i].firstarc;
        while (arcPos != NULL)
        {
            indegree[arcPos->adjvex] += 1;
            arcPos = arcPos->nextarc;
        }
    }
}
void topologicalSort(adjGraph *G)
{
    int *indegree = (int*)malloc(sizeof(int)*G->n);
    for (int i = 0; i < G->n; i++)
        indegree[i] = 0;
    findInDegree(G, indegree);
    int *tmpS = (int*)malloc(sizeof(int)*G->n);
    int top = -1;
    for (int i = 0; i < G->n; i++)
    {
        if (!indegree[i])tmpS[++top] = i;
    }
    topoS->top = -1;
    int i = 0;
    while (top != -1)
    {
        i=topoS->data[++topoS->top] = tmpS[top--];
        arcNode *arcPos = G->ver[i].firstarc;
        while (arcPos != NULL)
        {
            if (!(--indegree[arcPos->adjvex]))tmpS[++top] = arcPos->adjvex;
            arcPos = arcPos->nextarc;
        }
    }
}
#include<conio.h>
int main(void)
{
    freopen(".\\in.txt", "r", stdin);
    adjGraph *G = (adjGraph*)malloc(sizeof(adjGraph));

    createAdjGraph(G);
    fclose(stdin);
    for (int i = 0; i < G->n; i++)
    {
        printf("%c->", G->ver[i].data);
        arcNode *pos = G->ver[i].firstarc;
        while (pos != NULL)
        {
            printf("%c->", G->ver[pos->adjvex].data);
            pos = pos->nextarc;
        }
        printf("\n");
    }
    topologicalSort(G);
    if (topoS->top < G->n - 1)
        printf("Error!There is a circuit!\n");
    else
    {
        int vexNum = 0;
        int pos = 0;
        while (topoS->top != pos-1)
        {
            vexNum = topoS->data[pos];
            printf("%c\n", G->ver[vexNum].data);
            pos++;
        }
    }
    getch();
    return 0;
}

  

  测试文本in.txt:

5,5
A B C D E
0,1,1
1,2,2
1,3,3
2,4,4
3,4,5

测试结果:

  

  

 

转载于:https://www.cnblogs.com/GaussianPrince/p/6147427.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值