用C语言实现拓扑排序

AOV网:在一个表示工程的有向图中,顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network)。

在某些活动中,一些子活动必须要在某个特定的子活动完成后才能进行,像这样的工程图必须是无环的。如果有向图的所有顶点都输出,说明此图没有环,否则就有环

拓扑排序就是把图中的结点按照活动的进行顺序进行排列。例如:这是坐火车的流程图:
在这里插入图片描述
它的拓扑序列应该是:12345678或者12346578或者12354678.
序列的顺序与边表用头插法还是尾插法建立有关,并且在输入弧的时候,其弧的顺序也会影响到拓扑序列,但是影响的只是不分先后顺序的顶点,如:4,5,6。

拓扑排序实现思路:先输出一个入度为0的顶点,然后删除这个结点,并删除以此顶点为弧尾的弧,重复此步骤,知道AOV网中没有入度为0的顶点。

既然要进行删除操作,选择邻接表;
要判断入度是否为0,顶点节点中还应该设置一个in域来表示顶点的入度。

邻接表的结构定义:

typedef struct EdgeNode
{
    int index ;
    struct EdgeNode *next ;
}EdgeNode ;

typedef struct VerexNode
{
    int in ;
    int data ;
    EdgeNode *firstedge ;
}AdjList[ MAXVex ] ;

查找顶点在顶点表中的下标:

int Locate( GraphList G , int t )
{
    int i ;
    for( i = 0 ; i < G.vexnum ; i++ )
        if( G.adjlist[ i ].data == t )
            break ;
    return i ;
}

用邻接表存储有向图:

void CreateGraph( GraphList *G )
{
    int i , j , k ;
    EdgeNode *p ;
    printf( "请输入结点个数:" ) ;
    scanf( "%d" , &G->vexnum ) ;

    for( i = 0 ; i < G->vexnum ; i++ )
    {
        printf( "请输入第%d个结点的信息: " , i + 1 ) ;
        scanf( "%d" , &G->adjlist[ i ].data ) ;
    }

    for( i = 0 ; i < G->vexnum ; i++ )
    {
        G->adjlist[ i ].in = 0 ;
        G->adjlist[ i ].firstedge = NULL ;
    }

    printf( "请输入图中边的条数:" ) ;
    scanf( "%d" , &G->edgenum ) ;

    for( i = 0 ; i < G->edgenum ; i++ )
    {
        printf( "请分别输入第%d条边的弧尾的弧头信息:" , i + 1 ) ;
        scanf( "%d %d" , &j , &k ) ;

        p = ( EdgeNode * )malloc( sizeof( EdgeNode ) ) ;
        p->index = Locate( *G , k ) ;
        p->next = G->adjlist[ Locate( *G , j ) ].firstedge ;
        G->adjlist[ Locate( *G , j ) ].firstedge = p ;

        G->adjlist[ Locate( *G , k ) ].in += 1 ;//入度加1
    }
}

拓扑排序:

Status TopologicalSort( GraphList G )
{
    EdgeNode *p ;
    int cnt = 0 ;
    int top = 0 ;
    int i , gettop ;

    int *stack = ( int * )malloc( sizeof( int ) * ( G.vexnum + 5 ) ) ;//为栈动态分配一块内存
    for( i = 0 ; i < G.vexnum ; i++ )//入度为0就入栈
        if( G.adjlist[ i ].in == 0 )
            stack[ ++top ] = i ;

    while( top )
    {
        gettop = stack[ top-- ] ;
        printf( "%d ==> " , G.adjlist[ gettop ].data ) ;
        cnt++ ;

        for( p = G.adjlist[ gettop ].firstedge ; p != NULL ; p = p->next )
        {
            if( !( --G.adjlist[ p->index ].in ) ) //把刚刚遍历过的结点删去,并把以此节点为弧尾的边删去。
                stack[ ++top ] = p->index ;
        }
    }
    printf( "end\n" ) ;
    if( cnt < G.vexnum )//比较输出的顶点数与图中顶点个数来判断图中是否有环
        return ERROR ;
    else
        return OK ;
}

源代码:

#include<stdio.h>
#include<stdlib.h>
#define MAXVex 100
#define ERROR 0
#define OK 1

typedef int Status ;
typedef struct EdgeNode
{
    int index ;
    struct EdgeNode *next ;
}EdgeNode ;

typedef struct VerexNode
{
    int in ;
    int data ;
    EdgeNode *firstedge ;
}AdjList[ MAXVex ] ;

typedef struct
{
    AdjList adjlist ;
    int vexnum , edgenum ;
}GraphList ;

void CreateGraph( GraphList *G ) ;
int Locate( GraphList G , int t ) ;
Status TopologicalSort( GraphList G ) ;

int main( void )
{
    GraphList G ;
    CreateGraph( &G ) ;
    TopologicalSort( G ) ;
    return 0 ;
}

int Locate( GraphList G , int t )
{
    int i ;
    for( i = 0 ; i < G.vexnum ; i++ )
        if( G.adjlist[ i ].data == t )
            break ;

    return i ;
}

void CreateGraph( GraphList *G )
{
    int i , j , k ;
    EdgeNode *p ;
    printf( "请输入结点个数:" ) ;
    scanf( "%d" , &G->vexnum ) ;

    for( i = 0 ; i < G->vexnum ; i++ )
    {
        printf( "请输入第%d个结点的信息: " , i + 1 ) ;
        scanf( "%d" , &G->adjlist[ i ].data ) ;
    }

    for( i = 0 ; i < G->vexnum ; i++ )
    {
        G->adjlist[ i ].in = 0 ;
        G->adjlist[ i ].firstedge = NULL ;
    }

    printf( "请输入图中边的条数:" ) ;
    scanf( "%d" , &G->edgenum ) ;

    for( i = 0 ; i < G->edgenum ; i++ )
    {
        printf( "请分别输入第%d条边的弧尾的弧头信息:" , i + 1 ) ;
        scanf( "%d %d" , &j , &k ) ;

        p = ( EdgeNode * )malloc( sizeof( EdgeNode ) ) ;
        p->index = Locate( *G , k ) ;
        p->next = G->adjlist[ Locate( *G , j ) ].firstedge ;
        G->adjlist[ Locate( *G , j ) ].firstedge = p ;

        G->adjlist[ Locate( *G , k ) ].in += 1 ;
    }
}

Status TopologicalSort( GraphList G )
{
    EdgeNode *p ;
    int cnt = 0 ;
    int top = 0 ;
    int i , gettop ;

    int *stack = ( int * )malloc( sizeof( int ) * ( G.vexnum + 5 ) ) ;
    for( i = 0 ; i < G.vexnum ; i++ )
        if( G.adjlist[ i ].in == 0 )
            stack[ ++top ] = i ;

    while( top )
    {
        gettop = stack[ top-- ] ;
        printf( "%d ==> " , G.adjlist[ gettop ].data ) ;
        cnt++ ;

        for( p = G.adjlist[ gettop ].firstedge ; p != NULL ; p = p->next )
        {
            if( !( --G.adjlist[ p->index ].in ) ) //把刚刚遍历过的结点删去,并把以此节点为弧尾的边删去。并把入度为0的顶点压入栈中
                stack[ ++top ] = p->index ;
        }
    }
    printf( "end\n" ) ;
    if( cnt < G.vexnum )
        return ERROR ;
    else
        return OK ;
}

-------------------------参考资料:《大话数据结构》

  • 4
    点赞
  • 55
    收藏
  • 打赏
    打赏
  • 3
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:创作都市 设计师:CSDN官方博客 返回首页
评论 3

打赏作者

h3xz

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值