数据结构——邻接表表示的图的关键路径算法

本文介绍了一个使用邻接链表表示的有向图进行关键路径分析的过程。通过拓扑排序求解每个事件的最早发生时间(ve),再逆序求解最迟发生时间(vl),最终确定关键活动。代码详细展示了如何构建图、进行拓扑排序及关键路径分析。

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

#include <iostream>
using namespace std;

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

#define OK 1
#define NULL 0
#define MAX_VERTEX_NUM 20 // 最大顶点数

typedef char VertexType;
typedef int VRType;
typedef int InforType;
typedef int indegree[MAX_VERTEX_NUM];        //存放节点入度数组
int *ve,*vl;        //事件最早发生时间和最迟发生时间数组,全局变量
int *stack2;            //建栈存储拓扑序列
int top2;


typedef struct ArcNode
{
        int adjvex;        //该边所指的顶点的位置
        struct ArcNode *nextarc;        //指向下一条边的指针
        int info;        //弧的长度(关键路径中的活动)
}ArcNode;   //表的结点

typedef struct VNode
{
        VertexType data;        //顶点信息(如数据等)
        ArcNode *firstarc;        //指向第一条依附该顶点的边的弧指针
}VNode, AdjList[MAX_VERTEX_NUM];   //头结点

typedef struct ALGraph
{
        AdjList vertices;
        int vexnum, arcnum;   //图的当前顶点数和弧数
}ALGraph;


//初始化图
void init_ALGraph(ALGraph &g)
{
    g.arcnum=0;
    g.vexnum=0;
}

//返回顶点v在顶点向量中的位置
int LocateVex(ALGraph &G, char v)
{
        int i;
        for(i = 0; v != G.vertices[i].data && i < G.vexnum; i++)
                ;
        if(i >= G.vexnum)
                return -1;
        return i;
}

//增加节点
void add_vex(ALGraph &G)
{
        cout<<"输入有向图顶点数: "<<endl;
        cin>>G.vexnum;
        //getchar();    //吃回车
        cout<<"输入顶点信息:"<<endl;
        for(int i = 0; i < G.vexnum; i++)
        {
                cin>>G.vertices[i].data;   //构造顶点向量
                G.vertices[i].firstarc = NULL;
                //getchar();
        }
}

//增加边
void add_arc(ALGraph &G, indegree indegree)
{
        ArcNode *s;
        ArcNode *p;

        for(int k=0; k<G.vexnum; k++)
            indegree[k]=0;

        cout<<"输入有向图边数: "<<endl;
        cin>>G.arcnum;
        char v1, v2;
        int length;
        cout<<"输入边信息:"<<endl;
        for(k = 0; k < G.arcnum; k++)
        {
                cin>>v1>>v2>>length;
                int i = LocateVex(G, v1);
                int j = LocateVex(G, v2);    //确定v1 , v2在G中的位置
                ++indegree[j];        //点j的入度增加1

                s = (ArcNode*) malloc (sizeof(ArcNode));
                s->adjvex = j;   //该边所指向的顶点的位置为j
                s->info=length;
                s->nextarc = NULL;
                if(!G.vertices[i].firstarc)
                {
                    G.vertices[i].firstarc=s;
                }
                else
                {
                    for(p = G.vertices[i].firstarc; p->nextarc; p = p->nextarc)
                            ;
                    p->nextarc=s;
                }
        }
}

//构造邻接链表
void CreateUDN(ALGraph &G, indegree indegree)
{
        add_vex(G);        //增加节点 
        add_arc(G,indegree);        //增加边        
}


void PrintAdjList(ALGraph &G)
{
        int i;
        ArcNode *p;
        cout<<"编号    顶点    邻点编号"<<endl;

        for(i = 0; i < G.vexnum; i++)
        {
                cout<<"  "<<i<<"       "<<G.vertices[i].data<<"      ";
                for(p = G.vertices[i].firstarc; p; p = p->nextarc)
                        cout<<p->adjvex<<"("<<p->info<<")"<<"  ";
                cout<<endl;
        }
}

