描述:
无向连通图按邻接表存储结构存储的非深度优先遍历方法:
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上权值类型
typedef struct EdgeNode
{
int adjvex; // 邻接点域,存储该顶点对应的下标
EdgeType weight; // 用于存储权值,对于非网图可以不需要
struct EdgeNode* next; // 链域
};
typedef struct VertexNode
{
VertexType data; // 顶点域
EdgeNode* firstEdge; // 边表头指针
}VertexNode, AdjList[100];
typedef struct
{
AdjList adjList;
int numVertexes, numEdges; // 图中当前顶点数和边数
}GraphAdjList;
void CreateALGraph(GraphAdjList& G)
{
int i, j, k;
EdgeNode* e;
printf("输入顶点数和边数:\n");
cin >> G.numVertexes >> G.numEdges;
//printf("%d %d", G.numVertexes, G.numEdges);
printf("输入顶点信息:\n");
for (i = 0; i < G.numVertexes; ++i)
{ // 输入顶点信息
cin >> G.adjList[i].data;
G.adjList[i].firstEdge = NULL; // 将边表置为空表
}
for (k = 0; k < G.numEdges; ++k)
{
printf("输入边(vi,vj)上的顶点序号:\n");
cin >> i >> j;
e = new EdgeNode;
e->adjvex = j;
e->next = G.adjList[i].firstEdge;
G.adjList[i].firstEdge = e;
e = new EdgeNode;
e->adjvex = i; // 自己的邻接序号是i
e->next = G.adjList[j].firstEdge;
G.adjList[j].firstEdge = e;
}
}
bool visited[100]; // 标记该顶点是否被访问过
void DFS(GraphAdjList G, int i)
{
EdgeNode* p;
visited[i] = true; // 该点被访问过
printf("%c ", G.adjList[i].data);
p = G.adjList[i].firstEdge;
while (p)
{
if (!visited[p->adjvex]) DFS(G, p->adjvex);
p = p->next;
}
}
void DFSTraversal(GraphAdjList G)
{
int i;
for (i = 0; i < G.numVertexes; ++i)
{
visited[i] = 0;
}
for (i = 0; i < G.numVertexes; ++i)
{
if (!visited[i]) DFS(G, i);
}
}
// 非递归DFS
void DFS2(GraphAdjList G, int i)
{
stack<int> s;
visited[i] = true; // 表示该点已经访问过
cout << G.adjList[i].data << " ";
s.push(i);
while (!s.empty())
{ // 栈不为空
int tmp = s.top(); // 取栈顶元素
EdgeNode* p = G.adjList[tmp].firstEdge;
// 在序号为tmp顶点的边表中找未被访问过的顶点
while (p && visited[p->adjvex])
{
p = p->next;
}
if (!p) s.pop(); // 没找到,则说明该顶点对应的边表遍历完了,弹出该顶点
else {
s.push(p->adjvex);
cout << G.adjList[p->adjvex].data << " ";
visited[p->adjvex] = true;
}
}
}
void DFSTraversal2(GraphAdjList G)
{
int i;
for (i = 0; i < G.numVertexes; ++i)
{
visited[i] = 0;
}
for (i = 0; i < G.numVertexes; ++i)
{
if (!visited[i]) DFS2(G, i);
}
}
int main(void)
{
GraphAdjList A;
CreateALGraph(A);
cout << "递归深度优先遍历结果:" << endl;
DFSTraversal(A);
cout << endl;
cout << "非递归深度优先遍历结果:" << endl;
DFSTraversal2(A);
cout << endl;
return 0;
}
测试结果
讨论:
在上述代码中我将递归跟非递归方法都写了上去,目的是想作进一步对比。
从两种方法上看,不难发现,在遍历顶点边表的过程中,在递归方法中是不会重复遍历边表的,一个顶点的边表它遍历一次且仅只有一次。而在非递归方法中,它的边表是有可能重复遍历的,所以对于邻接表的非递归方法,如果不做进一步改进,它的时间复杂度是要高于递归方法的,也就是说在这种情况下我们最好还是用递归方法去实现深度优先遍历。
不过对于非递归方法可以通过进一步改进,比如说拿个数组来存遍历边表信息,可以解决这一问题,不过这样子就变复杂了,所以我还是比较推荐用递归去实现邻接表的深度优先遍历的。