您的位置:首页 > 理论基础 > 数据结构算法

算法:图的关键路径-数据结构(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
请按任意键继续. . .
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: