连通图和非连通图是“图”的 2 种不同存储形式,其遍历方式完全不一样,这次就来看看图的非连通遍历。
1、连通图和非连通图
连通图:任意的一个顶点到任意的另外一个顶点都有着相应的路径所能够到达。
非连通图:只要找出了有一个顶点不能够到达另外一个顶点。
2、遍历
对于连通图来说,通过DFS或BFS就可以完成遍历;
对于非连通图来说,就得从每个顶点出发进行搜索,每一次的从一个新的顶点出发访问,每个顶点都要开始搜索一遍。
3、非连通图的遍历算法
(1)、不可取的算法:没有必要将非连通图生成森林,在由森林生成我们的遍历树,然后再进行树形结构的访问。
(2)、比较好的算法:直接调动我们之前编写好的DFS()函数;只要没有访问的顶点,我们就由该顶点出发进行深度优先遍历,这样就最终把整个非连通图就遍历完成。
(3)强连通图:针对有向图,有A-->B的边,一定也有B-->A的边。
(4)、遍历算法
1void components(){ //非连通图的遍历
2 int n = Graph::getCurVertex(); 3 bool *visit = new bool[n]; 4 5 for(int i = 0; i 6 visit[i] = false; 7 } 8 for(i = 0; i //对每个顶点都看一下,是否访问过。4 9 if(!visit[i]){10 DFS(getValue(i), visit);11 }12 }1314 delete []visit;15}
4、完整代码、测试代码、测试结果
(1)、完整代码
1#ifndef _GRAPH_H_
2#define _GRAPH_H_
3
4#include
5#include
6using namespace std;
7
8#define VERTEX_DEFAULT_SIZE 20
9
10template<typename Type>
11class Graph{
12public:
13 bool isEmpty()const{
14 return curVertices == 0;
15 }
16 bool isFull()const{
17 if(curVertices >= maxVertices || curEdges >= curVertices*(curVertices-1)/2)
18 return true; //图满有2种情况:(1)、当前顶点数超过了最大顶点数,存放顶点的空间已满
19 return false; //(2)、当前顶点数并没有满,但是当前顶点所能达到的边数已满
20 }
21 int getCurVertex()const{
22 return curVertices;
23 }
24 int getCurEdge()const{
25 return curEdges;
26 }
27public:
28 virtual bool insertVertex(const Type &v) = 0; //插入顶点
29 virtual bool insertEdge(const Type &v1, const Type &v2) = 0; //插入边
30 virtual bool removeVertex(const Type &v) = 0; //删除顶点
31 virtual bool removeEdge(const Type &v1, const Type &v2) = 0; //删除边
32 virtual int getFirstNeighbor(const Type &v) = 0; //得到第一个相邻顶点
33 virtual int getNextNeighbor(const Type &v, const Type &w) = 0; //得到下一个相邻顶点
34public:
35 virtual int getVertexIndex(const Type &v)const = 0; //得到顶点下标
36 virtual void showGraph()const = 0; //显示图
37 virtual Type getValue(int index)const = 0;
38public:
39 virtual void DFS(const Type &v) = 0; //深度优先
40 virtual void BFS(const Type &v) = 0; //广度优先
41protected:
42 int maxVertices; //最大顶点数
43 int curVertices; //当前顶点数
44 int curEdges; //当前边数
45};
46
47template<typename Type>
48class GraphMtx : public Graph{ //邻接矩阵继承父类矩阵 49#define maxVertices Graph::maxVertices //因为是模板,所以用父类的数据或方法都得加上作用域限定符 50#define curVertices Graph::curVertices 51#define curEdges Graph::curEdges 52public: 53 GraphMtx(int vertexSize = VERTEX_DEFAULT_SIZE){ //初始化邻接矩阵 54 maxVertices = vertexSize > VERTEX_DEFAULT_SIZE ? vertexSize : VERTEX_DEFAULT_SIZE; 55 vertexList = new Type[maxVertices]; //申请顶点空间 56 for(int i = 0; i //都初始化为0 57 vertexList[i] = 0; 58 } 59 edge = new int*[maxVertices]; //申请边的行 60 for(i = 0; i //申请列空间 61 edge[i] = new int[maxVertices]; 62 } 63 for(i = 0; i //赋初值为0 64 for(int j = 0; j 65 edge[i][j] = 0; 66 } 67 } 68 curVertices = curEdges = 0; //当前顶点和当前边数 69 } 70 GraphMtx(Type (*mt)[4], int sz){ //通过已有矩阵的初始化 71 int e = 0; //统计边数 72 maxVertices = sz > VERTEX_DEFAULT_SIZE ? sz : VERTEX_DEFAULT_SIZE; 73 vertexList = new Type[maxVertices]; //申请顶点空间 74 for(int i = 0; i //都初始化为0 75 vertexList[i] = 0; 76 } 77 edge = new int*[maxVertices]; //申请边的行 78 for(i = 0; i //申请列空间 79 edge[i] = new Type[maxVertices]; 80 } 81 for(i = 0; i //赋初值为矩阵当中的值 82 for(int j = 0; j 83 edge[i][j] = mt[i][j]; 84 if(edge[i][j] != 0){ 85 e++; //统计列的边数 86 } 87 } 88 } 89 curVertices = sz; 90 curEdges = e/2; 91 } 92 ~GraphMtx(){} 93public: 94 bool insertVertex(const Type &v){ 95 if(curVertices >= maxVertices){ 96 return false; 97 } 98 vertexList[curVertices++] = v; 99 return true;100 }101 bool insertEdge(const Type &v1, const Type &v2){102 int maxEdges = curVertices*(curVertices-1)/2;103 if(curEdges >= maxEdges){104 return false;105 }106107 int v = getVertexIndex(v1);108 int w = getVertexIndex(v2);109110 if(v==-1 || w==-1){111 cout<<"edge no exit"<<endl; //要插入的顶点不存在,无法插入112 return false;113 }114 if(edge[v][w] != 0){ //当前边已经存在,不能进行插入115 return false;116 }117118 edge[v][w] = edge[w][v] = 1; //因为是无向图,对称的,存在边赋为1;119 return true; 120 } //删除顶点的高效方法121 bool removeVertex(const Type &v){122 int i = getVertexIndex(v);123 if(i == -1){124 return false;125 }126 vertexList[i] = vertexList[curVertices-1];127 int edgeCount = 0;128 for(int k = 0; k 129 if(edge[i][k] != 0){ //统计删除那行的边数130 edgeCount++;131 }132 }133 //删除行134 for(int j = 0; j 135 edge[i][j] = edge[curVertices-1][j];136 }137 //删除列138 for(j = 0; j 139 edge[j][i] = edge[j][curVertices-1];140 }141 curVertices--;142 curEdges -= edgeCount;143 return true;144 }145/* //删除顶点用的是数组一个一个移动的方法,效率太低。146 bool removeVertex(const Type &v){147 int i = getVertexIndex(v);148 if(i == -1){149 return false;150 }151 for(int k = i; k 152 vertexList[k] = vertexList[k+1];153 }154155 int edgeCount = 0;156 for(int j = 0; j 157 if(edge[i][j] != 0)158 edgeCount++;159 }160161 for(int k = i; k 162 {163 for(int j = 0; j 164 {165 edge[k][j] = edge[k+1][j];166 }167 }168169 for(int k = i; k 170 {171 for(int j = 0; j 172 {173 edge[j][k] = edge[j][k+1];174 }175 }176177 curVertices--;178 curEdges -= edgeCount;179180 return true;181 } 182*/183 bool removeEdge(const Type &v1, const Type &v2){184 int v = getVertexIndex(v1);185 int w = getVertexIndex(v2);186187 if(v==-1 || w==-1){ //判断要删除的边是否在当前顶点内188 return false; //顶点不存在189 }190 if(edge[v][w] == 0){ //这个边根本不存在,没有必要删191 return false;192 }193 edge[v][w] = edge[w][v] = 0; //删除这个边赋值为0,代表不存在;194 curEdges--;195196 return true;197 }198 int getFirstNeighbor(const Type &v){199 int i = getVertexIndex(v);200 if(i == -1){201 return -1;202 }203 for(int col = 0; col 204 if(edge[i][col] != 0){205 return col;206 }207 }208 return -1;209 }210 int getNextNeighbor(const Type &v, const Type &w){211 int i = getVertexIndex(v);212 int j = getVertexIndex(w);213214 if(i==-1 || j==-1){215 return -1;216 }217 for(int col = j+1; col 218 if(edge[i][col] != 0){219 return col;220 }221 }222223 return -1;224 }225public:226 void showGraph()const{227 if(curVertices == 0){228 cout<<"Nul Graph"<<endl;229 return;230 }231232 for(int i = 0; i 233 cout<" "; 234 }235 cout<<endl;236 for(i = 0; i 237 for(int j = 0; j 238 cout<" ";239 }240 cout<endl;241 }242 }243 int getVertexIndex(const Type &v)const{244 for(int i = 0; i 245 if(vertexList[i] == v){246 return i;247 }248 }249250 return -1;251 }252public:253 Type getValue(int index)const{254 return vertexList[index];255 }256 void DFS(const Type &v){257 int n = Graph::getCurVertex();258 bool *visit = new bool[n];259260 for(int i = 0; i 261 visit[i] = false;262 }263 DFS(v, visit);264 delete []visit;265 }266 void BFS(const Type &v){267 int n = Graph::getCurVertex();268 bool *visit = new bool[n];269 for(int i = 0; i 270 visit[i] = false;271 }272 cout<"-->";273 int index = getVertexIndex(v);274 visit[index] = true;275276 queue<int> q; //队列中存放的是顶点下标;277 q.push(index);278 int w;279 while(!q.empty()){280 index = q.front();281 q.pop();282 w = getFirstNeighbor(getValue(index));283 while(w != -1){284 if(!visit[w]){285 cout<"-->";286 visit[w] = true; 287 q.push(w);288 }289290 w = getNextNeighbor(getValue(index), getValue(w));291292 }293 }294295 delete []visit;296 }297 void components(){ //非连通图的遍历298 int n = Graph::getCurVertex();299 bool *visit = new bool[n];300301 for(int i = 0; i 302 visit[i] = false;303 }304 for(i = 0; i 305 if(!visit[i]){306 DFS(getValue(i), visit);307 }308 }309310 delete []visit;311312 }313protected:314 void DFS(const Type &v, bool *visit){315 cout<"-->";316 int index = getVertexIndex(v);317 visit[index] = true;318 int w = getFirstNeighbor(v);319 while(w != -1){320 if(!visit[w]){321 DFS(getValue(w), visit);322 }323 w = getNextNeighbor(v, getValue(w)); 324 }325 }326private:327 Type *vertexList; //存放顶点的数组328 int **edge; //存放边关系的矩阵329};330331#endif
(2)、测试代码
1#include"Graph2.h"
2
3int main(void){
4 GraphMtx<char> gm;
5 gm.insertVertex('A');
6 gm.insertVertex('B');
7 gm.insertVertex('C'); //B的第一个邻接顶点是C,
8 gm.insertVertex('D');
9 gm.insertVertex('E');
10 gm.insertVertex('F');
11 gm.insertVertex('G');
12 gm.insertVertex('H');
13 gm.insertVertex('I');
14 gm.insertVertex('J');
15 gm.insertVertex('K');
16 gm.insertVertex('L');
17 gm.insertVertex('M');
18
19 gm.insertEdge('A','B');
20 gm.insertEdge('A','C');
21 gm.insertEdge('A','F');
22 gm.insertEdge('A','L');
23 gm.insertEdge('B','M');
24 gm.insertEdge('L','J');
25 gm.insertEdge('L','M');
26 gm.insertEdge('J','M');
27 gm.insertEdge('D','E');
28 gm.insertEdge('G','H');
29 gm.insertEdge('G','I');
30 gm.insertEdge('G','K');
31 gm.insertEdge('H','K');
32
33 gm.showGraph();
34
35 cout<<"------------------------------------------------"<<endl;
36 gm.DFS('A');
37 cout<<"Nul."<<endl;
38 gm.BFS('A');
39 cout<<"Nul."<<endl;
40 gm.components();
41 cout<<"Nul."<<endl;
42 return 0;
43
44}
(3)、测试结果
测试图的模型:
推荐阅读:
从零开始学习数据结构-->入门篇
从零开始学习数据结构-->链表
从零开始学习数据结构-->线性表
从零开始学习数据结构-->栈
从零开始学习数据结构-->队列
从零开始学习数据结构-->矩阵+串
从零开始学习数据结构-->哈希表
从零开始学习数据结构-->散列桶
从零开始学习数据结构-->二叉树
从零开始学习数据结构-->二叉树方法实现
从零开始学习数据结构-->线索二叉树从零开始学习数据结构-->树、森林与二叉树的转换
从零开始学习数据结构-->大堆+小堆
从零开始学习数据结构-->AVL树之旋转算法从零开始学习数据结构-->AVL树之插入算法
从零开始学习数据结构-->AVL树之删除算法 从零开始学习数据结构-->红黑树 从零开始学习数据结构-->图之邻接矩阵从零开始学习数据结构-->图之邻接表
从零开始学习数据结构-->图的遍历 认真的人 自带光芒