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 }