图相关算法(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. 这三个算法都相当重要,要熟练掌握。

posted @ 2012-07-08 16:36  kasuosuo  阅读(645)  评论(0编辑  收藏  举报