拓撲排序算法
拓撲序列:spa
設G=(V,E)是一個具備n個頂點的有向圖,V中頂點序列V1,V2,......,Vn知足若從頂點Vi到Vj有一條路徑,則在頂點序列中頂點Vi必須在頂點Vj以前。則稱這樣的頂點序列爲一個拓撲序列指針
拓撲排序code
對一個無環有向圖(AOV網)構造拓撲序列的過程blog
方法排序
由於要刪除點和邊,因此用鄰接表較爲方便索引
1 #define MAXVEX 10 2 3 //邊表結點聲明 4 typedef struct EdgeNode{ 5 int adjvex; 6 struct EdgeNode *next; 7 }EdgeNode; 8 9 //頂點結點聲明 10 typedef struct VertexNode{ 11 int in;//頂點入度 12 int data; 13 EdgeNode *firstedge; 14 }VertexNode,AdjList[MAXVEX]; 15 16 typedef struct{ 17 AdjList adjList; 18 int numVertexes,numEdges; 19 }graphAdjList,* GraphAdjList; 20 21 //拓撲排序算法 22 //若GL無迴路,則會輸入拓撲排序序列並返回OK,不然返回ERROE 23 Status TopoLogicalSort(GraphAdjList GL){ 24 EdgeNode *e; 25 int i,k,gettop; 26 int top=0;//用於棧指針下標索引 27 int count=0;//用於統計輸出頂點的個數 28 int *stact;//用於存儲入度爲0的頂點 29 30 stact=(int *)malloc(GL->numVertexes*sizeof(int)); 31 32 for(i=0;i<GL->numVertexes;i++){ 33 if(0==GL->adjList[i].in){ 34 stack[++top]=i;//將度爲0的頂點下標入棧 35 } 36 } 37 38 while(0!=top){ 39 gettop=stact[top--];//出棧 40 printf("%d -> ",GL->adjList[gettop].data); 41 count++; 42 for(e=GL->adjList[gettop].firstedge;e;e=e->next){ 43 k=e->adjvex; 44 //注意:下邊這個if條件是分析整個程序的要點 45 //將k號頂點鄰接頂的入度-1;由於他的前序已經刪除 46 //接着判斷-1後入度爲是否爲0,若是爲0則也入棧 47 if(!(--GL->adjList[k].in)){ 48 stack[++top]=k; 49 } 50 } 51 } 52 if(count<GL->numVertexes){//若是count小於頂點數,說明存在環 53 return ERROR; 54 }else{ 55 return OK; 56 } 57 }
關鍵路徑事件
AOE網get
在一個表示工程的帶權有向圖中,用頂點表示事件,用有向邊表示活動,用邊上的權值表示活動的持續時間,這種有向圖的邊表示活動的網。把沒入度的頂點稱爲始點或源點,沒有出度的頂點稱爲終點或匯點it
關鍵路徑就是決定整個工程時間的路徑;由於工程中有些步驟要在一些步驟完成的基礎上才能進行,而有些則不須要,這種沒有制約的步驟就能夠同時進行,而決定整個整個工程時間的就是這種相互制約的步驟的最長時間和
思路
正向求處事件的最先發生時間,和反向求出事件最晚發生時間;而後根據事件的etv、ltv求出活動的ete和lte;【ete==lte的活動,爲關鍵活動,關鍵活動組成的路徑是關鍵路徑】
注:etv和ltv是針對事件的,ete和lte是針對活動的;而且根據etv、ltv和活動須要的時間是能夠求出活動ete和lte的;【活動:etv就是弧尾頂點事件的最先發生時間;lte就是弧頭頂底事件ltv(最晚時間)-活動所需時間】
1 #define MAXVEX 10 2 3 //邊表結點聲明 4 typedef struct EdgeNode{ 5 int adjvex; 6 int weight; 7 struct EdgeNode *next; 8 }EdgeNode; 9 10 //頂點結點聲明 11 typedef struct VertexNode{ 12 int in;//頂點入度 13 int data; 14 EdgeNode *firstedge; 15 }VertexNode,AdjList[MAXVEX]; 16 17 typedef struct{ 18 AdjList adjList; 19 int numVertexes,numEdges; 20 }graphAdjList,* GraphAdjList; 21 22 int *etv,ltv; 23 int *stact2;//用於存儲拓撲序列的棧 24 int top2;//用於stack2的棧頂指針 25 26 //拓撲排序算法 27 //若GL無迴路,則會輸入拓撲排序序列並返回OK,不然返回ERROE 28 Status TopoLogicalSort(GraphAdjList GL){ 29 EdgeNode *e; 30 int i,k,gettop; 31 int top=0;//用於棧指針下標索引 32 int count=0;//用於統計輸出頂點的個數 33 int *stact;//用於存儲入度爲0的頂點 34 35 stact=(int *)malloc(GL->numVertexes*sizeof(int)); 36 37 for(i=0;i<GL->numVertexes;i++){ 38 if(0==GL->adjList[i].in){ 39 stack[++top]=i;//將度爲0的頂點下標入棧 40 } 41 } 42 43 //初始化etv都爲0; 44 top2=0; 45 etv=(int *)malloc(GL->numVertexes*sizeof(int)); 46 for(i=0;i<GL->numVertexes;i++){ 47 etv[i]=0; 48 } 49 stack2=(int *)malloc(GL->numVertexes*sizeof(int)); 50 51 while(0!=top){ 52 gettop=stact[top--];//出棧 53 //printf("%d -> ",GL->adjList[gettop].data); 54 stack2[++top2]=gettop;//保存拓撲序列順序;頂點順序 55 count++; 56 57 for(e=GL->adjList[gettop].firstedge;e;e=e->next){//操做邊表 58 k=e->adjvex; 59 //注意:下邊這個if條件是分析整個程序的要點 60 //將k號頂點鄰接頂的入度-1;由於他的前序已經刪除 61 //接着判斷-1後入度爲是否爲0,若是爲0則也入棧 62 if(!(--GL->adjList[k].in)){ 63 stack[++top]=k; 64 } 65 66 //這裏刪除了一個入度爲0的點,刪除頂點(事件)的最先發生時間+邊表頂點之間的弧(活動)的權就是邊表頂點(事件)最先發生時間 67 //可能一個頂點(事件)有多個入度,就是有多個活動完成前提,因此要等這些前提活動都完成了才能夠開始頂點(事件),因此這個頂點(事件)最先發生時間要選那個最晚的 68 if((etv[gettop]+e->weight)>etv[k]){ 69 etv[k]=etv[gettop]+e->weight; 70 } 71 } 72 } 73 if(count<GL->numVertexes){//若是count小於頂點數,說明存在環 74 return ERROR; 75 }else{ 76 return OK; 77 } 78 } 79 80 //求關鍵路徑,GL爲有向圖;輸出GL的各項關鍵活動 81 void CriticalPath(GraphAdjList GL){ 82 EdgeNode *e; 83 int i,gettop,k,j; 84 int ete,lte; 85 86 //調用改進後的拓撲排序,求出etv和stack2的值 87 TopoLogicalSort(GL); 88 89 //初始化ltv都爲匯點時間; 90 ltv=(int *)malloc(GL->numVertexes*sizeof(int)); 91 for(i=0;i<GL->numVertexes;i++){ 92 ltv[i]=etv[GL->numVertexes-1]; 93 } 94 95 //從匯點倒過來逐個計算ltv 96 while(0!=top2){ 97 gettop=stack2[top2--];//注意,第一個出棧的就是匯點 98 for(e=GL->adjList[gettop].firstedge;e;e=e->next){//操做邊表 99 k=e->adjvex;//弧頭頂點★★★ 100 //這裏的頂點(事件)最晚發生時間爲:出度的弧頭(頂點)最晚發生時間-弧權(活動延續時間) 101 //固然可能有多個出度,爲保證每一個出度活動不延續整個工程,因此要取那個最先的弧(活動)的最晚發生時間 102 if((ltv[k]-e->weight)<ltv[gettop]){ 103 ltv[gettop]=ltv[k]-e->weight; 104 } 105 } 106 } 107 108 //經過etv和ltv求出ete和lte 109 for(j=0;j<GL->numVertexes;e=e->next){ 110 for(e=GL->adjList[j].firstedge;e;e=e->next){//操做邊表 111 k=e->adjvex;//弧頭頂點 112 //弧(活動)最先發生時間就是弧尾頂點(事件)最先發生時間 113 ete=etv[j]; 114 //弧(活動)最晚發生時間就是:弧頭頂點(事件)最晚發生時間-弧權(活動延續時間) 115 lte=ltv[k]-e->weight; 116 117 if(ete==lte){//活動的最先發生時間==活動的最晚發生時間爲關鍵活動,關鍵活動組成的路徑爲關鍵路徑 118 printf("<V%d,V%d>length:%d ",GL->adjList[j].data,GL->adjList[k].data,e->weight); 119 } 120 } 121 } 122 }