图相关算法(BFS,DFS等)
1. 首先代码如下:
View Code
1 #ifndef __GRAPH_H__ 2 #define __GRAPH_H__ 3 4 #include <vector> 5 #include <queue> 6 #include <stack> 7 #define IN 8 #define OUT 9 #define INOUT 10 using namespace std; 11 12 namespace graphspace 13 { 14 template <typename weight> 15 struct Edge 16 { 17 int nDestVertex; //边的另一个顶点位置 18 weight edgeWeight; //边的权重 19 Edge<weight> *pNextEdge; //下一条边链指针 20 21 Edge(int d, weight c, Edge<weight> *p = NULL) 22 :nDestVertex(d), edgeWeight(c), pNextEdge(p) 23 {} 24 }; 25 26 template <typename vertexNametype, typename weight> 27 struct Vertex 28 { 29 vertexNametype vertexName; //顶点名字 30 Edge<weight> *pAdjEdges; //顶点所拥有的边 31 32 Vertex(vertexNametype x, Edge<weight> *p = NULL) 33 :vertexName(x), pAdjEdges(p) 34 {} 35 }; 36 37 //adjacency list based graph 38 template <typename vertexNametype, typename weight> 39 class ALGraph 40 { 41 public: 42 explicit ALGraph(); //explicit修饰的构造函数不能担任转换函数 43 ~ALGraph(); 44 public: 45 46 47 bool insertAVertex(IN const vertexNametype vertexName); 48 49 bool insertAEdge(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2, IN const weight edgeWeight); 50 51 bool removeAEdge(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2, IN const weight edgeWeight); 52 53 weight getMinWeight(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2); 54 55 int getVertexIndex(IN const vertexNametype vertexName); 56 57 int getVertexNumber(); 58 59 vertexNametype getData(IN int index); 60 61 int Dijkstra(IN const vertexNametype vertexName1); 62 63 void DijkstraPrint(IN int index, IN int sourceIndex, IN vector<int> vecPreVertex); 64 void DFS(); //递归深度优先搜索 65 void NRDFS(); //非递归深度优先搜索 66 void NRBFS(); //非递归广度优先搜索 67 friend ostream& operator<<(OUT ostream &out, IN const ALGraph<vertexNametype,weight> &graphInstance); 68 69 public: 70 71 weight getEdgeWeight(IN const Edge<weight> *pEdge); 72 73 void getVertexEdgeWeight(IN const int v1, OUT vector<weight> &DistanceArray); 74 //存储顶点的vector 75 vector< Vertex<vertexNametype, weight> > m_vertexArray; 76 private: 77 void DFS(int vertexNumber,bool visited[]); 78 void NRDFS(int vertexNumber,bool visited[]); 79 void NRBFS(int VertexNumber,bool visited[]); 80 }; 81 82 #include "graph_realize.h" 83 84 } 85 86 #endif
View Code
1 #ifndef __GRAPH_REALIZE__H_ 2 #define __GRAPH_REALIZE__H_ 3 4 /*#define VERTEXARRAYITE (vector< Vertex<vertexNametype, weight> >::iterator) */ 5 6 template<typename vertexNametype, typename weight> 7 ALGraph<vertexNametype, weight>::ALGraph() 8 { 9 if (!m_vertexArray.empty()) 10 { 11 m_vertexArray.clear(); 12 } 13 14 } 15 16 template<typename vertexNametype, typename weight> 17 ALGraph<vertexNametype, weight>::~ALGraph() 18 { 19 vector< Vertex<vertexNametype, weight> >::iterator iter; 20 //遍历图中所有的顶点 21 for(iter = m_vertexArray.begin(); iter != m_vertexArray.end(); iter++) 22 { 23 Edge<weight> *p = iter->pAdjEdges; 24 //删除顶点的所有邻接边 25 while(NULL != p) 26 { 27 iter->pAdjEdges = p->pNextEdge; 28 delete p; 29 p = iter->pAdjEdges; 30 } 31 } 32 //清空存储顶点的vector 33 if (!m_vertexArray.empty()) 34 { 35 m_vertexArray.clear(); 36 } 37 } 38 39 //插入顶点 40 template<typename vertexNametype, typename weight> 41 bool ALGraph<vertexNametype, weight>::insertAVertex(IN const vertexNametype vertexName) 42 { 43 Vertex<vertexNametype, weight> VertexInstance(vertexName, NULL); 44 m_vertexArray.push_back(VertexInstance); 45 46 return true; 47 } 48 49 template<typename vertexNametype, typename weight> 50 bool ALGraph<vertexNametype, weight>::insertAEdge(IN const vertexNametype vertexName1, 51 IN const vertexNametype vertexName2, IN const weight edgeWeight) 52 { 53 int v1 = getVertexIndex(vertexName1); 54 if (-1 == v1) 55 { 56 cerr << "There is no vertex 1" << endl; 57 return false; 58 } 59 60 int v2 = getVertexIndex(vertexName2); 61 if (-1 == v2) 62 { 63 cerr << "There is no vertex 2" << endl; 64 return false; 65 } 66 67 Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges; 68 while(p != NULL && p->nDestVertex != v2) 69 { 70 p = p->pNextEdge; 71 } 72 73 if (NULL == p) 74 { 75 //v2是边的另一个顶点,edgeWeight是边v1v2的权重,m_vertexArray.at(v1).pAdjEdges 76 //是顶点v1的邻接边指针,此时边p的指向的下一个节点既是m_vertexArray.at(v1).pAdjEdges 77 p = new Edge<weight>(v2, edgeWeight, m_vertexArray.at(v1).pAdjEdges); //总是加入到链表头 78 m_vertexArray.at(v1).pAdjEdges = p; 79 return true; 80 } 81 if (v2 == p->nDestVertex) 82 { 83 Edge<weight> *q = p; 84 p = new Edge<weight>( v2, edgeWeight, q->pNextEdge ); //允许两个节点之间有多条边,加入到同名节点边之后 85 q->pNextEdge = p; 86 return true; 87 } 88 89 return false; 90 } 91 92 template<typename vertexNametype, typename weight> 93 bool ALGraph<vertexNametype, weight>::removeAEdge(IN const vertexNametype vertexName1, 94 IN const vertexNametype vertexName2, IN const weight edgeWeight) 95 { 96 int v1 = getVertexIndex(vertexName1); 97 if (-1 == v1) 98 { 99 cerr << "There is no vertex 1" << endl; 100 return false; 101 } 102 103 int v2 = getVertexIndex(vertexName2); 104 if (-1 == v2) 105 { 106 cerr << "There is no vertex 2" << endl; 107 return false; 108 } 109 110 Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges; 111 Edge<weight> *q = NULL; 112 while(p != NULL && p->nDestVertex != v2 ) 113 { 114 q = p; 115 p = p->pNextEdge; 116 } 117 if (NULL == p) 118 { 119 cerr << "Edge is not found" << endl; 120 return false; 121 } 122 while( edgeWeight != p->edgeWeight && p->nDestVertex == v2) 123 { 124 q = p; 125 p = p->pNextEdge; 126 } 127 if (v2 != p->nDestVertex) 128 { 129 cerr << "Edge is not found" << endl; 130 return false; 131 } 132 q->pNextEdge = p->pNextEdge; 133 delete p; 134 135 return true; 136 } 137 138 //返回一条边的权重 139 template<typename vertexNametype, typename weight> 140 weight ALGraph<vertexNametype, weight>::getEdgeWeight(IN const Edge<weight> *pEdge) 141 { 142 return pEdge->edgeWeight; 143 } 144 145 146 //返回一个顶点所有边的权重,使用vector存储,vector的下标为边中 147 //目标顶点的索引 148 template<typename vertexNametype, typename weight> 149 void ALGraph<vertexNametype, weight>::getVertexEdgeWeight(IN const int v1, OUT vector<weight> &DistanceArray) 150 { 151 Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges; 152 int prevIndex = -1; 153 weight tmp; 154 155 while(NULL != p) 156 { 157 //考虑两个顶点之间有相同的边只是权重不同 158 //选择权重中最小的 159 if (prevIndex == p->nDestVertex) 160 { 161 if (tmp > p->edgeWeight) 162 { 163 DistanceArray[prevIndex] = p->edgeWeight; 164 } 165 } 166 else 167 { 168 DistanceArray[p->nDestVertex] = p->edgeWeight; 169 prevIndex = p->nDestVertex; 170 tmp = p->edgeWeight; 171 } 172 173 p = p->pNextEdge; 174 } 175 } 176 177 178 //返回两点之间边的最小权值 179 template<typename vertexNametype, typename weight> 180 weight ALGraph<vertexNametype, weight>::getMinWeight(IN const vertexNametype vertexName1, 181 IN const vertexNametype vertexName2) 182 { 183 Edge<weight> *pEdge = NULL; 184 int v1 = getVertexIndex(vertexName1); 185 if (-1 == v1) 186 { 187 cerr << "There is no vertex 1" << endl; 188 return false; 189 } 190 191 int v2 = getVertexIndex(vertexName2); 192 if (-1 == v2) 193 { 194 cerr << "There is no vertex 2" << endl; 195 return false; 196 } 197 198 Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges; 199 while (p != NULL && p->nDestVertex != v2) 200 { 201 p = p->pNextEdge; 202 } 203 if (NULL == p) 204 { 205 pEdge = NULL; 206 return weight(0); 207 } 208 weight tmp = getEdgeWeight(p); 209 pEdge = p; 210 while (NULL != p && v2 == p->nDestVertex) 211 { 212 if (tmp > getEdgeWeight(p)) 213 { 214 tmp = getEdgeWeight(p); 215 pEdge = p; 216 } 217 p = p->pNextEdge; 218 } 219 return tmp; 220 } 221 222 //返回顶点在vector中的下标 223 template<typename vertexNametype, typename weight> 224 int ALGraph<vertexNametype, weight>::getVertexIndex(IN const vertexNametype vertexName) 225 { 226 for (int i = 0; i < m_vertexArray.size(); i++) 227 { 228 if (vertexName == getData(i)) 229 { 230 return i; 231 } 232 } 233 return -1; 234 } 235 236 //返回顶点个数 237 template<typename vertexNametype, typename weight> 238 int ALGraph<vertexNametype, weight>::getVertexNumber() 239 { 240 return m_vertexArray.size(); 241 } 242 243 //返回vector中第i个顶点的名称 244 template<typename vertexNametype, typename weight> 245 vertexNametype ALGraph<vertexNametype, weight>::getData(IN int index) 246 { 247 return m_vertexArray.at(index).vertexName; 248 } 249 250 //单源最短路径算法 251 template<typename vertexNametype, typename weight> 252 int ALGraph<vertexNametype, weight>::Dijkstra(IN const vertexNametype vertexName1) 253 { 254 int sourceIndex = getVertexIndex(vertexName1); 255 if (-1 == sourceIndex) 256 { 257 cerr << "There is no vertex " << endl; 258 return false; 259 } 260 int nVertexNo = getVertexNumber(); 261 262 //the array to record the points have been included, if included the value is true 263 //else is false 264 //节点是否访问初始化 265 vector<bool> vecIncludeArray; 266 vecIncludeArray.assign(nVertexNo, false); 267 vecIncludeArray[sourceIndex] = true; 268 269 //the array to record the distance from vertex1 270 //节点距离初始化 271 vector<weight> vecDistanceArray; 272 vecDistanceArray.assign(nVertexNo, weight(INT_MAX)); 273 vecDistanceArray[sourceIndex] = weight(0); 274 275 //prev array to record the previous vertex 276 //记录到达本节点的上一个节点,记录信息,用来输出最短路径 277 vector<int> vecPrevVertex; 278 vecPrevVertex.assign(nVertexNo, sourceIndex); 279 280 getVertexEdgeWeight(sourceIndex, vecDistanceArray); 281 282 int vFrom, vTo; 283 284 while(1) 285 { 286 weight minWeight = weight(INT_MAX); 287 vFrom = sourceIndex; 288 vTo = -1; 289 //找到没有访问过的且权值最小的边,vFrom记录 290 //这条边的目标点。 291 for (int i = 0; i < nVertexNo; i++) 292 { 293 if (!vecIncludeArray[i] && minWeight > vecDistanceArray[i]) 294 { 295 minWeight = vecDistanceArray[i]; 296 vFrom = i; 297 } 298 } 299 //如果最小的边权值是INT_MAX,说明再也没有可达的边,跳出循环 300 if (weight(INT_MAX) == minWeight) 301 { 302 break; 303 } 304 //将最小的边的目标顶点加入到vecIncludeArray, 305 //具体操作为将vecIncludeArray[vFrom] 置为true 306 vecIncludeArray[vFrom] = true; 307 308 Edge<weight> *p = m_vertexArray[vFrom].pAdjEdges; 309 while (NULL != p) 310 { 311 weight wFT = p->edgeWeight; 312 vTo = p->nDestVertex; 313 if (!vecIncludeArray[vTo] && vecDistanceArray[vTo] > wFT + vecDistanceArray[vFrom]) 314 { 315 vecDistanceArray[vTo] = wFT + vecDistanceArray[vFrom]; 316 vecPrevVertex[vTo] = vFrom; 317 } 318 p = p->pNextEdge; 319 } 320 } 321 322 //print the shortest route of all vertexes 323 for (int i = 0; i < nVertexNo; i++) 324 { 325 if (weight(INT_MAX) != vecDistanceArray[i]) 326 { 327 cout << getData(sourceIndex) << "->" << getData(i) << ": "; 328 DijkstraPrint(i, sourceIndex, vecPrevVertex); 329 cout << " " << vecDistanceArray[i]; 330 cout << endl; 331 } 332 } 333 return 0; 334 } 335 336 template<typename vertexNametype, typename weight> 337 void ALGraph<vertexNametype, weight>::DijkstraPrint(IN int index, IN int sourceIndex, IN vector<int> vecPreVertex) 338 { 339 if (sourceIndex != index) 340 { 341 DijkstraPrint(vecPreVertex[index], sourceIndex, vecPreVertex); 342 } 343 cout << getData(index) << " "; 344 } 345 346 //非递归深度优先搜索 347 template<typename vertexNametype, typename weight> 348 void ALGraph<vertexNametype, weight>::NRDFS() 349 { 350 int n=getVertexNumber(); 351 bool *visited=new bool[n]; 352 for (int i=0;i<n;i++) 353 { 354 visited[i]=false; 355 } 356 for (int i=0;i<n;i++) 357 { 358 if (!visited[i]) 359 { 360 NRDFS(i,visited); 361 cout<<endl; 362 } 363 } 364 delete[] visited; 365 } 366 367 //非递归深度优先搜索 368 template<typename vertexNametype, typename weight> 369 void ALGraph<vertexNametype, weight>::NRDFS(int vertexNumber,bool visited[]) 370 { 371 stack<int> st; 372 vector<int> vec; 373 visited[vertexNumber]=true; 374 st.push(vertexNumber); 375 while(!st.empty()) 376 { 377 int tmpVertexNumber=st.top(); 378 st.pop(); 379 vec.push_back(tmpVertexNumber); 380 cout<<getData(tmpVertexNumber)<<" "; 381 Edge<weight> *pE=m_vertexArray.at(tmpVertexNumber).pAdjEdges; 382 int flag=0; 383 while(pE) 384 { 385 int tmpDesVertex=pE->nDestVertex; 386 if (!visited[tmpDesVertex]) 387 { 388 visited[tmpDesVertex]=true; 389 st.push(tmpDesVertex); 390 } 391 pE=pE->pNextEdge; 392 } 393 } 394 } 395 396 //递归深度优先搜索 397 template<typename vertexNametype, typename weight> 398 void ALGraph<vertexNametype, weight>::DFS() 399 { 400 int n=getVertexNumber(); 401 bool *visited=new bool[n]; 402 for (int i=0;i<n;i++) 403 { 404 visited[i]=false; 405 } 406 for (int i=0;i<n;i++) 407 { 408 if (!visited[i]) 409 { 410 DFS(i,visited); 411 cout<<endl; 412 } 413 } 414 delete[] visited; 415 } 416 417 418 template<typename vertexNametype, typename weight> 419 void ALGraph<vertexNametype, weight>::DFS(int vertexNumber,bool visited[]) 420 { 421 cout<<getData(vertexNumber)<<" "; 422 visited[vertexNumber]=true; 423 Edge<weight> *p=m_vertexArray.at(vertexNumber).pAdjEdges; 424 while(p!=NULL) 425 { 426 if (!visited[p->nDestVertex]) 427 { 428 DFS(p->nDestVertex,visited); 429 } 430 p=p->pNextEdge; 431 } 432 } 433 434 //非递归广度优先搜索 435 template<typename vertexNametype, typename weight> 436 void ALGraph<vertexNametype, weight>::NRBFS() 437 { 438 int n=getVertexNumber(); 439 bool *visited=new bool[n]; 440 for (int i=0;i<n;i++) 441 { 442 visited[i]=false; 443 } 444 for (int i=0;i<n;i++) 445 { 446 if (!visited[i]) 447 { 448 NRBFS(i,visited); 449 cout<<endl; 450 } 451 } 452 delete[] visited; 453 } 454 455 //非递归广度优先搜索实现 456 template<typename vertexNametype, typename weight> 457 void ALGraph<vertexNametype, weight>::NRBFS(int VertexNumber,bool visited[]) 458 { 459 int n=getVertexNumber(); 460 cout<<getData(VertexNumber)<<" "; 461 visited[VertexNumber]=true; 462 queue<int> q; 463 q.push(VertexNumber); 464 while(!q.empty()) 465 { 466 VertexNumber=q.front(); 467 q.pop(); 468 Edge<weight> *p=m_vertexArray.at(VertexNumber).pAdjEdges; 469 while(p!=NULL) 470 { 471 if (!visited[p->nDestVertex]) 472 { 473 cout<<getData(p->nDestVertex)<<" "; 474 visited[p->nDestVertex]=true; 475 q.push(p->nDestVertex); 476 } 477 p=p->pNextEdge; 478 } 479 } 480 } 481 482 template<typename vertexNametype, typename weight> 483 ostream& operator<<(OUT ostream &out, IN ALGraph<vertexNametype,weight> &graphInstance) 484 { 485 int vertexNo = graphInstance.getVertexNumber(); 486 out << "This graph has " << vertexNo << "vertexes" << endl; 487 488 for(int i = 0; i < vertexNo; i++) 489 { 490 vertexNametype x1 = graphInstance.getData(i); 491 out << x1 << ": "; 492 493 Edge<weight> *p = graphInstance.m_vertexArray.at(i).pAdjEdges; 494 while (NULL != p) 495 { 496 out << "(" << x1 << "," << graphInstance.getData(p->nDestVertex) << "," << p->edgeWeight << ") "; 497 p = p->pNextEdge; 498 } 499 out << endl; 500 } 501 return out; 502 } 503 504 505 506 507 #endif
View Code
1 #include <iostream> 2 #include "graph.h" 3 #include <fstream> 4 #include <string> 5 using namespace std; 6 using namespace graphspace; 7 8 void main() 9 { 10 ALGraph<char, int> g; 11 char vertex; 12 ifstream infile; 13 infile.open("components.txt"); 14 //先读节点 15 while (infile>>vertex && vertex!='q') 16 { 17 g.insertAVertex(vertex); 18 } 19 char source,dest; 20 int weight; 21 //接着读边 22 while(infile>>source>>dest>>weight) 23 { 24 g.insertAEdge(source,dest,weight); 25 } 26 27 cout << g << endl << endl; 28 g.Dijkstra('A'); 29 cout<<"深度优先搜索:"<<endl; 30 g.DFS(); 31 cout<<"广度优先搜索:"<<endl; 32 g.NRBFS(); 33 34 cout<<"非递归深度优先搜索:"<<endl; 35 g.NRDFS(); 36 return; 37 }
测试文件:components.txt
View Code
1 A B C D E F G H I J K L M N O q 2 A B 1 3 A C 5 4 A D 4 5 A E 3 6 B F 2 7 E F 1 8 E G 2 9 F G 7 10 H I 5 11 H J 8 12 I J 3 13 K L 1 14 K M 3 15 K N 5 16 L O 2 17 M O 4 18 B A 1 19 C A 5 20 D A 4 21 E A 3 22 F B 2 23 F E 1 24 G E 2 25 G F 7 26 I H 5 27 J H 8 28 J I 3 29 L K 1 30 M K 3 31 N K 5 32 O L 2 33 O M 4
运行结果:
2. 在上述代码中主要有图的BFS广度优先搜索,DFS深度优先搜索,单源最短路径(Dijkstra)算法。
3. DFS运行速度一般比BFS运行速度快一点,DFS比较适合使用递归方式书写,BFS适合使用队列进行书写。
4. 上述代码中也给出了DFS的非递归实现,非递归实现主要使用栈模拟递归程序,记录一些信息。
5. 代码中考虑到图的联通性问题,两个点之间存在多条路径问题。
6. 单源最短路径算法只能用于边权值非负的情况。
7. 注意Dijkstra是使用的用来输出最短路劲信息的方法,使用一个vecPrevVertex记录信息,使用递归方法打印最短路径。
8. Dijkstra算法流程如下:转载http://blog.csdn.net/v_JULY_v/article/details/6096981。算法是BFS的一个应用,在BFS的过程中记录及更新节点信息。
9. 这三个算法都相当重要,要熟练掌握。