66-拓扑排序

1. 什么是拓扑排序

  设G=(V,E)是一个具有n个顶点的有向图,若< vi,vj >是图中的边(即从顶点vi到vj有一条路径),则顶点vi必须排在顶点vj之前,那么满足这个条件的顶点序列就是拓扑序列。在一个有向图中找一个拓扑序列的过程就称为拓扑排序。


我们通过一个例子来举例说明。

这里写图片描述
图1

  比如,计算机专业的学生必须完成一系列规定的基础课和专业课才能毕业,有一些课程会有一些先修课程。例如高等数学和程序设计这两门课程来说,是没有先修课的,而对于数据结构这门课程来1说,在学习这门课之前必须先修程序设计和离散数学两门课,而在学习离散数学时,还需要先修高等数学课程。



对于课程之间的先后关系用一个有向图来表示:

这里写图片描述
图2

  从图2中可以看出,一个有向图的拓扑排序可以有好几种,比如< C0,C2 >有一条边,那么C0就必须在C2的前面,对于< C1,C6 >有一条边,那么C1必须在C6的前面。而对于C0和C1之间没有边的,那么C0和C1谁在前,谁在后都可以的。


2. 数据的存储结构

这里写图片描述
图3

有向图的存储结构定义:

typedef struct ANode
{
    int adjvex;
    InfoType info;
    struct ANode *nextarc;
} ArcNode; //边表节点类型


typedef struct Vnode
{
Vertex data;
    int count;  //存放顶点入度
    ArcNode *firstarc;
} VNode; //表头节点类型


typedef VNode AdjList[MAXV];
typedef struct
{
    AdjList adjlist;
    int n,e;
} ALGraph; //完整的图邻接表类型

3. 拓扑排序步骤

1 . 从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它。

2 . 从图中删去该顶点,并且删去从该顶点发出的全部有向边。

3 . 重复上述两步,直到剩余的网中不再存在没有前驱的顶点为止。



这里写图片描述
图4

  如图4所示,对于图G来说,C0和C1的入度都是为0的,这里我们选择C0开始,把顶点C0删除掉,并删除从C0出发的所有出边。



这里写图片描述
图5

如图5所示,然后选择C2开始,把C2顶点删除掉,并删除从C2出发的所有出边。



这里写图片描述
图6

如图6所示,再选择C1开始,把C1顶点删除掉,并删除从C1出发的所有出边。



这里写图片描述
图7

再选择C6开始,把C6顶点删除掉,并删除从C6出发的所有出边。



这里写图片描述
图8

再选择C3开始,把C3顶点删除掉,并删除从C3出发的所有出边。



这里写图片描述
图9

最后依次选择C5,C4顶点全部都删除掉。

4. 拓扑排序算法

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

#define MAXV 7

typedef int InfoType;

typedef struct ANode
{
    int adjvex;
    InfoType info;
    struct ANode *nextarc;
} ArcNode; //边表节点类型


typedef int Vertex;

typedef struct Vnode
{
    Vertex data;
    int count;  //存放顶点入度
    ArcNode *firstarc;
} VNode; //表头节点类型


typedef VNode AdjList[MAXV];
typedef struct
{
    AdjList adjlist;
    int n,e;
} ALGraph; //完整的图邻接表类型


//图的定义:邻接矩阵
typedef struct MGRAPH{
    int n;                  //顶点数
    int e;                  //边数
    int deges[MAXV][MAXV];  //邻接矩阵
} MGraph;


/*
将邻接矩阵转换成邻接表
MGraph *g:表示邻接矩阵
*/
ALGraph *MatToList(MGraph *g)
{
    int i;
    int j;
    ArcNode *p = NULL;
    ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph));

    //给所有头节点的指针域置初值
    for(i = 0; i < g->n; i++)
    {
        G->adjlist[i].firstarc = NULL;
    }

    //根据邻接矩阵建立邻接表中节点
    for(i = 0; i < g->n; i++)
    {
        for(j = g->n - 1; j >= 0; j--)
        {
            if(g->deges[i][j] != 0)
            {
                p = (ArcNode *)malloc(sizeof(ArcNode));
                p->adjvex = j;
                //采用头插法,插入邻接表
                p->nextarc = G->adjlist[i].firstarc;
                G->adjlist[i].firstarc = p;
            }
        }
    }
    G->n = g->n;
    G->e = g->e;

    return G;
}

//拓扑排序算法
void TopSort(ALGraph *G)
{
    int i,j;
    int top;
    ArcNode *p;
    //先初始化
    for (i=0; i<G->n; i++)
    {
        G->adjlist[i].count=0;
    }

    //求所有顶点的入度
    for (i=0; i<G->n; i++)
    {
        p=G->adjlist[i].firstarc;
        while (p!=NULL)
        {
            G->adjlist[p->adjvex].count++;
            p=p->nextarc;
        }
    }


    //入栈度为0的顶点
    int St[MAXV];
    top=-1;
    for (i=0; i<G->n; i++)
    {
        if (G->adjlist[i].count==0)
        {
            top++;
            St[top]=i; 
        }
    }

    while (top>-1) //栈不为空时循环
    {
        //出栈并输出
        i=St[top];
        top--;
        printf("%d ",i);

        //"删除"顶点,同时把相邻顶点入度均减1
        //比如在删除顶点1来说,需要把顶点3,4,6的入度都-1
        p=G->adjlist[i].firstarc;
        while (p!=NULL)
        {   //记录相邻的顶点
            j=p->adjvex;
            //并把相邻的顶点的入度-1
            G->adjlist[j].count--;
            //如果该相邻的顶点入度减一后为零的话,则需要入栈
            if (G->adjlist[j].count==0) 
            {
                top++;
                St[top]=j; 
            }
            //找下一个相邻的顶点
            p=p->nextarc;
        }    
    }
}




int main(void)
{

    int A[7][7] = {
                    {0,0,1,0,0,0,0},
                    {0,0,0,1,1,0,1},
                    {0,0,0,1,0,0,0},
                    {0,0,0,0,1,1,0},
                    {0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0},
                    {0,0,0,0,0,1,0}

                    };

    int i;
    int j;
    MGraph g;
    ALGraph *ag = NULL;
    g.e = 8;
    g.n = 7;

    //转换为邻接矩阵
    for(i = 0; i < g.n; i++)
    {
        for(j = 0; j < g.n; j++)
        {
            g.deges[i][j] = A[i][j];
        }
    }

    //转换为邻接表
    ag = MatToList(&g);

    printf("\n拓扑排序: ");
    //拓扑排序
    TopSort(ag);
    printf("\n\n");
    return 0;
}

测试结果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_35733751/article/details/81315846
今日推荐