View Code
1 // 优先队列的Dijkstra算法.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <stdio.h> 6 #include <queue> 7 #include <vector> 8 #include <stdlib.h> 9 using namespace std; 10 #define NotAVertex (-1) 11 #define NumVertex 20 12 #define Infinity 1000 13 typedef int Vertex; 14 typedef int Arc; 15 typedef int DistType; 16 //typedef struct TableEntry* List; 17 18 struct TableNode //表节点 19 { 20 Vertex V; 21 DistType Weigh; //边重 22 struct TableNode* NextArc; 23 }; 24 25 typedef struct TableNode* EdgeNode; 26 typedef struct ListNode* VexNode; //定义头节点指针 27 struct ListNode //头节点 28 { 29 Vertex V; 30 EdgeNode FirstArc; 31 DistType Dist; 32 int Known; 33 Vertex Path; 34 35 friend bool operator> ( struct ListNode n1,struct ListNode n2) //因为使用到greater模板 需要操作符>重载 36 { 37 return n1.Dist> n2.Dist; 38 } 39 40 }; 41 42 //typedef struct ListNode Node[NumVertex]; 43 typedef struct ListNode ListNode; 44 priority_queue<ListNode,vector<ListNode>,greater<ListNode> > PriorVexQue; //申明优先级队列的类型 默认是less 45 46 struct Graphic //图的结构体 包括有边数,点数,头节点数组 47 { 48 Vertex VertexNum; 49 Arc ArcNum; 50 struct ListNode Adj[NumVertex]; 51 }; 52 53 typedef struct Graphic* Graph; 54 55 void ReadGraph(Graph G) //图的输入函数 56 { 57 Vertex from,to; 58 DistType weight; 59 struct TableNode *S; 60 printf("请输入节点数和边数,注意为整型!\n"); 61 scanf("%d%d",&(G->VertexNum),&(G->ArcNum)); 62 if(G->ArcNum<=0||G->VertexNum<=0) 63 { 64 printf("图边数或点数必须大于零\n"); 65 return; 66 } 67 for(int i =0;i<G->ArcNum;i++) 68 { 69 printf("请输入第%d条边的起点,终点和权值!\n",i+1); 70 scanf("%d%d%d",&from,&to,&weight); 71 S=(EdgeNode)malloc(sizeof(struct TableNode)); 72 S->V=to; 73 S->Weigh=weight; 74 S->NextArc=G->Adj[from].FirstArc; //这里是from的头边给S的下一条边,这里是表节点插入细节,好好体会下。 75 G->Adj[from].FirstArc=S; 76 } 77 78 } 79 80 void InitNode(Graph G) //图的初始化 81 { 82 int i ; 83 for(i=0;i<NumVertex;i++) 84 { 85 G->Adj[i].V=i; 86 G->Adj[i].Path=NotAVertex; 87 G->Adj[i].Known=false; 88 G->Adj[i].Dist=Infinity; 89 G->Adj[i].FirstArc=NULL; 90 } 91 ReadGraph(G); 92 G->Adj[0].Dist=0; 93 } 94 #if 0 95 96 Vertex ExtractMin(Graph G) //较为简单的寻找最小值函数,复杂度O(n),一直不是很满意 97 { 98 int i;int j=Infinity; 99 Vertex Min=Infinity; 100 for(i=0;i<G->VertexNum;i++) 101 { 102 if(!(G->Adj[i].Known)&&Min>G->Adj[i].Dist)//刚开始犯了一个很傻的错误,这里的第二个条件放到第一个循环了,总是不对。 103 { 104 Min=G->Adj[i].Dist; 105 j=i; 106 } 107 } 108 if(j==Infinity) return -1; 109 return j; 110 } 111 #endif 112 113 114 115 void PrintPath(Graph G,Vertex V) //打印分支函数,只能打印一条分支。 116 { 117 if(G->Adj[V].Path!=NotAVertex) 118 { 119 PrintPath(G,G->Adj[V].Path); 120 printf("to"); 121 } 122 printf(" %d ",V); 123 } 124 125 126 127 void Dijkstra(Graph G) //函数::步步贪心,最终全体贪心 128 { 129 Vertex Value; 130 EdgeNode pVex; 131 PriorVexQue.push(G->Adj[0]); 132 for(int i=0;i<G->VertexNum;i++) 133 { 134 Value=PriorVexQue.top().V; //抽取图中最小距离的点,纳入{S} 135 PriorVexQue.pop(); 136 if(Value==NotAVertex) 137 break; 138 G->Adj[Value].Known=true; 139 pVex=G->Adj[Value].FirstArc; 140 // pEdge=pVex->NextArc; 141 while(pVex!=NULL) //对图{Q-S}点的集合中与距离最小点毗邻的点做松弛操作 142 { 143 144 if(!(G->Adj[pVex->V].Known)) //邻接的节点更新 145 { 146 if(G->Adj[Value].Dist+pVex->Weigh< G->Adj[pVex->V].Dist) 147 { 148 G->Adj[pVex->V].Dist=G->Adj[Value].Dist+pVex->Weigh; 149 G->Adj[pVex->V].Path=Value; 150 } 151 PriorVexQue.push(G->Adj[pVex->V]); 152 } 153 pVex=pVex->NextArc; 154 } 155 } 156 } 157 158 Vertex ReturnDistMax(Graph G) //这个函数是为了方便Print调用的,可以不要。 159 { 160 int i; 161 Vertex key=0; 162 DistType Max=0; 163 for(i=0;i<G->VertexNum;i++) 164 if(G->Adj[i].Dist>Max) 165 { 166 Max=G->Adj[i].Dist; 167 key=i; 168 } 169 return key; 170 171 172 } 173 174 175 int _tmain(int argc, _TCHAR* argv[]) 176 { 177 int i; 178 Vertex V; 179 Graph G=(Graph)malloc(sizeof(Graphic)); 180 InitNode(G); 181 Dijkstra(G); 182 // PrintPath(G,4); 183 printf("\n"); 184 for(i=0;i<G->VertexNum;i++) 185 { 186 printf("## %d ##",G->Adj[i].Dist); 187 printf("##$ %d $##",G->Adj[i].Path); 188 } 189 190 V=ReturnDistMax(G); 191 192 PrintPath(G,V); 193 194 195 196 return 0; 197 }