【数据结构】关键路径

前端之家收集整理的这篇文章主要介绍了【数据结构】关键路径前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

关键路径

数据结构中 求关键路径,以前写的代码,传给大家看看!


/*
	名称:关键路径 
	语言:数据结构C语言版 
	编译环境:VC++ 6.0
	日期:2014-3-25 
*/
#include <stdio.h>  
#include <limits.h>  
#include <malloc.h>      
#include<cstdlib>   
#include <string.h>

//  求关键路径。实现算法7.13、7.14的程序 

// 图的邻接表存储表示 
#define MAX_NAME 3					// 顶点字符串的最大长度+1 
#define MAX_VERTEX_NUM 20
typedef int InfoType;				// 存放网的权值 
typedef char VertexType[MAX_NAME];	// 字符串类型 
typedef enum{DG,DN,AG,AN}GraphKind; // {有向图,有向网,无向图,无向网} 

typedef struct ArcNode
{
	int adjvex;					// 该弧所指向的顶点的位置 
	struct ArcNode *nextarc;	// 指向下一条弧的指针 
	InfoType *info;				// 网的权值指针) 
}ArcNode;	// 表结点 

typedef struct VNode
{
	VertexType data;			// 顶点信息 
	ArcNode *firstarc;			// 第一个表结点的地址,指向第一条依附该顶点的弧的指针 
 }VNode,AdjList[MAX_VERTEX_NUM];// 头结点 

typedef struct
{
	AdjList vertices;
	int vexnum,arcnum;	// 图的当前顶点数和弧数 
	int kind;			// 图的种类标志 
}ALGraph;

int ve[MAX_VERTEX_NUM]; // 全局变量(用于算法7.13和算法7.14) 


// 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。 
int LocateVex(ALGraph G,VertexType u)
{
	int i;
	for(i=0;i<G.vexnum;++i)
		if(strcmp(u,G.vertices[i].data)==0)
			return i;
	return -1;
}

// 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)。
int CreateGraph(ALGraph *G)
{
	int i,j,k;
	int w;		// 权值 
	VertexType va,vb;
	ArcNode *p;
	
	printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
	scanf("%d",&(*G).kind);
	printf("请输入图的顶点数和边数:(空格)\n");
	scanf("%d%d",&(*G).vexnum,&(*G).arcnum);
	printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
	for(i = 0; i < (*G).vexnum; ++i)	// 构造顶点向量 
	{
		scanf("%s",(*G).vertices[i].data);
		(*G).vertices[i].firstarc = NULL;
	}
	if((*G).kind == 1 || (*G).kind == 3) // 网 
		printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
	else // 图 
		printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
	for(k = 0;k < (*G).arcnum; ++k)	// 构造表结点链表 
	{
		if((*G).kind==1||(*G).kind==3) // 网 
			scanf("%d%s%s",&w,va,vb);
		else			// 图 
			scanf("%s%s",vb);
		i = LocateVex(*G,va); // 弧尾 
		j = LocateVex(*G,vb); // 弧头 
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j;
		if((*G).kind == 1 || (*G).kind == 3) // 网 
		{
			p->info = (int *)malloc(sizeof(int));
			*(p->info) = w;
		}
		else
			p->info = NULL; // 图 
		p->nextarc = (*G).vertices[i].firstarc; // 插在表头 
		(*G).vertices[i].firstarc = p;
		if((*G).kind >= 2) // 无向图或网,产生第二个表结点 
		{
			p = (ArcNode*)malloc(sizeof(ArcNode));
			p->adjvex = i;
			if((*G).kind == 3) // 无向网 
			{
				p->info = (int*)malloc(sizeof(int));
				*(p->info) = w;
			}
			else
				p->info = NULL; // 无向图 
			p->nextarc = (*G).vertices[j].firstarc; // 插在表头 
			(*G).vertices[j].firstarc = p;
		}
	}
	return 1;
}

