数据结构图之四(最短路径--弗洛伊德算法)
【1】为什么需要弗洛伊德算法?
带权图中单个源点到所有顶点的最短路径问题可以用《迪杰斯特拉算法》求解。
那如果要求图中每一个顶点与其它顶点之间的最短路径呢?类似可以想到的方法为:
每次以一个顶点为源点,重复执行地杰斯特拉算法算法n次。
这样,理论上我们便可以求得每一个顶点与其它顶点的最短路径,总的执行时间为O(n3)。
好吧!为了实现这个中需求,可以采用另外一种求解算法:弗洛伊德算法。
为了更好的理解弗洛伊德算法的精妙,我们先看简单的案例。
如下图是一个最简单的3个顶点连通网图:
【2】弗洛伊德算法
弗洛伊德算法是非常漂亮的算法,简洁直观大气上档次。
不过很可惜由于它的三重循环,因此也是O(n*n*n)的时间复杂度。
如果你面临需要求所有顶点至所有顶点的最短路径问题?
它是很好的选择。算法代码如下图:
关于本算法再不做详细赘述。如若感兴趣,下面的代码案例可以自己琢磨琢磨。
【3】弗洛伊德算法实现
注意:本算法的实现案例与迪杰斯特拉算法相同都是在求同一个图的最短路径问题。
不同的是这个算法可以求得所有顶点到所有顶点的最短路径。
模拟实现代码如下:
1 #include <iostream> 2 #include "SeqList.h" 3 #include <iomanip> 4 using namespace std; 5 6 #define INFINITY 65535 7 8 typedef int* pInt; 9 typedef pInt* ppInt; 10 11 template<class NameType, class DistType> 12 class Graph 13 { 14 private: 15 SeqList<NameType> Vertices; 16 DistType **Edges; 17 int nVer, nEdges; 18 19 public: 20 Graph() 21 : Edges(NULL) 22 , nEdges(0) 23 , nVer(0) 24 {} 25 ~Graph() 26 {} 27 28 public: 29 int GetVer() const 30 { 31 return nVer; 32 } 33 34 istream & operator>>(istream &in) 35 { 36 int v, u, value; 37 int i, j; 38 NameType item; 39 cout << "请输入顶点的个数: " << endl; 40 in >> nVer; 41 cout << "请输入顶点的数据信息: " << endl; 42 for (i = 0; i < nVer; ++i) 43 { 44 in >> item; 45 Vertices.push_back(item); // 保存全部顶点 46 } 47 /////二维数组的创建并初始化 48 Edges = new DistType*[nVer]; // DistType *ar[10]; 49 for (i = 0; i < nVer; ++i) 50 { 51 Edges[i] = new DistType[nVer]; 52 for (j = 0; j < nVer; ++j) 53 { 54 Edges[i][j] = 0; 55 } 56 } 57 cout << "请输入边的个数: " << endl; 58 in >> nEdges; 59 cout << "请输入边的信息:" << endl; 60 for (i = 0; i < nEdges; ++i) 61 { 62 in >> v >> u >> value; 63 Edges[v][u] = value; 64 Edges[u][v] = value; 65 } 66 return in; 67 } 68 ostream & operator<<(ostream &out) const 69 { 70 int i, j; 71 out << "顶点信息 " << endl; 72 for (i = 1; i <= nVer; ++i) 73 { 74 out << Vertices[i] << setw(5); 75 } 76 out << endl; 77 out << "矩阵信息:" << endl; 78 out << setw(10); 79 for (i = 1; i <= nVer; ++i) 80 { 81 out << Vertices[i] << setw(5); 82 } 83 out << endl; 84 for (i = 0; i < nVer; ++i) 85 { 86 out << Vertices[i+1] << setw(5); 87 for (j = 0; j < nVer; ++j) 88 { 89 if (0 == Edges[i][j] && i != j) 90 Edges[i][j] = INFINITY; 91 cout << Edges[i][j] << setw(5); 92 } 93 out << endl; 94 } 95 out << endl; 96 97 return out; 98 } 99 // 弗洛伊德算法实现 100 void ShortestPath_Floyd(int** p, int** D) 101 { 102 int v = 0, w = 0, k = 0; 103 // 初始化数据 104 for (v = 0; v < nVer; ++v) 105 { 106 for (w = 0; w < nVer; ++w) 107 { 108 D[v][w] = Edges[v][w]; 109 p[v][w] = w; 110 } 111 } 112 for (k = 0; k < nVer; ++k) 113 { 114 for (v = 0; v < nVer; ++v) 115 { 116 for(w = 0; w < nVer; ++w) 117 { 118 if (D[v][w] > D[v][k] + D[k][w]) 119 { 120 D[v][w] = D[v][k] + D[k][w]; 121 p[v][w] = p[v][k]; 122 } 123 } 124 } 125 } 126 } 127 // 打印矩阵信息 128 void PrintArray(ppInt pp) 129 { 130 cout << setw(10); 131 for (int i = 1; i <= nVer; ++i) 132 { 133 cout << Vertices[i] << setw(5); 134 } 135 cout << endl; 136 for (int i = 0; i < nVer; ++i) 137 { 138 cout << Vertices[i+1] << setw(5); 139 for (int j = 0; j < nVer; ++j) 140 { 141 cout << pp[i][j] << setw(5); 142 } 143 cout << endl; 144 } 145 cout << endl; 146 } 147 // 求解完成后打印所以路径信息 148 void PrintPath(ppInt pp, ppInt DD) 149 { 150 int v, k, w; 151 for (v = 0; v < nVer; ++v) 152 { 153 for (w = v+1; w < nVer; ++w) 154 { 155 cout << "V" << v << "-->" << "V" << w << " weight:" << DD[v][w] << endl; 156 k = pp[v][w]; 157 cout << "Path:V" << v; 158 while (k != w) 159 { 160 cout << "-->V" << k; 161 k = pp[k][w]; 162 } 163 cout << "-->V" << w << endl; 164 } 165 } 166 cout << endl; 167 } 168 }; 169 170 template<class NameType, class DistType> 171 istream & operator>>(istream &in, Graph<NameType,DistType> &g) 172 { 173 g >> in; 174 return in; 175 } 176 177 template<class NameType, class DistType> 178 ostream & operator<<(ostream &out, const Graph<NameType,DistType> &g) 179 { 180 g << out; 181 return out; 182 } 183 184 185 void main() 186 { 187 Graph<char, int> myg; 188 cin >> myg; 189 cout << "打印所有输入信息:" << endl; 190 cout << myg << endl; 191 cout << "求最短路径....." << endl; 192 int numVer = myg.GetVer(); 193 ppInt pPathmatirx = new pInt[numVer]; 194 for (int i = 0; i < numVer; ++i) 195 { 196 pPathmatirx[i] = new int[numVer]; 197 for (int j = 0; j < numVer; ++j) 198 { 199 pPathmatirx[i][j] = 0; 200 } 201 } 202 ppInt pShortPath = new pInt[numVer]; 203 for (int i = 0; i < numVer; ++i) 204 { 205 pShortPath[i] = new int[numVer]; 206 for (int j = 0; j < numVer; ++j) 207 { 208 pShortPath[i][j] = 0; 209 } 210 } 211 myg.ShortestPath_Floyd(pPathmatirx, pShortPath); 212 cout << "分别打印矩阵结果:" << endl; 213 cout << "各顶点最短路径:" << endl; 214 myg.PrintArray(pShortPath); 215 cout << "各最短路径前驱顶点下标值:" << endl; 216 myg.PrintArray(pPathmatirx); 217 cout << "打印全部最短路径:"<< endl; 218 myg.PrintPath(pPathmatirx, pShortPath); 219 // 释放二维数组 220 for (int i = 0; i < numVer; ++i) 221 delete []pPathmatirx[i]; 222 delete []pPathmatirx; 223 for (int i = 0; i < numVer; ++i) 224 delete []pShortPath[i]; 225 delete []pShortPath; 226 pPathmatirx = NULL; 227 pShortPath = NULL; 228 } 229 // 备注: 230 // 最短路径弗洛伊德算法实现 231 // 整理于2013-12-05 232 // 测试输入程序为: 233 /* 234 请输入顶点的个数: 235 9 236 请输入顶点的数据信息: 237 A B C D E F G H I 238 请输入边的个数: 239 16 240 请输入边的信息: 241 0 1 1 242 0 2 5 243 1 2 3 244 1 3 7 245 1 4 5 246 2 4 1 247 2 5 7 248 3 4 2 249 3 6 3 250 4 5 3 251 4 6 6 252 4 7 9 253 5 7 5 254 6 7 2 255 6 8 7 256 7 8 4 257 打印所有输入信息: 258 顶点信息 259 A B C D E F G H I 260 矩阵信息: 261 A B C D E F G H I 262 A 0 1 5655356553565535655356553565535 263 B 1 0 3 7 565535655356553565535 264 C 5 3 065535 1 7655356553565535 265 D65535 765535 0 265535 36553565535 266 E65535 5 1 2 0 3 6 965535 267 F6553565535 765535 3 065535 565535 268 G655356553565535 3 665535 0 2 7 269 H65535655356553565535 9 5 2 0 4 270 I655356553565535655356553565535 7 4 0 271 272 273 求最短路径..... 274 分别打印矩阵结果: 275 各顶点最短路径: 276 A B C D E F G H I 277 A 0 1 4 7 5 8 10 12 16 278 B 1 0 3 6 4 7 9 11 15 279 C 4 3 0 3 1 4 6 8 12 280 D 7 6 3 0 2 5 3 5 9 281 E 5 4 1 2 0 3 5 7 11 282 F 8 7 4 5 3 0 7 5 9 283 G 10 9 6 3 5 7 0 2 6 284 H 12 11 8 5 7 5 2 0 4 285 I 16 15 12 9 11 9 6 4 0 286 287 各最短路径前驱顶点下标值: 288 A B C D E F G H I 289 A 0 1 1 1 1 1 1 1 1 290 B 0 1 2 2 2 2 2 2 2 291 C 1 1 2 4 4 4 4 4 4 292 D 4 4 4 3 4 4 6 6 6 293 E 2 2 2 3 4 5 3 3 3 294 F 4 4 4 4 4 5 7 7 7 295 G 3 3 3 3 3 7 6 7 7 296 H 6 6 6 6 6 5 6 7 8 297 I 7 7 7 7 7 7 7 7 8 298 299 打印全部最短路径: 300 V0-->V1 weight:1 301 Path:V0-->V1 302 V0-->V2 weight:4 303 Path:V0-->V1-->V2 304 V0-->V3 weight:7 305 Path:V0-->V1-->V2-->V4-->V3 306 V0-->V4 weight:5 307 Path:V0-->V1-->V2-->V4 308 V0-->V5 weight:8 309 Path:V0-->V1-->V2-->V4-->V5 310 V0-->V6 weight:10 311 Path:V0-->V1-->V2-->V4-->V3-->V6 312 V0-->V7 weight:12 313 Path:V0-->V1-->V2-->V4-->V3-->V6-->V7 314 V0-->V8 weight:16 315 Path:V0-->V1-->V2-->V4-->V3-->V6-->V7-->V8 316 V1-->V2 weight:3 317 Path:V1-->V2 318 V1-->V3 weight:6 319 Path:V1-->V2-->V4-->V3 320 V1-->V4 weight:4 321 Path:V1-->V2-->V4 322 V1-->V5 weight:7 323 Path:V1-->V2-->V4-->V5 324 V1-->V6 weight:9 325 Path:V1-->V2-->V4-->V3-->V6 326 V1-->V7 weight:11 327 Path:V1-->V2-->V4-->V3-->V6-->V7 328 V1-->V8 weight:15 329 Path:V1-->V2-->V4-->V3-->V6-->V7-->V8 330 V2-->V3 weight:3 331 Path:V2-->V4-->V3 332 V2-->V4 weight:1 333 Path:V2-->V4 334 V2-->V5 weight:4 335 Path:V2-->V4-->V5 336 V2-->V6 weight:6 337 Path:V2-->V4-->V3-->V6 338 V2-->V7 weight:8 339 Path:V2-->V4-->V3-->V6-->V7 340 V2-->V8 weight:12 341 Path:V2-->V4-->V3-->V6-->V7-->V8 342 V3-->V4 weight:2 343 Path:V3-->V4 344 V3-->V5 weight:5 345 Path:V3-->V4-->V5 346 V3-->V6 weight:3 347 Path:V3-->V6 348 V3-->V7 weight:5 349 Path:V3-->V6-->V7 350 V3-->V8 weight:9 351 Path:V3-->V6-->V7-->V8 352 V4-->V5 weight:3 353 Path:V4-->V5 354 V4-->V6 weight:5 355 Path:V4-->V3-->V6 356 V4-->V7 weight:7 357 Path:V4-->V3-->V6-->V7 358 V4-->V8 weight:11 359 Path:V4-->V3-->V6-->V7-->V8 360 V5-->V6 weight:7 361 Path:V5-->V7-->V6 362 V5-->V7 weight:5 363 Path:V5-->V7 364 V5-->V8 weight:9 365 Path:V5-->V7-->V8 366 V6-->V7 weight:2 367 Path:V6-->V7 368 V6-->V8 weight:6 369 Path:V6-->V7-->V8 370 V7-->V8 weight:4 371 Path:V7-->V8 372 */
关于本代码中的SeqList.h文件,可以从随笔《顺序表》拷贝一份即可。
Good Good Study, Day Day Up.
顺序 选择 循环 总结