拓扑排序--C语言

本文介绍了一种基于邻接表存储的有向无环图(DAG)的拓扑排序算法实现。通过选择并移除入度为0的顶点来逐步构建排序序列,最终输出一个拓扑排序结果或判断图中是否存在环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本思想:
1、在有向图中选一个没有前驱(入度为0)的顶点且输出;
2、从图中删除该顶点和所有以它为尾的边。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止(此时说明有向图中存在环)。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/*--有向无环图拓扑排序--*/ 
#define MAX_VERTEX_NUM 20

typedef char VertexType;
typedef int StackElem;
//邻接表存储图 
typedef struct ArcNode
{
    int adjvex;
    struct ArcNode *nextarc;
}ArcNode;

typedef struct VNode
{
    int indegree;   //图中顶点入度 
    VertexType data;
    ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct
{
    AdjList vertices;
    int vernum,arcnum;
}ALGraph;

//创建有向图
int locateVex(ALGraph alg,char v)
{
    int i;
    for(i=0;i<alg.vernum;i++)
    {
        if(alg.vertices[i].data == v)
        return i;
    }
    return -1;
 } 

void createAOVGraph(ALGraph *alg)
{
    int i,j,k;
    char v1,v2;
    ArcNode *p,*s;
    printf("输入有向图顶点数个和边数:");
    scanf("%d %d",&(alg->vernum),&(alg->arcnum));
    getchar();
    printf("输入顶点名称\n");
    for(k=0;k<alg->vernum;k++)
    {
        printf("输入第%d个顶点名称:",k);
        scanf("%c",&(alg->vertices[k].data));
        alg->vertices[k].firstarc = NULL;
        alg->vertices[k].indegree = 0;
        getchar();
    }
    printf("输入边信息v1 v2\n");
    for(k=0;k<alg->arcnum;k++)
    {
        printf("输入d第%d条边的起止顶点名称:",k);
        scanf("%c %c",&v1,&v2);
        i = locateVex(*alg,v1);
        j = locateVex(*alg,v2);
        p = (ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex = j;
        p->nextarc = NULL;
        if(alg->vertices[i].firstarc == NULL)
        {
            alg->vertices[i].firstarc = p;
        }
        else
        {
            s = alg->vertices[i].firstarc;
            while(s->nextarc != NULL)
                s = s->nextarc;
            s->nextarc = p;
        }       
        alg->vertices[j].indegree += 1;   //结点j的入度增加1 
        getchar();
    } 
 } 

 //打印有向图
 void print(ALGraph G)
 {
    int i;
    ArcNode *p;
    printf("图的邻接链表(顶点名称 入度:邻接点)\n"); 
    for(i=0;i<G.vernum;i++)
    {
        printf("%c %d:",G.vertices[i].data,G.vertices[i].indegree);
        p = G.vertices[i].firstarc;
        while(p!= NULL)
        {
            printf("%c ",G.vertices[p->adjvex].data);
            p = p->nextarc;
         }
         printf("\n");
     }
     printf("\n");
  } 

//有向图进行拓扑排序,若有向图没有回路则输出图的一个拓扑排序以OK结尾,否则输出序列以error结束
//为避免重复检测入度为0的顶点,设一个栈暂存入度为0的顶点
typedef struct SNode
{
    StackElem index;
    struct SNode *snext;
}SNode,*PSNode;

typedef struct Stack
{
    PSNode top;
    PSNode bottom;
 }Stack,*PStack;

bool stackEmpty(PStack ps)
{
    if(ps->bottom == ps->top)
        return true;
    return false;
}
PStack initStack()
{
    PStack ps = (PStack)malloc(sizeof(Stack));
    PSNode p = (PSNode)malloc(sizeof(SNode));
    if(p==NULL && ps ==NULL)
    {
        printf("initstack error!\n");
        exit(-1);
    }
    p->snext = NULL;
    ps->bottom = ps->top = p;
    return ps;
 } 

void push(PStack ps,StackElem index)
{
    PSNode p = (PSNode)malloc(sizeof(SNode));
    if(p == NULL)
    {
        printf("push error!\n");
        exit(-1);
    }
    p->index = index;
    p->snext = ps->top;
    ps->top = p;
}
StackElem pop(PStack ps)
{
    if(stackEmpty(ps))
    {
        printf("stack is NULL\n");
        exit(-1);
    }
    else
    {
        PSNode p = ps->top;
        StackElem index = p->index;
        ps->top = p->snext;
        free(p);
        return index;
    }
}

//拓扑排序 
void topologicalSort(ALGraph G)
{
    printf("拓扑排序序列:"); 
    int i,count=0,index;  //count对栈中输出顶点计数 
    ArcNode *p;
    StackElem k;
    PStack ps = initStack();
    for(i=0;i<G.vernum;i++)
    {
        if(G.vertices[i].indegree==0)     //入度为0的顶点入栈 
            push(ps,i);
    }
    while(!stackEmpty(ps))
    {
        index = pop(ps);
        printf("%c ",G.vertices[index].data);
        ++count;
        for(p=G.vertices[index].firstarc;p!=NULL;p=p->nextarc)
        {
            k = p->adjvex;
            if((--G.vertices[k].indegree)==0)    //对第index个顶点的每个邻接点的入度减1,若邻接点入度为0,则入栈 
                push(ps,k);
        }
     } 
    printf("\n");
    if(count < G.vernum)
        printf("有向图中存在环ERROR!\n");

    else
        printf("OK!\n");

 } 
int main()
{
    ALGraph alg;
    createAOVGraph(&alg);
    print(alg);
    topologicalSort(alg);
    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值