数据结构与算法-拓扑排序

2020-05-14  本文已影响0人  卡布奇诺_95d2

一、定义

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV(Activity On Vertex Network)
注意:AOV网中不存在回路
设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列V1, V2,..., Vn满足若从顶点Vi到Vj有一条路径,则在顶点序列中,顶点Vi必须在顶点Vj之前,我们称这样的顶点序列为拓扑序列
拓扑排序其实就是对一个有向图构造拓扑序列的过程

二、算法思路

  1. 从AOV网中选择一个入度为0的顶点V0入输出。
  2. 删除V0结果,并删除以此顶点为尾的弧。
  3. 继续重复1、2步骤,直至输出全部顶点或者AOV网中不存在入度为0的顶点为止。
  4. 如果此网的顶点全部被输出,则说明它是不存在环路的AOV网,如果输出顶点数少了,哪怕是少了一个,也说明这个网存在环路,不是AOV网。

三、算法实现

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

/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Status;

/*邻接矩阵结构 */
typedef struct
{
    int vexs[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
}MGraph;


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

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

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


/*1.构成AOV网图*/
void CreateMGraph(MGraph *G)/* 构件图 */{
    int i, j;
    
    /* printf("请输入边数和顶点数:"); */
    G->numEdges=MAXEDGE;
    G->numVertexes=MAXVEX;
    
    /* 初始化图 */
    for (i = 0; i < G->numVertexes; i++)
    {
        G->vexs[i]=i;
    }
    
    /* 初始化图 */
    for (i = 0; i < G->numVertexes; i++)
    {
        for ( j = 0; j < G->numVertexes; j++)
        {
            G->arc[i][j]=0;
        }
    }
    
    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;
    
}

/*2.将AOV网图借助邻近矩阵转换成邻接表结构*/
void CreateALGraph(MGraph G,GraphAdjList *GL){
    (*GL) = (GraphAdjList)malloc(sizeof(graphAdjList));
    (*GL)->numVertexes = G.numVertexes;
    (*GL)->numEdges = G.numEdges;
    
    for(int i = 0; i<G.numVertexes; i++){
        (*GL)->adjList[i].in = 0;
        (*GL)->adjList[i].data = G.vexs[i];
        (*GL)->adjList[i].firstedge = NULL;
    }
    
    for(int i = 0; i<G.numVertexes; i++){
        for(int j = 0; j<G.numVertexes; j++){
            if(G.arc[i][j] == 1){
                EdgeNode* e = (EdgeNode*)malloc(sizeof(EdgeNode));
                e->adjvex = j;
                e->next = (*GL)->adjList[i].firstedge;
                (*GL)->adjList[i].firstedge = e;
                (*GL)->adjList[j].in++;
            }
        }
    }
}

/*3.拓扑排序. 若AOV网图无回路则输出拓扑排序的序列并且返回状态值1,若存在回路则返回状态值0*/
/*拓扑排序:解决的是一个工程能否顺序进行的问题!*/
Status TopologicalSort(GraphAdjList GL){
    //栈用于存储入度为0的顶点
    int* stack = (int *)malloc(GL->numVertexes * sizeof(int));
    int stackTop = 0;
    int count = 0;
    
    for(int i = 0; i<GL->numVertexes; i++){
        if(GL->adjList[i].in == 0){
            stack[++stackTop] = i;
        }
    }
    while(stackTop != 0){
        int i = stack[stackTop--];
        printf("%d ", i);
        count++;
        for(EdgeNode* p=GL->adjList[i].firstedge; p; p=p->next){
            GL->adjList[p->adjvex].in-- ;
            if(GL->adjList[p->adjvex].in == 0){
                stack[++stackTop] = p->adjvex;
            }
        }
    }
    printf("\n");
    if(count != GL->numVertexes)
        return ERROR;
    return OK;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, 拓扑排序!\n");
    MGraph G;
    GraphAdjList GL;
    int result;
    CreateMGraph(&G);
    CreateALGraph(G,&GL);
    result=TopologicalSort(GL);
    printf("result:%d",result);
    return 0;
}

四、算法复杂度
分析整个算法,对于一个具有n个顶点e条弧的AOV网来说,扫描顶点表,将入度为0的顶点入栈的时间复杂度为O(n),而之后的while循环中,每个顶点进一次栈出一次栈,入度减1的操作共执行了e次,因此整个时间复杂度为O(n+e)。

上一篇 下一篇

猜你喜欢

热点阅读