//拓扑排序
int TopologicalSort(ALGraph &g, indegree indegree)
{
    //若G无回路,则输出拓扑排序序列并返回1,若有回路返回0。
    ArcNode *q;
    int i,k;
    int gettop;
    top2=0;

    ve=(int *)malloc( g.vexnum*sizeof(int) );        //事件最早发生时间数组
    for(i=0; i<g.vexnum; i++)
        ve[i]=0;    //初始化

    int *stack1;            //建栈将入度为0的顶点入栈
    stack1=(int *)malloc( g.vexnum*sizeof(int) );
    int top1=0;

    stack2=(int *)malloc( g.vexnum*sizeof(int) );//初始化拓扑序列栈

    for(i = 0; i<g.vexnum; i++)        
        if(0 == indegree[i])        //将入度为0的顶点入栈
            stack1[++top1]=i;
    int count=0;

    while(top1!=0)
    {
        gettop=stack1[top1--];
        cout<<g.vertices[gettop].data<<"-->";
        count++;        //输出i号顶点,并计数
        
        stack2[++top2]=gettop;        //将弹出的顶点序号压入拓扑序列的栈

        for(q = g.vertices[gettop].firstarc; q; q = q->nextarc)
        {
            k=q->adjvex;
            if( !(--indegree[k]) )        //将i号顶点的邻接点的入度减1,如果减1后为0,则入栈
                stack1[++top1]=k;
            //入栈是求ve
            if(ve[gettop] + q->info > ve[k])        //求各顶点事件的最早发生时间ve值
                ve[k] =    ve[gettop] + q->info;
        }//for
    }//while
    cout<<endl;
    if(count < g.vexnum)    //有环路
        return 1;
    else
        return 0;
}


//求关键路径
void CriticalPath(ALGraph &g, indegree indegree)        //G为有向网,输出G的各项关键活动
{
    ArcNode *q;
    int gettop,k,j;
    int ee,el;        //活动最早发生时间和最迟发生时间
    
    TopologicalSort(g, indegree);

    vl=(int *)malloc( g.vexnum*sizeof(int) );        //事件最早发生时间数组
    for(int i=0; i<g.vexnum; i++)
        vl[i]=ve[g.vexnum-1];    //初始化
    
    cout<<"ve:"<<endl;    //输出ve
    for(i=0; i<g.vexnum; i++)
        cout<<ve[i]<<"  ";
    cout<<endl;

    while(top2!=0)    //出栈是求vl
    {
        gettop=stack2[top2--];
        for(q = g.vertices[gettop].firstarc; q; q = q->nextarc)        //求各顶点事件的最迟发生时间vl值
        {
            k=q->adjvex;
            if(vl[k] - q->info < vl[gettop])
                vl[gettop] = vl[k] - q->info;
        }//for
    }

    cout<<"vl:"<<endl;    //输出vl
    for(i=0; i<g.vexnum; i++)
        cout<<vl[i]<<"  ";
    cout<<endl;

        for(j=0; j<g.vexnum; j++)        //求ee,el和关键活动
        {
            for(q = g.vertices[j].firstarc; q; q = q->nextarc)
            {
                k=q->adjvex;
                ee = ve[j];        //活动最早发生时间
                el = vl[k] - q->info;        //活动最迟发生时间
                if(ee == el)    //两者相等即在关键路径上
                    cout<<g.vertices[j].data<<"到"<<g.vertices[k].data
                        <<"长度为:"<<q->info<<"发生时间为"<<ee<<endl;
            }
        }
}

int main()
{
        ALGraph G;
        indegree indegree;
        init_ALGraph(G);    //初始化图

        CreateUDN(G, indegree);        //创建图
        PrintAdjList(G);    //打印图

        CriticalPath(G,indegree);    //求关键路径
        
        return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minyuanxiani

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值