码迷,mamicode.com
首页 > 其他好文 > 详细

_DataStructure_C_Impl:AOE网的关键路径

时间:2015-08-12 01:29:23      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:数据结构

//_DataStructure_C_Impl:CriticalPath
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"SeqStack.h"
//图的邻接表类型定义
typedef char VertexType[4];
typedef int InfoPtr;	//定义为整型,为了存放权值
typedef int VRType;

#define MaxSize 50	 //最大顶点个数
typedef enum{DG,DN,UG,UN}GraphKind;		//图的类型:有向图、有向网、无向图和无向网
//边结点的类型定义
typedef struct ArcNode{
	int adjvex;	//邻接点域,弧指向的顶点的位置
	InfoPtr *info;	//弧的权值
	struct ArcNode *nextarc;	//指示下一个与该顶点相邻接的顶点
}ArcNode;
//头结点的类型定义
typedef struct VNode{
	VertexType data;	//用于存储顶点
	ArcNode *firstarc;	//指示第一个与该顶点邻接的顶点
}VNode,AdjList[MaxSize];
//图的类型定义
typedef struct{
	AdjList vertex;
	int vexnum,arcnum;	//图的顶点数目与弧的数目
	GraphKind kind;	//图的类型
}AdjGraph;
//返回图中顶点对应的位置
int LocateVertex(AdjGraph G,VertexType v){
	int i;
	for(i=0;i<G.vexnum;i++)
		if(strcmp(G.vertex[i].data,v)==0)
			return i;
	return -1;
}
//采用邻接表存储结构,创建有向网N
void CreateGraph(AdjGraph *N){
	int i,j,k,w;
	VertexType v1,v2;	//定义两个顶点v1和v2
	ArcNode *p;
	printf("请输入图的顶点数,边数(逗号分隔): ");
	scanf("%d,%d",&(*N).vexnum,&(*N).arcnum);
	printf("请输入%d个顶点的值:\n",N->vexnum);
	for(i=0;i<N->vexnum;i++){
		scanf("%s",N->vertex[i].data);
		N->vertex[i].firstarc=NULL;	//将相关联的顶点置为空
	}
	printf("请输入弧尾和弧头(以空格作为间隔):\n");
	for(k=0;k<N->arcnum;k++){	//建立边链表
		scanf("%s%s%*c%d",v1,v2,&w);
		i=LocateVertex(*N,v1);
		j=LocateVertex(*N,v2);
		//j为弧头i为弧尾创建邻接表
		p=(ArcNode *)malloc(sizeof(ArcNode));
		p->adjvex=j;
		p->info=(InfoPtr*)malloc(sizeof(InfoPtr));
		*(p->info)=w;
		//将p指向的结点插入到边表中
		p->nextarc=N->vertex[i].firstarc;
		N->vertex[i].firstarc=p;
	}
	(*N).kind=DN;
}
//销毁无向图G
void DestroyGraph(AdjGraph *G){
	int i;
	ArcNode *p,*q;
	for(i=0;i<(*G).vexnum;++i){	//释放图中的边表结点
		p=G->vertex[i].firstarc;	//p指向边表的第一个结点
		if(p!=NULL){	//如果边表不为空,则释放边表的结点
			q=p->nextarc;
			free(p);
			p=q;
		}
	}
	(*G).vexnum=0;	//将顶点数置为0
	(*G).arcnum=0;	//将边的数目置为0
}
//输出图的邻接表
void DisplayGraph(AdjGraph G){
	int i;
	ArcNode *p;
	printf("%d个顶点:\n",G.vexnum);
	for(i=0;i<G.vexnum;i++)
		printf("%s ",G.vertex[i].data);
	printf("\n%d条边:\n",G.arcnum);
	for(i=0;i<G.vexnum;i++)
	{
		p=G.vertex[i].firstarc;
		while(p)
		{
			printf("<%s,%s,%d> ",G.vertex[i].data,G.vertex[p->adjvex].data,*(p->info));
			p=p->nextarc;
		}
		printf("\n");
	}
}
//*********************************************************
int ve[MaxSize]; //ve存放事件最早发生时间
/*采用邻接表存储结构的有向网N的拓扑排序,并求各顶点对应事件的最早发生时间ve*/
/*如果N无回路,则用用栈T返回N的一个拓扑序列,并返回1,否则为0*/
int TopologicalOrder(AdjGraph N,SeqStack *T){
	int i,k,count=0;
	int indegree[MaxSize];	//数组indegree存储各顶点的入度
	SeqStack S;
	ArcNode *p;
	//将图中各顶点的入度保存在数组indegree中
	for(i=0;i<N.vexnum;i++) //将数组indegree赋初值
		indegree[i]=0;
	for(i=0;i<N.vexnum;i++){
		p=N.vertex[i].firstarc;
		while(p!=NULL){
			k=p->adjvex;
			indegree[k]++;
			p=p->nextarc;
		}
	}
	//初始化栈S
	InitStack(&S);
	printf("拓扑序列:");
	for(i=0;i<N.vexnum;i++)
		if(!indegree[i])	//将入度为零的顶点入栈
			PushStack(&S,i);
	InitStack(T);	//初始化逆拓扑排序顶点栈
	for(i=0;i<N.vexnum;i++)	//初始化ve
		ve[i]=0;
	while(!StackEmpty(S)){	//如果栈S不为空
		PopStack(&S,&i);	//从栈S将已拓扑排序的顶点i弹出
		printf("%s ",N.vertex[i].data);
		PushStack(T,i);	//i号顶点入逆拓扑排序栈T
		count++;	//对入栈T的顶点计数
		for(p=N.vertex[i].firstarc;p;p=p->nextarc){	//处理编号为i的顶点的每个邻接点
			k=p->adjvex;		//顶点序号为k
			if(--indegree[k]==0)	//如果k的入度减1后变为0,则将k入栈S
				PushStack(&S,k);
			if(ve[i]+*(p->info)>ve[k])	//计算顶点k对应的事件的最早发生时间
				ve[k]=ve[i]+*(p->info);
		}
	}
	if(count<N.vexnum){
		printf("该有向网有回路\n");
		return 0;
	}else
		return 1;
}
//输出AOE网N的关键路径
int CriticalPath(AdjGraph N){
	int vl[MaxSize];	//事件最晚发生时间
	SeqStack T;
	int i,j,k,e,l,dut,value,count,e1[MaxSize],e2[MaxSize];
	ArcNode *p;
	if(!TopologicalOrder(N,&T))	//如果有环存在,则返回0
		return 0;
	value=ve[0];
	for(i=1;i<N.vexnum;i++)
		if(ve[i]>value)
			value=ve[i];	//value为事件的最早发生时间的最大值
	for(i=0;i<N.vexnum;i++) //将顶点事件的最晚发生时间初始化
		vl[i]=value;
	while(!StackEmpty(T))	//按逆拓扑排序求各顶点的vl值
		for(PopStack(&T,&j),p=N.vertex[j].firstarc;p;p=p->nextarc){ //弹出栈T的元素,赋给j,p指向j的后继事件k
			k=p->adjvex;
			dut=*(p->info);	//dut为弧<j,k>的权值
			if(vl[k]-dut<vl[j])//计算事件j的最迟发生时间
				vl[j]=vl[k]-dut;
		}
		printf("\n事件的最早发生时间和最晚发生时间\ni ve[i] vl[i]\n");
		for(i=0;i<N.vexnum;i++)		//输出顶点对应的事件的最早发生时间最晚发生时间
			printf("%d   %d     %d\n",i,ve[i],vl[i]);
		printf("关键路径为:(");
		for(i=0;i<N.vexnum;i++) //输出关键路径经过的顶点
			if(ve[i]==vl[i])
				printf("%s ",N.vertex[i].data);
		printf(")\n");
		count=0;
		printf("活动最早开始时间和最晚开始时间\n   弧    e   l   l-e\n");
		for(j=0;j<N.vexnum;j++)
			for(p=N.vertex[j].firstarc;p;p=p->nextarc){
				k=p->adjvex;
				dut=*(p->info);	//dut为弧<j,k>的权值
				e=ve[j];		//e就是活动<j,k>的最早开始时间
				l=vl[k]-dut;	//l就是活动<j,k>的最晚开始时间
				printf("%s→%s %3d %3d %3d\n",N.vertex[j].data,N.vertex[k].data,e,l,l-e);
				if(e==l){	//将关键活动保存在数组中
					e1[count]=j;
					e2[count]=k;
					count++;
				}
			}
		printf("关键活动为:");
		for(k=0;k<count;k++)		//输出关键路径
		{
			i=e1[k];
			j=e2[k];
			printf("(%s→%s) ",N.vertex[i].data,N.vertex[j].data);
		}
		printf("\n");
	return 1;
}
void main(){
	AdjGraph N;
	CreateGraph(&N);		/*采用邻接表存储结构创建有向网N*/
	DisplayGraph(N);		/*输出有向网N*/
	CriticalPath(N);		/*求网N的关键路径*/
	DestroyGraph(&N);		/*销毁网N*/
	system("pause");
}

