邻接表与十字邻链表
#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;
}
-> 1 ↘
0 -> 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;
}