_DataStructure_C_Impl:AOE網的關鍵路徑
阿新 • • 發佈:2017-06-25
adjlist 存儲 pos 輸出 回路 無向圖 structure amp cal
//_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; }
_DataStructure_C_Impl:AOE網的關鍵路徑