#pragma once
#include<stdio.h>
#include<stdlib.h>
#define StackSize 100
typedef int DataType;	//栈元素类型定义
typedef struct{
	DataType stack[StackSize];
	int top;
}SeqStack;
//将栈初始化为空栈只需要把栈顶指针top置为
void InitStack(SeqStack *S){
	S->top=0;//把栈顶指针置为0
}
//判断栈是否为空,栈为空返回1,否则返回0
int StackEmpty(SeqStack S){
	if(S.top==0)
		return 1;
	else
		return 0;
}
//取栈顶元素。将栈顶元素值返回给e,并返回1表示成功;否则返回0表示失败。
int GetTop(SeqStack S,DataType *e){
	if(S.top<=0){		//在取栈顶元素之前,判断栈是否为空
		printf("栈已经空!\n");
		return 0;
	}else{
		*e=S.stack[S.top-1];	//在取栈顶元素
		return 1;
	}
}
//将元素e进栈,元素进栈成功返回1,否则返回0
int PushStack(SeqStack *S,DataType e){
	if(S->top>=StackSize){	//在元素进栈前,判断是否栈已经满
		printf("栈已满,不能进栈!\n");
		return 0;
	}else{
		S->stack[S->top]=e;	//元素e进栈
		S->top++;	//修改栈顶指针
		return 1;
	}
}
//出栈操作。将栈顶元素出栈,并将其赋值给e。出栈成功返回1,否则返回0
int PopStack(SeqStack *S,DataType *e){
	if(S->top<=0){	//元素出栈之前,判断栈是否为空
		printf("栈已经没有元素,不能出栈!\n");
		return 0;
	}else{
		S->top--;	//先修改栈顶指针,即出栈
		*e=S->stack[S->top]; //将出栈元素赋值给e
		return 1;
	}
}
//求栈的长度,即栈中元素个数,栈顶指针的值就等于栈中元素的个数
int StackLength(SeqStack S){
	return S.top;
}
//清空栈的操作
void ClearStack(SeqStack *S){
	S->top=0;
}
技术分享

版权声明:本文为博主原创文章,未经博主允许不得转载|Copyright ©2011-2015,Supernatural, All Rights Reserved.

_DataStructure_C_Impl:AOE网的关键路径

标签:数据结构

原文地址:http://blog.csdn.net/williamfan21c/article/details/47430355

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!