//	输出图的邻接表G。
void Display(ALGraph G)
{
	int i;
	ArcNode *p;

	switch(G.kind)
	{
	case DG: printf("有向图\n");
		break;
	case DN: printf("有向网\n");
		break;
	case AG: printf("无向图\n");
		break;
	case AN: printf("无向网\n");
	}
	printf("%d个顶点:\n",G.vexnum);
	for(i = 0; i < G.vexnum; ++i)
		printf("%s ",G.vertices[i].data);
	printf("\n%d条弧(边):\n",G.arcnum);
	for(i = 0; i < G.vexnum; i++)
	{
		p = G.vertices[i].firstarc;
		while(p)
		{
			if(G.kind <= 1) // 有向 
			{
				printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
				if(G.kind == DN) // 网 
					printf(":%d ",*(p->info));
			}
			else	// 无向(避免输出两次) 
			{
				if(i < p->adjvex)
				{
					printf("%s-%s ",G.vertices[p->adjvex].data);
					if(G.kind == AN)	// 网 
						printf(":%d ",*(p->info));
				}
			}
			p=p->nextarc;
		}
		printf("\n");
	}
}


// 求顶点的入度,算法7.12、7.13调用
void FindInDegree(ALGraph G,int indegree[])
{
	int i;
	ArcNode *p;
	
	for(i=0;i<G.vexnum;i++)
		indegree[i]=0; // 赋初值 
	for(i=0;i<G.vexnum;i++)
	{
		p=G.vertices[i].firstarc;
		while(p)
		{
			indegree[p->adjvex]++;
			p=p->nextarc;
		}
	}
}

typedef int SElemType; // 栈类型

#define STACK_INIT_SIZE 10	// 存储空间初始分配量 
#define STACKINCREMENT 2	// 存储空间分配增量 
// 栈的顺序存储表示 P46 
typedef struct SqStack
{
	SElemType *base;	// 在栈构造之前和销毁之后,base的值为NULL 
	SElemType *top;		// 栈顶指针 
	int stacksize;		// 当前已分配的存储空间,以元素为单位 
}SqStack;	// 顺序栈



//	构造一个空栈S。
int InitStack(SqStack *S)
{
	// 为栈底分配一个指定大小的存储空间
	(*S).base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
	if( !(*S).base )
		exit(0);		// 存储分配失败 
	(*S).top = (*S).base;	// 栈底与栈顶相同表示一个空栈
	(*S).stacksize = STACK_INIT_SIZE;
	return 1;
}

// 若栈S为空栈(栈顶与栈底相同的),则返回1,否则返回0。
int StackEmpty(SqStack S)
{
	if(S.top == S.base)
		return 1;
	else
		return 0;
}

