算法:图的关键路径-数据结构(24)
2017-05-21 20:32
537 查看
一、个人理解-简单说说
关键路径其实就是一个点到另外一个点的最唱路径,其中这个图是有向无环图。求出工程里面最关键的事件,不能拖延的事件路径,参考P183-P186。解决的思路,便是找出每个事件点的最早开始时间Ve和最晚完成时间ee,当Ve==ee的情况下就是不能拖延的事件,便是关键路径。二、数据结构与算法
1、有向图的十字链表
//==========有向图的十字链表=============== typedef int InfoType; typedef struct ArcBox{ int tailvex, headvex;//数组索引的弧头和弧尾 struct ArcBox *hlink, *tlink;//头链和尾链 头链是弧头相同的下一条弧 尾弧是弧尾相同的一条弧 InfoType info; }ArcBox;//弧 typedef struct VexNode{ VertexType data; ArcBox *firstin, *firstout; }VexNode;//头结点 typedef struct{ VexNode xlist[MAX_VERTEX_NUM]; int vexnum, arcnum;//顶点总数 和弧总数 }OLGraph; Status CreateDG(OLGraph &G, int vexnum, char * vexs, int arcnum, int maps[][6]){ //创建有向图 G.vexnum = vexnum; G.arcnum = arcnum; for (int i = 0; i < G.vexnum; i++) { //初始化指针 G.xlist[i].data = vexs[i]; G.xlist[i].firstin = NULL; G.xlist[i].firstout = NULL; } for (int i = 0; i < vexnum; i++) { for (int j = 0; j < vexnum; j++) { if (maps[i][j] != 0) { //i到j这个有有弧 ArcBox * p = (ArcBox*)malloc(sizeof(ArcBox)); *p = { i, j, G.xlist[j].firstin, G.xlist[i].firstout, maps[i][j] }; G.xlist[i].firstout = p; G.xlist[j].firstin = p; } } } return OK; } //对弧的所有遍历. void PrintfGraphDg(OLGraph G){ printf("弧尾\t弧头\n"); for (int i = 0; i < G.vexnum; i++) { ArcBox* arc = G.xlist[i].firstout; while (arc!=NULL) { printf("%d\t%d \t%c->%c 权重:%d\n", arc->tailvex, arc->headvex, G.xlist[arc->tailvex].data, G.xlist[arc->headvex].data,arc->info); arc = arc->tlink; } } }
2、关键路径算法
//利用拓扑排序算法计算ve数组 int ve[MAX_VERTEX_NUM];//点的最早完成时间数组 int vl[MAX_VERTEX_NUM];//点的最迟完成时间数组 Status TopologicalOrder(OLGraph G,SqStack &T){ //初始化ve数组 for (int i = 0; i < G.vexnum; i++) { ve[i] = 0; } int indegree[MAX_VERTEX_NUM];//存放各顶点入度的数组 //生成入度数组 for (int i = 0; i < G.vexnum; i++) { int count = 0; ArcBox* arc = G.xlist[i].firstin;//入度的弧 while (arc != NULL) { count++; arc = arc->hlink; } indegree[i] = count; printf("%c的入度为%d \n", G.xlist[i].data, indegree[i]); } SqStack stack;//保存的是入度为0的结点 InitStack(stack); InitStack(T);//初始化栈 for (int i = 0; i < G.vexnum; i++) { if (indegree[i] == 0) { //入度为0 进栈 //printf("push %d\n", i); Push(stack, i); } } int count = 0;//计数计算拓扑排序入度为0 的个数 while (!StackEmpty(stack)){ //在栈不为空的情况下 int elem; Pop(stack, elem); //获取逆的拓扑排序 Push(T, elem); count++; printf("pop %d\n", elem); //printf("%c", G.xlist[elem].data); //遍历所有指向elem顶点的弧 ArcBox* arc = G.xlist[elem].firstout;//出去的弧 while (arc != NULL) { int k = arc->headvex;//当前弧的头的索引 if ((--indegree[k]) == 0) { //printf("push %d\n", arc->tailvex); Push(stack, k); } //找出j-k的弧上最大的边 if (ve[elem] + arc->info > ve[k]) { ve[k] = ve[elem] + arc->info; } arc = arc->tlink; } } if (count < G.vexnum) { printf("个图有回路"); return ERROR;//这个图有回路 } return OK; } //求出关键路径 Status CriticalPath(OLGraph G){ SqStack T; TopologicalOrder(G, T); for (int i = 0; i < G.vexnum; i++) { //printf("%d:",ve[i]); } //计算出vl数组 //初始化vl数组 最后一个点的ve与vl相等 for (int i = 0; i < G.vexnum; i++) { vl[i] = ve[G.vexnum - 1]; } //使用逆拓扑排序计算出所有的vl while (!StackEmpty(T)) { int j;//当前计算的点j Pop(T, j); //遍历点j的所有 ArcBox* arc = G.xlist[j].firstout;//出去的弧 while (arc != NULL) { int k = arc->headvex;//当前弧的头的索引 //找出j-k的弧上最大的边 if (vl[k] - arc->info < vl[j]) { vl[j] = vl[k] - arc->info; } arc = arc->tlink; } } //for (int i = 0; i < G.vexnum; i++) //{ // printf("%d:", vl[i]); //} a0e6 //求出ee和el 就是关于弧的最早开始时间和最晚开始时间 遍历所有的弧 for (int i = 0; i < G.vexnum; i++) { ArcBox* arc = G.xlist[i].firstout; while (arc != NULL) { //printf("%d\t%d \t%c->%c 权重:%d\n", arc->tailvex, arc->headvex, G.xlist[arc->tailvex].data, G.xlist[arc->headvex].data, arc->info); int ee = ve[arc->tailvex]; int el = vl[arc->headvex] - arc->info; if (ee == el) { printf("%d\t%d \t%c->%c 权重:%d\n", arc->tailvex, arc->headvex, G.xlist[arc->tailvex].data, G.xlist[arc->headvex].data, arc->info); } arc = arc->tlink; } } return OK; }
三、执行
//链表创建进行拓扑排序和关键路径 int vexnum = 6; char *vexs = "abcdef"; int arcnum = 8; int maps[6][6] = { { 0, 3, 2, 0, 0, 0 }, { 0, 0, 0, 2, 3, 0 }, { 0, 0, 0, 4, 0, 3 }, { 0, 0, 0, 0, 0, 2 }, { 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0 } }; OLGraph G; CreateDG(G,vexnum,vexs,arcnum,maps); //PrintfGraphDg(G); //DFSTraverse_L(G); //BFSTraverse_L(G); //TopologicalSort(G);//拓扑排序 CriticalPath(G);//关键路径
输出:
a的入度为0 b的入度为1 c的入度为1 d的入度为2 e的入度为1 f的入度为3 pop 0 pop 1 pop 4 pop 2 pop 3 pop 5 0 2 a->c 权重:2 2 3 c->d 权重:4 3 5 d->f 权重:2 请按任意键继续. . .
相关文章推荐
- 【数据结构】关键路径算法
- 数据结构中关键路径算法的实现与应用
- 数据结构与算法--关键路径
- 数据结构中关键路径算法的实现与应用
- 数据结构——邻接表表示的图的关键路径算法
- 数据结构中关键路径算法的实现与应用
- 看数据结构写代码(46) 关键路径
- [置顶] 数据结构之 迪杰斯特拉最短路径算法
- 算法——数据结构图的最短路径实现JAVA代码
- 【数据结构与算法】图之最短路径
- 【学习笔记----数据结构22-图的关键路径】
- 算法竞赛入门经典:第六章 数据结构基础 6.12迷宫路径
- 数据结构之---C语言实现关键路径AOE图
- 数据结构之(图最短路径之)Dijkstra(迪杰斯特拉)算法
- 数据结构之---C语言实现最短路径之Floyd(弗洛伊德)算法
- 数据结构与算法——最短路径Dijkstra算法的C++实现
- 看数据结构写代码(47)迪杰斯特拉最短路径算法
- 数据结构之(图最短路径之)Dijkstra(迪杰斯特拉)算法
- 数据结构之(图最短路径之)Floyd(弗洛伊德)算法
- 【数据结构】关键路径_CriticalPath