拓扑排序 Topological Sort

AOV网介绍

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称AOV网(Activity On Vertex Network).
如图:
在这里插入图片描述
设G(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,…vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在顶点vj之间。则我们称这样的顶点序列为一个拓扑序列。

拓扑排序

拓扑排序,就是对一个有向图构造拓扑序列的过程。
构造时,会出现两种结果

  1. 如果此网的全部顶点都被输出,则说明它是不存在环(回路)的AOV网;
  2. 如果输出定点数少了,哪怕少了一个,也说明这个网存在回路,不是AOV网。

拓扑排序算法

对AOV网构建拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出,然后删除此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
拓扑排序适用的数据结构:邻接表(便于删除节点)
在这里插入图片描述
in存放入度,data存放数据,firstedge指向下一个元素

举栗

如图,给出一张AOV图
在这里插入图片描述
它的邻接表结构
在这里插入图片描述
先来看邻接矩阵的结构代码:

/*邻接矩阵结构*/
typedef struct
{
    
    
    VertexType vexs[MAXVEX];   /*vertex*/
    int arc[MAXVEX][MAXVEX];   /*邻接矩阵*/
    int numVertexes, numEdges; /*顶点个数,边个数*/
} MGraph;

再来看邻接表的结构代码:

//邻接表结构
typedef struct EdgeNode /*边表节点*/
{
    
    
    int adjvex;            /*邻接点域,存储该顶点对应的下标*/
    int weight;            //用于存储权值,非网图可不需要
    struct EdgeNode *next; //链域,指向下一个邻接点
} EdgeNode;

typedef struct VertexNode //定点表结点
{
    
    
    int in;              //顶点入度
    char data;           //顶点域,存储顶点信息
    EdgeNode *firstedge; //边表头指针
} VertexNode, AdjList[MAXVEX];

typedef struct
{
    
    
    AdjList adjList;
    int numVertexes, numEdges; //图中当前顶点数和边数
} graphAdjList, *GraphAdjList;

为了实现删除入度为0的顶点,我们同时需要辅助数据结构——栈
以下为拓扑排序的代码实现:

//拓扑排序,有环返回0,无环返回1并输出序列
Status TopologicalSort(GraphAdjList GL)
{
    
    
    EdgeNode *e;
    int i, k;
    char gettop;
    int top = 0;   //用于栈指针下标
    int count = 0; //用于统计输出顶点的个数
    char *stack;   //建立栈将入度为0的顶点入栈
    stack = (char *)malloc(GL->numVertexes * sizeof(char));//为栈分配内存空间
    for (i = 0; i < GL->numVertexes; i++)
        if (0 == GL->adjList[i].in)
            stack[++top] = vexs1[i]; //入度为0 的顶点入栈
    int index;
    while (top != 0)
    {
    
    
        gettop = stack[top--];
        for (int kk = 0; kk < MAXVEX; kk++)
            if (vexs1[kk] == gettop)
                index = kk;
        printf("%c -> ", GL->adjList[index].data);
        count++; //输出i顶点,并计数
        for (e = GL->adjList[find_index(gettop)].firstedge; e; e = e->next)
        {
    
    
            k = e->adjvex;
            if (!(--GL->adjList[k].in)) /*将i顶点的邻接点的入度减一,如果减一后等于0,则入栈*/
                stack[++top] = vexs1[k];
        }
    }
    printf("\n");
    if (count < GL->numVertexes)
        return ERROR;
    else
        return OK;
}

测试数据:

// G->arc[0][4] = 1;
    // G->arc[0][5] = 1;
    // G->arc[0][11] = 1;
    // G->arc[1][2] = 1;
    // G->arc[1][4] = 1;
    // G->arc[1][8] = 1;
    // G->arc[2][5] = 1;
    // G->arc[2][6] = 1;
    // G->arc[2][9] = 1;
    // G->arc[3][2] = 1;
    // G->arc[3][13] = 1;
    // G->arc[4][7] = 1;
    // G->arc[5][8] = 1;
    // G->arc[5][12] = 1;
    // G->arc[6][5] = 1;
    // G->arc[8][7] = 1;
    // G->arc[9][10] = 1;
    // G->arc[9][11] = 1;
    // G->arc[10][13] = 1;
    // G->arc[12][9] = 1;

完整代码:

#include <stdio.h>
#include <stdlib.h>

#include <math.h>
#include <time.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 14

typedef int Status; /*Status是函数返回值类型*/
typedef char VertexType;

VertexType vexs1[MAXVEX];
/*邻接矩阵结构*/
typedef struct
{
    
    
    VertexType vexs[MAXVEX];   /*vertex*/
    int arc[MAXVEX][MAXVEX];   /*邻接矩阵*/
    int numVertexes, numEdges; /*顶点个数,边个数*/
} MGraph;

//邻接表结构
typedef struct EdgeNode /*边表节点*/
{
    
    
    int adjvex;            /*邻接点域,存储该顶点对应的下标*/
    int weight;            //用于存储权值,非网图可不需要
    struct EdgeNode *next; //链域,指向下一个邻接点
} EdgeNode;

typedef struct VertexNode //定点表结点
{
    
    
    int in;              //顶点入度
    char data;           //顶点域,存储顶点信息
    EdgeNode *firstedge; //边表头指针
} VertexNode, AdjList[MAXVEX];

typedef struct
{
    
    
    AdjList adjList;
    int numVertexes, numEdges; //图中当前顶点数和边数
} graphAdjList, *GraphAdjList;

// function declaration
void CreateMGraph_matrix(MGraph *G);
void CreateMGraph_list(MGraph *G);
void CreateALGraph(MGraph G, GraphAdjList *GL);
Status TopologicalSort(GraphAdjList GL);
void menu();

void menu()
{
    
    
    printf("Please input the method you want to bulid a graph:\n");
    printf(" 1. Adjacent matrix   2. Adjacent list\n");
    int choice;
    scanf("%d", &choice);
}
void CreateMGraph_matrix(MGraph *G) //邻接矩阵法构建矩阵
{
    
    
    int i, j, k, value;
    G->numEdges = MAXEDGE;
    G->numVertexes = MAXVEX;
    G->arc[MAXVEX][MAXVEX] = {
    
    0};
    G->vexs[MAXVEX] = {
    
    '0'};
    printf("Please input number of vertexs and edges:\n");
    scanf("%d %d", &G->numVertexes, &G->numEdges);
    getchar();
    printf("please input your vertexs\n");
    for (i = 0; i < G->numVertexes; i++)
    {
    
    
        scanf("%c", &G->vexs[i]);
        vexs1[i] = G->vexs[i];
    }
    //初始化
    for (i = 0; i < G->numVertexes; i++)
        for (j = 0; j < G->numVertexes; j++)
            G->arc[i][j] = 0;
    for (k = 0; k < G->numEdges; k++)
    {
    
    
        printf("please input the value of(vi,vj):\n");
        scanf("%d %d %d", &i, &j, &value);
        G->arc[i][j] = value;
    }
    //打印邻接矩阵
    printf("The adjancent matirx is :\n");
    for (i = 0; i < G->numVertexes; i++)
    {
    
    
        for (j = 0; j < G->numVertexes; j++)
            printf("%d ", G->arc[i][j]);
        printf("\n");
    }
    // G->arc[0][4] = 1;
    // G->arc[0][5] = 1;
    // G->arc[0][11] = 1;
    // G->arc[1][2] = 1;
    // G->arc[1][4] = 1;
    // G->arc[1][8] = 1;
    // G->arc[2][5] = 1;
    // G->arc[2][6] = 1;
    // G->arc[2][9] = 1;
    // G->arc[3][2] = 1;
    // G->arc[3][13] = 1;
    // G->arc[4][7] = 1;
    // G->arc[5][8] = 1;
    // G->arc[5][12] = 1;
    // G->arc[6][5] = 1;
    // G->arc[8][7] = 1;
    // G->arc[9][10] = 1;
    // G->arc[9][11] = 1;
    // G->arc[10][13] = 1;
    // G->arc[12][9] = 1;
}

/*邻接矩阵构建邻接表*/
void CreateALGraph(MGraph G, GraphAdjList *GL)
{
    
    
    int i, j;
    EdgeNode *e;

    *GL = (GraphAdjList)malloc(sizeof(graphAdjList));

    (*GL)->numVertexes = G.numVertexes;
    (*GL)->numEdges = G.numEdges;
    for (i = 0; i < G.numVertexes; i++) //读入顶点信息,建立顶点表
    {
    
    
        (*GL)->adjList[i].in = 0;
        (*GL)->adjList[i].data = G.vexs[i];
        (*GL)->adjList[i].firstedge = NULL; //将边表置为空表
    }

    for (i = 0; i < G.numVertexes; i++) //建立边表
    {
    
    
        for (j = 0; j < G.numVertexes; j++)
        {
    
    
            if (G.arc[i][j] == 1)
            {
    
    
                e = (EdgeNode *)malloc(sizeof(EdgeNode));
                e->adjvex = j;                         //邻接序号为j
                e->next = (*GL)->adjList[i].firstedge; //将当前顶点上的指向的节点指针赋值给e
                (*GL)->adjList[i].firstedge = e;       //将当前顶点的指针指向e
                (*GL)->adjList[j].in++;
            }
        }
    }
}
int find_index(char s)
{
    
    
    for (int i = 0; i < MAXVEX; i++)
    {
    
    
        if (vexs1[i] == s)
            return i;
    }
    return 0;
}
//拓扑排序,有环返回0,无环返回1并输出序列
Status TopologicalSort(GraphAdjList GL)
{
    
    
    EdgeNode *e;
    int i, k;
    char gettop;
    int top = 0;   //用于栈指针下标
    int count = 0; //用于统计输出顶点的个数
    char *stack;   //建立栈将入度为0的顶点入栈
    stack = (char *)malloc(GL->numVertexes * sizeof(char));
    for (i = 0; i < GL->numVertexes; i++)
        if (0 == GL->adjList[i].in)
            stack[++top] = vexs1[i]; //入度为0 的顶点入栈
    int index;
    while (top != 0)
    {
    
    
        gettop = stack[top--];
        for (int kk = 0; kk < MAXVEX; kk++)
            if (vexs1[kk] == gettop)
                index = kk;
        printf("%c -> ", GL->adjList[index].data);
        count++; //输出i顶点,并计数
        for (e = GL->adjList[find_index(gettop)].firstedge; e; e = e->next)
        {
    
    
            k = e->adjvex;
            if (!(--GL->adjList[k].in)) /*将i顶点的邻接点的入度减一,如果减一后等于0,则入栈*/
                stack[++top] = vexs1[k];
        }
    }
    printf("\n");
    if (count < GL->numVertexes)
        return ERROR;
    else
        return OK;
}

int main(void)
{
    
    
    MGraph G;
    GraphAdjList GL;
    int result;
    CreateMGraph_matrix(&G);
    CreateALGraph(G, &GL);
    result = TopologicalSort(GL);
    printf("result:%d", result);

    return 0;
}

运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_52109814/article/details/121884306
今日推荐