//	插入元素e为新的栈顶元素。
int Push(SqStack *S,SElemType e)
{
	if((*S).top - (*S).base >= (*S).stacksize)	// 栈满,追加存储空间 
	{
		(*S).base = (SElemType *)realloc((*S).base,((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
		if( !(*S).base )
			exit(0); // 存储分配失败 
		(*S).top = (*S).base+(*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++=e;
	// 这个等式的++ * 优先级相同,但是它们的运算方式,是自右向左
	return 1;
}

//	若栈不空,则删除S的栈顶元素,用e返回其值,并返回1;否则返回0。
int Pop(SqStack *S,SElemType *e)
{
	if((*S).top == (*S).base)
		return 0;
	*e = *--(*S).top;
	// 这个等式的++ * 优先级相同,但是它们的运算方式,是自右向左
	return 1;
}

// 算法7.13  P185
// 有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve (全局变量)。
// T为拓扑序列顶点栈,S为零入度顶点栈。若G无回路,则用栈T返回G的一个拓
// 扑序列,且函数值为1,否则为0 
int TopologicalOrder(ALGraph G,SqStack *T)
{
	int j,k,count,indegree[MAX_VERTEX_NUM];
	SqStack S;
	ArcNode *p;
	
	FindInDegree(G,indegree);//对各顶点求入度indegree[0..vernum-1] 
	InitStack(&S); // 初始化栈 
	for(j=0;j<G.vexnum;++j) // 建零入度顶点栈S 
		if(!indegree[j])
			Push(&S,j); // 入度为0者进栈 
	InitStack(T); // 初始化拓扑序列顶点栈 
	count=0; // 对输出顶点计数 
	for(j=0;j<G.vexnum;++j) // 初始化ve[]=0 (最小值) 
		ve[j]=0;
	while(!StackEmpty(S))
	{
		// 栈不空 
		Pop(&S,&j);
		Push(T,j); // j号顶点入T栈并计数 
		++count;
		for(p=G.vertices[j].firstarc;p;p=p->nextarc)
		{
			// 对j号顶点的每个邻接点的入度减1 
			k=p->adjvex;
			if(--indegree[k]==0) // 若入度减为0,则入栈 
				Push(&S,k);
			if(ve[j]+*(p->info)>ve[k])
				ve[k]=ve[j]+*(p->info);
		}
	}
	if(count<G.vexnum)
	{
		printf("此有向网有回路\n");
		return 0;
	}
	else
		return 1;
}

// 算法7.14 P185
// G为有向网,输出G的各项关键活动
int CriticalPath(ALGraph G)
{ 
	int vl[MAX_VERTEX_NUM];
	SqStack T;
	int i,ee,el;
	ArcNode *p;
	char dut,tag;
	
	if(!TopologicalOrder(G,&T)) // 产生有向环 
		return 0;
	j=ve[0];
	for(i=1;i<G.vexnum;i++) // j=Max(ve[]) 完成点的值 
		if(ve[i]>j)
			j=ve[i];
	for(i=0;i<G.vexnum;i++) // 初始化顶点事件的最迟发生时间(最大值) 
		vl[i]=j; // 完成点的最早发生时间 
	while(!StackEmpty(T)) // 按拓扑逆序求各顶点的vl值 
		for(Pop(&T,&j),p=G.vertices[j].firstarc;p;p=p->nextarc)
		{
			k=p->adjvex;
			dut=*(p->info); // dut<j,k> 
			if(vl[k]-dut<vl[j])
				vl[j]=vl[k]-dut;
		}
	printf(" j  k  dut  ee  el  tag\n");
	for(j=0;j<G.vexnum;++j) // 求ee,el和关键活动 
	for(p=G.vertices[j].firstarc;p;p=p->nextarc)
	{
		k=p->adjvex;
		dut=*(p->info);
		ee=ve[j];
		el=vl[k]-dut;
		tag=(ee==el)?'*':' ';
		// 输出关键活动
		printf("%2d %2d %3d %3d %3d    %c\n",dut,el,tag); 
	}
	printf("关键活动为:\n");
	for(j=0;j<G.vexnum;++j) // 同上 
	for(p=G.vertices[j].firstarc;p;p=p->nextarc)
	{
		k=p->adjvex;
		dut=*(p->info);
		if(ve[j]==vl[k]-dut)
			// 输出关键活动 
			printf("%s→%s\n",G.vertices[j].data,G.vertices[k].data); 
	}
	return 1;
}

int main()
{
	ALGraph h;
	printf("请选择有向网\n");
	CreateGraph(&h);
	Display(h);
	CriticalPath(h);
	
	system("pause");
	return 0;
}

/*
输出效果:

请选择有向网
请输入图的类型(有向图:0,无向网:3): 1
请输入图的顶点数和边数:(空格)
6 8
请输入6个顶点的值(<3个字符):
v1
v2
v3
v4
v5
v6
请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):
3 v1 v2
2 v1 v3
2 v2 v4
3 v2 v5
4 v3 v4
3 v3 v6
2 v4 v6
1 v5 v6
有向网
6个顶点:
v1 v2 v3 v4 v5 v6
8条弧(边):
v1→v3 :2 v1→v2 :3
v2→v5 :3 v2→v4 :2
v3→v6 :3 v3→v4 :4
v4→v6 :2
v5→v6 :1

 j  k  dut  ee  el  tag
 0  2   2   0   0    *
 0  1   3   0   1
 1  4   3   3   4
 1  3   2   3   4
 2  5   3   2   5
 2  3   4   2   2    *
 3  5   2   6   6    *
 4  5   1   6   7
关键活动为:
v1→v3
v3→v4
v4→v6
请按任意键继续. . . 

*/
原文链接:https://www.f2er.com/datastructure/383076.html

猜你在找的数据结构相关文章