拓扑排序~C语言完整代码

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
拿个例子来说,比如下面一张图:
拓扑排序~C语言完整代码_第1张图片
上面的图中的1的顶点的入度为0,先去掉1顶点,去掉1顶点进入其他顶点的边(去掉1->2,去掉1->3),这时2和3d的顶点的入度
变为0,去掉2顶点,去掉(2->4)边,去掉3顶点,去掉(3->4)边,注意到4这个顶点的时候就出现了环,而拓扑排序计算的是有向无环图,有环的话是计算不出拓扑排序的。就好像是4代表C语言课程,4是离散数学,6是数据结构,咱们先认定先学C语言课程和离散数学才能学数据结构,像下面的图那样。
拓扑排序~C语言完整代码_第2张图片
如果反过的话就违背之前的规定,打乱了顺序而导致不知道先学那一科。
如果改成上面的图的话,就可以计算出拓扑排序为1 2 3 4 5 6。

这个时候你差不多知道拓扑排序的原理是什么了,但如何去计算拓扑排序呢?好,下面我再举个例子为大家讲解一下。
拓扑排序~C语言完整代码_第3张图片
首先我们要创建邻接表:
拓扑排序~C语言完整代码_第4张图片
也可以参考我的邻接表博客:
邻接表完整代码

接着我们要定义一个一维数组作为栈来使用,上面有6个顶点,我们可以a[6],数据的元素填每个顶点的入度情况。
先用数组的下标代替顶点。
拓扑排序~C语言完整代码_第5张图片
在定义一把 top 指针,初始化top=-1,
拓扑排序~C语言完整代码_第6张图片
先找到第一个是入度是0的元素,赋值为-1,如果还有入度为0的元素,注意赋的值为之前的入度为0的元素的下标,比如之前入度的元素的下标为1,则a[4]=1,这样的话就把入度的0的顶点形成一条链,以上图为例刚开始时top=4,删除4顶点以及4顶点进入其他顶点的边,如果删除4顶点后出现入度为0的顶点,假设为b顶点,则接着从b顶点再出发,如果没有的话,top=a[top],则top变为另一个顶点,为1顶点,从1顶点出发。
完整代码如下:

#include
#include

#define MaxVertexNum 100
#define ERROR 0
#define OK 1
#define FALSE 0
#define TRUE 1

typedef int Boolean;
typedef int VertexType;
Boolean visit[MaxVertexNum];
typedef struct node
{
    int adjvex;
    struct node *next;
}EdgeNode;

typedef struct
{
    VertexType vertex;
    EdgeNode *firstedge;
}VertexNode;

typedef VertexNode AdjList[MaxVertexNum];

typedef struct
{
    AdjList adjlist;
    int n,e;
}ALGraph;

int FindVertex(ALGraph *G ,int e,int n)
{
    int i;

    for(i=0;iadjlist[i].vertex==e)
        {
            return i;
        }
    }
    return -1;
}
void create(ALGraph *G)			//创建邻接表
{
    int i,j,k,w,v;
    EdgeNode *s;

    printf("读入顶点和边数");
    scanf("%d %d",&G->n,&G->e);

    for(i=0;in;i++)
    {

        printf("建立顶点表");
        fflush(stdin);
        scanf("%d",&G->adjlist[i].vertex);
        G->adjlist[i].firstedge=NULL;
    }
    printf("建立边表\n");
    for(k=0;ke;k++)
    {
        printf("读入(vi-vj)的顶点对序号");
        scanf("%d %d",&i,&j);

        i=FindVertex(G,i,G->n);
        j=FindVertex(G,j,G->n);
        if(i==-1||j==-1)
        {
            printf("找不到顶点,请重新输入!\n");
            printf("读入(vi-vj)的顶点对序号");
            scanf("%d %d",&i,&j);
            i=FindVertex(G,i,G->n);
            j=FindVertex(G,j,G->n);
        }
        s=(EdgeNode*)malloc(sizeof(EdgeNode));
        s->adjvex=(j);
        s->next=G->adjlist[i].firstedge;
        G->adjlist[i].firstedge=s;
    }
}

void TopoSort(ALGraph *G,int n)
{
    int i,j,k,top,m=0;
    EdgeNode *p;
    int *d=(int *)malloc(n*sizeof(int));		
    for(i=0;iadjlist[i].firstedge;
        while(p!=NULL)
        {
            j=p->adjvex;
            d[j]++;
            p=p->next;
        }
    }
    top=-1;
    for(i=0;iadjlist[j].firstedge;
        while(p)
        {
            k=p->adjvex;		//相l连接的顶点
            d[k]--;		//相连接的顶点入度减1
            if(d[k]==0)		//如果发现入度为0的新顶点,从该顶点出发
            {
                d[k]=top;
                top=k;
            }
            p=p->next;
        }

    }
    if(m'表示两个之间有连接):\n");
    for(i=0;in;i++)
    {
        p=G->adjlist[i].firstedge;
        printf("%d->",G->adjlist[i].vertex);
        while(p!=NULL)
        {
            printf("%d->",G->adjlist[p->adjvex].vertex);
            p=p->next;
        }
        printf("\n");
    }
    printf("拓扑排序为:\n");
    TopoSort(G,G->n);
}

初始化数据:
拓扑排序~C语言完整代码_第7张图片
结果:
拓扑排序~C语言完整代码_第8张图片
说明一下,拓扑排序可能有多种结果。

好了,拓扑排序就介绍到这里了。
谢谢你的浏览,创作不易,点个赞再走呗,支持一下作者!谢谢啦!

你可能感兴趣的:(数据结构)