邻接表、十字邻链表、拓扑排序(AOV图)与关键路径(AOE图)

邻接表与十字邻链表

#include <stdio.h>
#include <stdlib.h>
#define MAXN 1000

typedef struct EdgeNode{
    int weight;
    int adjvex;
    struct EdgeNode *next;
}EdgeNode;

typedef struct VexNode{
    //data可存储该结点信息
    EdgeNode *firstEdge;
}AdjList[MAXN];


typedef struct
{
    AdjList adjList;
    int numVex,numEdge;
}GraphAdjList;


typedef struct node
{
    int i;
    struct node *next;
}Node;

typedef struct
{
    Node *front;
    Node *rear;
    int size;
}Queue;


void InitQueue(Queue *q)
{
    q->front = q->rear = NULL;
    q->size = 0;
}

int isEmpty(Queue *q)
{
    if(q->size==0)
        return 1;
    return 0;
}

void EnQueue(Queue *q,int data)
{
    Node *t = (Node *)malloc(sizeof(Node));
    t->i = data;
    t->next = NULL;

    if(isEmpty(q))
        q->front = t;
    else
        q->rear->next = t;
    q->rear = t;
    q->size++;
}

void DeQueue(Queue *q,int *temp)
{
    if(isEmpty(q))
        return;
    *temp = q->front->i;
    Node *t = q->front;

    q->size--;
    if(isEmpty(q))
        q->rear = NULL;
    q->front = q->front->next;
    free(t);
}

void CreatALGraph(GraphAdjList *g)
{
    int i,j,k;
    EdgeNode *e;
    printf("请输入边数和顶点数:");
    scanf("%d%d",&g->numEdge,&g->numVex);

    for(i=0;i<g->numVex;i++)
    {
        //scanf(data)可输入结点信息
        g->adjList[i].firstEdge = NULL;
    }

    for(k=0;k<g->numEdge;k++)
    {
         int weight;
          printf("输入边(i,j)以及权值:");
          scanf("%d%d%d",&i,&j,&weight);

          //利用头插法由于是无向图所以需要两步
          e = (EdgeNode *)malloc(sizeof(EdgeNode));
          e->adjvex = i;
          e->weight = weight;
          e->next = g->adjList[j].firstEdge;
          g->adjList[j].firstEdge = e;

          e = (EdgeNode *)malloc(sizeof(EdgeNode));
          e->adjvex = j;
          e->weight = weight;
          e->next = g->adjList[i].firstEdge;
          g->adjList[i].firstEdge = e;
    }
}

int vis[MAXN];
void DFS(GraphAdjList g,int i)
{
    EdgeNode *p;
    vis[i]=1;
    printf("%d ",i);
    p = g.adjList[i].firstEdge;

    while(p)
    {
        if(!vis[p->adjvex])
            DFS(g,p->adjvex);
        p = p->next;
    }
}

void DFSTraverse(GraphAdjList g)
{
    for(int i=0;i<g.numVex;i++)
        vis[i] = 0;
    for(int i=0;i<g.numVex;i++)
        if(!vis[i])
         DFS(g,i);    //连通图只会执行一次
}

void BFSTraverse(GraphAdjList g)
{
    int i;
    Queue q;
    EdgeNode *p;
    InitQueue(&q);

    for(i=0;i<g.numVex;i++)
        vis[i]=0;
    for(i=0;i<g.numVex;i++)  //连通图只执行一次
    {
        if(!vis[i])
        {
            int t;
            EnQueue(&q,i);
            vis[i]=1;
            while(!isEmpty(&q))
            {
                DeQueue(&q,&t);
                printf("%d ",t);
                p = g.adjList[t].firstEdge;
                while(p)
                {
                    if(!vis[p->adjvex])
                    {
                        vis[p->adjvex] = 1;
                        EnQueue(&q,p->adjvex);
                    }
                    p = p->next;
                }
            }
        }
    }
}

int main()
{
    GraphAdjList g;
    CreatALGraph(&g);
    printf("\nDFS遍历:");
    DFSTraverse(g);
    putchar('\n');
    printf("BFS遍历:");
    BFSTraverse(g);
    return 0;
}

在这里插入图片描述

拓扑排序

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define N 1000
#define ERROR false
#define OK true

typedef bool Status;
typedef struct EdgeNode
{
    int weight;
    int adjvex;
    struct EdgeNode * next;
}EdgeNode;

typedef struct VexNode
{
    int in;  //入度
    EdgeNode * firstedge;
}AdjList[N];

typedef struct
{
    int numVex,numEdge;
    AdjList adjlist;
}GraphAdjList;

void CreatGraph(GraphAdjList *g)
{
    int i;
    EdgeNode * e;
    printf("请输入边数和结点数:");
    scanf("%d%d",&g->numEdge,&g->numVex);

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

    for(i=0;i<g->numEdge;i++)
    {
        int start,end,w;
        printf("输入(i,j)以及权值:");
        scanf("%d%d%d",&start,&end,&w);
        g->adjlist[end].in++;

        e = (EdgeNode *)malloc(sizeof(EdgeNode));
        e->adjvex = end;
        e->weight = w;
        e->next = g->adjlist[start].firstedge;
        g->adjlist[start].firstedge = e;
    }
}

