图的存储结构:邻接矩阵、邻接表,那么对于不同的存储结构必然存在着不同的访问方式,拿到具体数据的过程就是图的遍历。
1、遍历
图的遍历与树的很相似,遍历满足:
(1)、对每一个顶点都得进行一次访问;
(2)、对其不能进行重复的访问,只能是一次;
对上次的一个补充: 当父类是模板类时,子类继承后,要是想调用父类的方法/数据,必须加上模板的作用域限定符,例 : Grapth::maxVertices;方可在子类中使用父类的数据或方法。
2、深度优先(DFS)
DFS(depth first search):一个不断探查和回溯的过程,一个往死里整的过程;一条路必须走到死方可结束;
模型分析:
3、广度优先(BFS)
BFS(breadth first search):一个逐层遍历的过程,借助队列来实现 !
模型分析:
4、代码实现
(1)、对无向图的遍历,用邻接矩阵实现DFS;
借助了一个visit数组,看当前顶点是否被访问过,visit数组充当标志!
1public:
2 void DFS(const Type &v){
3 int n = Graph::getCurVertex(); 4 bool *visit = new bool[n]; 5 6 for(int i = 0; i 7 visit[i] = false; 8 } 9 DFS(v, visit);10 delete []visit;11 }12protected:13 void DFS(const Type &v, bool *visit){14 cout<"-->";15 int index = getVertexIndex(v);16 visit[index] = true;17 int w = getFirstNeighbor(v);18 while(w != -1){19 if(!visit[w]){20 DFS(getValue(w), visit);21 }22 w = getNextNeighbor(v, getValue(w)); 23 }24 }
(2)、对无向图的遍历,用邻接矩阵实现BFS;
借助visit数组和队列来实现;
1void BFS(const Type &v){
2 int n = Graph::getCurVertex(); 3 bool *visit = new bool[n]; 4 for(int i = 0; i 5 visit[i] = false; 6 } 7 cout<"-->"; 8 int index = getVertexIndex(v); 9 visit[index] = true;1011 queue<int> q; //队列中存放的是顶点下标;12 q.push(index);13 int w;14 while(!q.empty()){15 index = q.front();16 q.pop();17 w = getFirstNeighbor(getValue(index));18 while(w != -1){19 if(!visit[w]){20 cout<"-->";21 visit[w] = true; 22 q.push(w);23 }2425 w = getNextNeighbor(getValue(index), getValue(w));2627 }28 }2930 delete []visit;31}
5、完整代码、测试代码、测试结果
(1)、完整代码 (无向图)
1#ifndef _GRAPH_H_
2#define _GRAPH_H_
3
4#include
5#include
6using namespace std;
7
8#define VERTEX_DEFAULT_SIZE 10
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 }297protected:298 void DFS(const Type &v, bool *visit){299 cout<"-->";300 int index = getVertexIndex(v);301 visit[index] = true;302 int w = getFirstNeighbor(v);303 while(w != -1){304 if(!visit[w]){305 DFS(getValue(w), visit);306 }307 w = getNextNeighbor(v, getValue(w)); 308 }309 }310private:311 Type *vertexList; //存放顶点的数组312 int **edge; //存放边关系的矩阵313};314315#endif
(2)、测试代码
1#include"Graph1.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
15 gm.insertEdge('A','B');
16 gm.insertEdge('A','C');
17 gm.insertEdge('A','D');
18 gm.insertEdge('B','C');
19 gm.insertEdge('B','E');
20 gm.insertEdge('C','F');
21 gm.insertEdge('D','F');
22 gm.insertEdge('E','G');
23 gm.insertEdge('F','H');
24 gm.insertEdge('H','I');
25
26 gm.showGraph();
27
28 cout<<"------------------------------------------------"<<endl;
29 gm.DFS('A');
30 cout<<"Nul."<<endl;
31 gm.BFS('A');
32 cout<<"Nul."<<endl;
33 return 0;
34
35}
(3)、测试结果
无向图的模型:
推荐阅读:
从零开始学习数据结构-->入门篇 从零开始学习数据结构-->链表 从零开始学习数据结构-->线性表 从零开始学习数据结构-->栈 从零开始学习数据结构-->队列 从零开始学习数据结构-->矩阵+串 从零开始学习数据结构-->哈希表 从零开始学习数据结构-->散列桶 从零开始学习数据结构-->二叉树从零开始学习数据结构-->二叉树方法实现
从零开始学习数据结构-->线索二叉树从零开始学习数据结构-->树、森林与二叉树的转换
从零开始学习数据结构-->大堆+小堆
从零开始学习数据结构-->AVL树之旋转算法从零开始学习数据结构-->AVL树之插入算法
从零开始学习数据结构-->AVL树之删除算法 从零开始学习数据结构-->红黑树 从零开始学习数据结构-->图之邻接矩阵从零开始学习数据结构-->图之邻接表
认真的人 自带光芒