图论中一个基本的概念就是遍历。就是访问到图的每一个顶点,同时每个顶点只访问一次。
DFS和BFS的概念和思路网上说明的很详细了。但是网上很多代码实现有缺陷,基本都没有考虑图不连通的情况,比如某个顶点A和其它任何一个顶点都不关联,那么这个顶点A就访问不到了。如果遍历的起点刚好是孤立的顶点A,就只能访问顶点A了,其它顶点就访问不到了。
我这边的代码就是增加了这些情况的处理,确保每个顶点都能可以访问到。
完整的代码如下(通过邻接矩阵实现图):
#define MAX_VERTEX 16
typedef enum
{
UNDIRECTED_GRAPH = 0, //无向图
DIRECTED_GRAPH = 1, //有向图
UNDIRECTED_NET = 2, //无向网
DIRECTED_NET = 3, //有向网
}GRAPH_TYPE;
typedef struct
{
GRAPH_TYPE type; //图的类型
int vertexCount;//顶点个数
BOOL visitFlag[MAX_VERTEX];
char vertex[MAX_VERTEX]; //顶点数组
int edge[MAX_VERTEX][MAX_VERTEX]; //邻接矩阵
}GRAPH,*PGRAPH;
void Visit(PGRAPH graph,int vIndex)
{
graph->visitFlag[vIndex] = TRUE; //设置已访问标志
printf("Visit Vertex: %c\r\n",graph->vertex[vIndex]);
}
void DFS(PGRAPH graph,int startVertexIndex)
{
stack<int> s; //访问栈
s.push(startVertexIndex);
while(!s.empty())
{
int vertexIndex = s.top();
if(!graph->visitFlag[vertexIndex])//未访问过
{
Visit(graph,vertexIndex);
}
s.pop();//vertexIndex顶点出栈
for(int j=graph->vertexCount-1;j>=0;j--)
{
if(!graph->visitFlag[j] && graph->edge[vertexIndex][j])
{
s.push(j); //于vertexIndex相邻的顶点并且未访问过的顶点全部入栈
}
}
}
//图并不一定是连通的,因此要确保每个顶点都遍历过
for(int i=0;i<graph->vertexCount;i++)
{
if(!graph->visitFlag[i])
{
printf("Not Connected vertex start DFS: %c\r\n",graph->vertex[i]);
DFS(graph,i);
}
}
}
void BFS(PGRAPH graph,int startVertexIndex)
{
queue<int> q; //访问队列
q.push(startVertexIndex);//起始访问的顶点入队
while(!q.empty())
{
int vertexIndex = q.front();
if(!graph->visitFlag[vertexIndex])//未访问过
{
Visit(graph,vertexIndex);
}
q.pop();//vertexIndex顶点出队
for(int j=0;j<graph->vertexCount;j++)
{
if(!graph->visitFlag[j] && graph->edge[vertexIndex][j])
{
q.push(j); //于vertexIndex相邻的顶点并且未访问过的顶点全部入队
}
}
}
//图并不一定是连通的,因此要确保每个顶点都遍历过
for(int i=0;i<graph->vertexCount;i++)
{
if(!graph->visitFlag[i])
{
printf("Not Connected vertex start BFS: %c\r\n",graph->vertex[i]);
BFS(graph,i);
}
}
}
void InitGraph(PGRAPH graph)
{
graph->type = UNDIRECTED_GRAPH; //无向图
graph->vertexCount = 10;
for(int i=0;i<graph->vertexCount;i++)
{
graph->vertex[i] = 'A'+i; //顶点为'A','B','C'等等
}
graph->edge[0][1] = 1;//AB有边
graph->edge[1][0] = 1;
graph->edge[0][4] = 1;//AE有边
graph->edge[4][0] = 1;
graph->edge[1][3] = 1;//BD有边
graph->edge[3][1] = 1;
graph->edge[2][4] = 1;//EC有边
graph->edge[4][2] = 1;
graph->edge[2][5] = 1;//CF CG CH 有边
graph->edge[5][2] = 1;
graph->edge[2][6] = 1;
graph->edge[6][2] = 1;
graph->edge[2][7] = 1;
graph->edge[7][2] = 1;
graph->edge[6][8] = 1;//GI GJ 有边
graph->edge[8][6] = 1;
graph->edge[6][9] = 1;
graph->edge[9][6] = 1;
}
void InitVistFlag(PGRAPH graph)
{
for(int i=0;i<graph->vertexCount;i++)
{
graph->visitFlag[i] = FALSE;
}
}
void TestGraph()
{
GRAPH graph = {UNDIRECTED_GRAPH,0};
InitGraph(&graph);
printf("Test BFS,Start vertex 0:\r\n");
BFS(&graph,0);
InitVistFlag(&graph);
printf("\r\nTest DFS,Start vertex 0:\r\n");
DFS(&graph,0);
InitVistFlag(&graph);
for(int i=0;i<graph.vertexCount;i++)
{
graph.edge[2][i] = 0;
graph.edge[i][2] = 0;//使得第3个顶点和任何顶点都不连通
}
printf("\r\nTest BFS,Start vertex 5:\r\n");
BFS(&graph,5);
InitVistFlag(&graph);
printf("\r\nTest DFS,Start vertex 5:\r\n");
DFS(&graph,5);
}