按照图的存储结构来遍历图中的每一个顶点,有这样两种方法,深度优先DFS和广度优先BFS。
注:这些代码都没有运行过,所以可能存在问题,但思路是对的。
1、深度优先遍历
图的深度优先遍历就像一颗树的前序遍历,从图中的某个顶点V出发,访问该顶点,然后从V的未被访问的邻接点出发深度优先遍历图,直至图中所有和V有路经相通的顶点都被访问。
邻接矩阵结构的深度优先遍历:
typedef char VertexType; typedef int EdgeType; const int MAXVEX = 100; const int MAXEDGE = 1000; struct MGraph { VertexType vexs[MAXVEX]; EdgeType arc[MAXVEX][MAXVEX]; int numVertexes; int numEdges; }; bool visited[MAXVEX]; void DFS(MGraph &G, int i, vector<VertexType> &res) { visited[i] = true; res.push_back(G.vexs[i]); for (int j = 0; j < G.numVertexes; ++j) { if (!visited[j] && G.arc[i][j] != 0) DFS(G, j, res); } } void DFStraverse(MGraph &G, vector<VertexType> &res) { for (int i = 0; i < G.numVertexes; ++i) visited[i] = false; for (int i = 0; i < G.numVertexes; ++i) { if (!(visited[i])) DFS(G, i, res); } }
邻接表的深度优先遍历:
//************邻接表的深度优先遍历 typedef char VertexType; typedef int EdgeType; const int MAXVEX = 100; const int MAXEDGE = 1000; struct EdgeNode { int adjvex; EdgeType weight; EdgeNode *next; }; struct VertexNode { VertexType data; EdgeNode *firstedge; }; struct GraphAdjList { VertexNode adjList[MAXVEX]; int numVertexes; int numEdges; }; bool visited[MAXVEX]; void DFS(GraphAdjList *G, int i, vector<VertexType> &res) { visited[i] = true; EdgeNode *p = G->adjList[i].firstedge; res.push_back(G->adjList[i].data); while (p) { if (!visited[p->adjvex]) DFS(G, p->adjvex, res); p = p->next; } } void DFStraverse(GraphAdjList *G, vector<VertexType> &res) { for (int i = 0; i < G->numVertexes; ++i) visited[i] = false; for (int i = 0; i < G->numVertexes; ++i) { if (!visited[i]) DFS(G, i, res); } }
对于两个不同存储结构的深度优先遍历算法,对于n个顶点e条边的图来说,邻接矩阵二维数组要查找每个顶点的邻接点需要访问矩阵中的所有元素,所以需要o(n2)。邻接表存储结构中,找邻接点的时间取决于顶点和变的数量,所以是o(n+e)。 显然,对于稀疏矩阵,邻接表结构算法在时间效率上大大提高。
2、广度优先遍历BFS:类似于数的按层遍历,借助于队列数据结构 ,可以简单实现。
邻接矩阵的广度优先遍历:
typedef char VertexType; typedef int EdgeType; const int MAXVEX = 100; const int MAXEDGE = 1000; struct MGraph { VertexType vexs[MAXVEX]; EdgeType arc[MAXVEX][MAXVEX]; int numVertexes; int numEdges; }; bool visited[MAXVEX]; void BFStraverse(MGraph &G, vector<VertexType> &res) { for (int i = 0; i < G.numVertexes; ++i) visited[i] = false; queue<int> Q; for (int i = 0; i < G.numVertexes; ++i) { if (!visited[i]) { visited[i] = true; Q.push(i); res.push_back(G.vexs[i]); while (!Q.empty()) { int m = Q.front();//数据结构中此处用i来存储队列第一个元素,可是这样就必须要保证从第一个节点开始按照顺序存储每个节点在vex数组中,
//即从第一个节点开始,按照其子节点依次增加序列 用m来存储当前队列队首元素则不用那样依次存储
Q.pop(); for (int j = 0; j < G.numVertexes; ++j) { if (!visited[j] && G.arc[m][j] != 0) { visited[j] = true; res.push_back(G.vexs[j]); Q.push(j); } } } } } }
邻接表的广度优先遍历:
//************邻接表的广度优先遍历 typedef char VertexType; typedef int EdgeType; const int MAXVEX = 100; const int MAXEDGE = 1000; struct EdgeNode { int adjvex; EdgeType weight; EdgeNode *next; }; struct VertexNode { VertexType data; EdgeNode *firstedge; }; struct GraphAdjList { VertexNode adjList[MAXVEX]; int numVertexes; int numEdges; }; bool visited[MAXVEX]; void BFStraverse(GraphAdjList *G, vector<VertexType>&res) { for (int i = 0; i < G->numVertexes; ++i) visited[i] = false; queue<int> Q; EdgeNode *p; for (int i = 0; i < G->numVertexes; ++i) { if (!visited[i]) { visited[i] = true; res.push_back(G->adjList[i].data); Q.push(i); while (!Q.empty()) { int m = Q.front(); p = G->adjList[m].firstedge; while (p) { if (!visited[p->adjvex]) { visited[p->adjvex] = true; res.push_back(G->adjList[p->adjvex].data); Q.push(p->adjvex); } p = p->next; } } } } }