Status TopologicalSort(GraphAdjList *g)
{
    int top = -1;
    int *stack;  //拓扑排序需要用到栈的概念来保存入度为0的点
    int count = 0;  //用于计数,若是成环count会少于图中点数
    EdgeNode * p;

    int i;
    stack = (int *)calloc(g->numVex,sizeof(int));
    for(i=0;i<g->numVex;i++)
    {
        if(g->adjlist[i].in == 0)
            stack[++top] = i;
    }

    while(top!=-1)
    {
        int k = stack[top--];
        count++;
        if(count==g->numVex)
            printf("%d",k);
        else
            printf("%d -> ",k);

        p = g->adjlist[k].firstedge;
        while(p)
        {
            if( (--g->adjlist[p->adjvex].in)==0 )
                stack[++top] = p->adjvex;
            p = p->next;
        }
    }

    if(count<g->numVex)
        return ERROR;
    else
        return OK;
}

int main()
{
    GraphAdjList g;
    CreatGraph(&g);
    bool check = TopologicalSort(&g);
    printf("\n%s",check==true?"true":"false");
    return 0;
}
  -> 10 -> 2 -> 4 -> 7
  -> 3 -> 5 -> 6

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

拓扑排序练习

车站分级(洛谷P1983)与排序(洛谷P1347)
原题网址:https://www.luogu.com.cn/problem/P1983
https://www.luogu.com.cn/problem/P1347

个人题解:https://blog.csdn.net/m0_52103105/article/details/117849992

关键路径

在这里插入图片描述

在这里插入图片描述

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX 100

//这里我们要建立aoe图,它与拓扑排序中的aov图不同的地方在于他的顶点表示事件,线表示活动
//如组装车要造零件后再瓶装
//AOE图:起始点——零件造完——拼装完成 (而带权值的线分别为造零件和执行拼装,其中权值代表时间)
//AOV图:造零件——拼装

int *etv,*ltv;  //事件最早发生时间与事件最晚发生时间
int *stack2;    //存储事件的拓扑序列
int top2=-1;    //要从汇点开始求活动最迟发生时间

typedef struct NodeEdge
{
    int adjvex;
    int weight;
    struct NodeEdge * next;
}NodeEdge;

typedef struct
{
    int in;
    NodeEdge * firstEdge;
}AdjList[MAX];

typedef struct
{
    AdjList adjlist;
    int numVex,numEdge;
}GraphAdList;


void Creat(GraphAdList *g)
{
    int i;
    NodeEdge *e;
    printf("请输入边数和顶点数(0起步):");
    scanf("%d%d",&g->numEdge,&g->numVex);

    //初始化
    for(i=0;i<g->numVex;i++)
    {
        g->adjlist[i].in = 0;
        g->adjlist[i].firstEdge = NULL;
    }

    for(i=0;i<g->numEdge;i++)
    {
        int st,en,weight;
        printf("请输入<i,j>及权值:");
        scanf("%d%d%d",&st,&en,&weight);

        //由于是AOE图虽是有向但只有一个方向
        e = (NodeEdge *)malloc(sizeof(NodeEdge));
        e->next = g->adjlist[st].firstEdge;
        e->adjvex = en;
        e->weight = weight;
        g->adjlist[st].firstEdge = e;
        g->adjlist[en].in++; //入度增加
    }
}


//拓扑排序用于寻找事件最早开始时间以及拓扑序列
bool TopologicalSort(GraphAdList *g)
{
    int i,k;
    int count=0;
    NodeEdge *p;
    etv = (int *)calloc(g->numVex,sizeof(int));  //初始化为0
    int *stack;
    int top = -1;
    stack = (int *)malloc(g->numVex*sizeof(int));
    stack2 = (int *)malloc(g->numVex*sizeof(int));

    for(i=0;i<g->numVex;i++)
    {
        if(g->adjlist[i].in==0)
            stack[++top] = i;
    }

    while(top!=-1)
    {
        int gettop = stack[top--];
        stack2[++top2] = gettop;
        count++;
        for(p = g->adjlist[gettop].firstEdge;p;p = p->next)
        {
            k = p->adjvex;
            if(etv[gettop]+p->weight > etv[k])
                etv[k] = etv[gettop]+p->weight;   //必须取最大根据拓扑排序的定理前置点不完成则该点不能进行
            if(--(g->adjlist[k].in) == 0)
                stack[++top] = k;
        }
    }

    if(count == g->numVex)
        return true;
    else
        return false;
}

void CriticalPath(GraphAdList *g)
{
    int i,gettop,k;
    NodeEdge * p;
    int ete,lte;  //活动最早发生时间和活动最晚发生时间,若两者相同则为绝对路径
    ltv = (int *)malloc(g->numVex*sizeof(int));
    TopologicalSort(g);
    for(i=0;i<g->numVex;i++)
    {
        ltv[i] = etv[g->numVex-1];    //全部初始化为汇点(汇点必为关键路径)
        //我们stack2必从汇点开始
    }

    while(top2!=-1)
    {
        gettop = stack2[top2--];
        for(p = g->adjlist[gettop].firstEdge;p;p = p->next)
        {
            k = p->adjvex;
            if(ltv[k]-p->weight < ltv[gettop])   //为什么取小于?由拓扑排序定理逆向既然后面的点都发生那前面的点必然已经完成,小于是因为部分前置路径导致后方点etv变大,故取小于
                ltv[gettop] = ltv[k]-p->weight;
        }
    }

    for(i=0;i<g->numVex;i++)
    {
        for(p = g->adjlist[i].firstEdge;p;p = p->next)
        {
            k = p->adjvex;
            ete = etv[i];
            lte = ltv[k]-p->weight;
            if(ete == lte)
            {
              printf("<v%d,v%d> length:%d,",i,k,p->weight);
            }
        }
    }
}

int main()
{
    GraphAdList g;
    Creat(&g);
    CriticalPath(&g);
    return 0;
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值