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

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

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

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

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

#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;i<n;i++)
    {
        if(G->adjlist[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;i<G->n;i++)
    {

        printf("建立顶点表");
        fflush(stdin);
        scanf("%d",&G->adjlist[i].vertex);
        G->adjlist[i].firstedge=NULL;
    }
    printf("建立边表\n");
    for(k=0;k<G->e;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;i<n;i++)		//初始化数组
    {
        d[i]=0;
    }
    for(i=0;i<n;i++)		//统计各个顶点的入度情况,并把他们填入数组里面
    {
        p=G->adjlist[i].firstedge;
        while(p!=NULL)
        {
            j=p->adjvex;
            d[j]++;
            p=p->next;
        }
    }
    top=-1;
    for(i=0;i<n;i++)			//先找出里面入度是0的顶点
    {
        if(d[i]==0)
        {
            d[i]=top;
            top=i;
        }
    }

    while(top!=-1)
    {
        j=top;	
        top=d[top];
        printf("%d ",j);		
        m++;		//统计顶点
        p=G->adjlist[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) printf("\n有回路!\n");
    free(d);
}

void main()
{
    ALGraph *G=(ALGraph *)malloc(sizeof(ALGraph));
    EdgeNode *p;
    create(G);
    int i;
    printf("其邻接表为('->'表示两个之间有连接):\n");
    for(i=0;i<G->n;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);
}

初始化数据:
在这里插入图片描述
结果:
在这里插入图片描述
说明一下,拓扑排序可能有多种结果。

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

  • 83
    点赞
  • 239
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是使用队列完成拓扑排序C语言代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 最大顶点数 typedef struct ArcNode { int adjvex; // 邻接点下标 struct ArcNode *next; // 指向下一个邻接点的指针 } ArcNode; typedef struct VertexNode { int indegree; // 顶点入度 ArcNode *firstarc; // 指向第一个邻接点的指针 } VertexNode; typedef struct { VertexNode vexs[MAX_VERTEX_NUM]; // 顶点数组 int vexnum; // 顶点数 int arcnum; // 弧数 } ALGraph; typedef struct { int data[MAX_VERTEX_NUM]; // 存储队列元素的数组 int front; // 队头指针 int rear; // 队尾指针 } Queue; void InitQueue(Queue *Q) { // 初始化队列 Q->front = Q->rear = 0; } int QueueEmpty(Queue *Q) { // 判断队列是否为空 return Q->front == Q->rear; } int EnQueue(Queue *Q, int e) { // 入队 if ((Q->rear + 1) % MAX_VERTEX_NUM == Q->front) { // 队列已满 return 0; } Q->data[Q->rear] = e; Q->rear = (Q->rear + 1) % MAX_VERTEX_NUM; return 1; } int DeQueue(Queue *Q, int *e) { // 出队 if (QueueEmpty(Q)) { // 队列为空 return 0; } *e = Q->data[Q->front]; Q->front = (Q->front + 1) % MAX_VERTEX_NUM; return 1; } void CreateALGraph(ALGraph *G) { // 创建有向图 int i, j, k; int v1, v2; ArcNode *p; printf("请输入有向图的顶点数和弧数:"); scanf("%d%d", &G->vexnum, &G->arcnum); printf("请输入有向图的顶点:"); for (i = 0; i < G->vexnum; i++) { // 初始化顶点数组 scanf("%d", &j); G->vexs[i].indegree = 0; G->vexs[i].firstarc = NULL; } printf("请输入有向图的弧(起点 终点):\n"); for (k = 0; k < G->arcnum; k++) { // 构造邻接表 scanf("%d%d", &v1, &v2); p = (ArcNode *) malloc(sizeof(ArcNode)); p->adjvex = v2; p->next = G->vexs[v1].firstarc; G->vexs[v1].firstarc = p; G->vexs[v2].indegree++; } } void TopologicalSort(ALGraph *G) { // 拓扑排序 int i, e, count = 0; ArcNode *p; Queue Q; InitQueue(&Q); // 初始化队列 for (i = 0; i < G->vexnum; i++) { // 将入度为0的顶点入队 if (G->vexs[i].indegree == 0) { EnQueue(&Q, i); } } while (!QueueEmpty(&Q)) { // 队列不为空时 DeQueue(&Q, &e); // 取出队头元素 printf("%d ", e); // 输出该顶点 count++; // 统计已输出的顶点数 for (p = G->vexs[e].firstarc; p != NULL; p = p->next) { // 将所有以该顶点为起点的弧的终点的入度减1 if (--G->vexs[p->adjvex].indegree == 0) { // 若终点的入度为0,则入队 EnQueue(&Q, p->adjvex); } } } if (count == G->vexnum) { // 输出顶点数等于图中顶点数,说明拓扑排序成功 printf("\n拓扑排序成功!\n"); } else { // 输出顶点数小于图中顶点数,说明存在回路 printf("\n该有向图存在回路!\n"); } } int main() { ALGraph G; CreateALGraph(&G); TopologicalSort(&G); return 0; } ``` 该代码实现了通过邻接表表示的有向图进行拓扑排序,并使用队列来存储入度为0的顶点。其中,`CreateALGraph`函数用于创建有向图,`TopologicalSort`函数用于进行拓扑排序。在`TopologicalSort`函数中,首先将所有入度为0的顶点入队,然后依次取出队头元素并输出,再将所有以该顶点为起点的弧的终点的入度减1,若该终点的入度为0,则入队。最后,通过统计已输出的顶点数来判断拓扑排序是否成功。如果输出的顶点数等于图中顶点数,则说明拓扑排序成功;否则,说明存在回路,即该有向图不是一个DAG。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值