图的遍历:从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次。
图比树复杂,为了避免同一顶点被访问多次,可以设置一个辅助数组,初始值置为False或者0。当访问到后,设置值为真或被访问的次序ID。
图遍历主要有两种:深度优先搜索、广度优先搜索。
深度优先遍历
是树的先根遍历的推广。
从图中某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v相连通的路径都被访问到。然后再另选一个未被访问的结点做为起始点。
代码如下:
void graph_dfs(struct Graph* g, int* visit, int i)
{
struct Arc* ptr = g->vexs[i].first_arc;
// Visit
printf("Visit %d\n", g->vexs[i].data);
visit[i] = 1;
// Visit neighor
while(ptr!=NULL)
{
if(!visit[ptr->ivex])
{
graph_dfs(g, visit, ptr->ivex);
}
ptr = ptr->next;
}
}
void graph_dfs_traverse(struct Graph* g)
{
int i;
int visit[MAX_VEXS];
memset(visit, 0, sizeof(int)*MAX_VEXS);
for(i=0; i<g->nvexs; i++)
{
if(!visit[i])
{
graph_dfs(g, visit, i);
}
}
}
当用邻接矩阵(二维数组表示时),查找顶点邻接点的复杂度为O(n^2)。
用邻接表时,实践复杂度为O(n+e)。
广度优先遍历
类似树的层次遍历。
使得“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。此时再选取图中另一个未曾被访问的顶点做为起始点。
实际是依次访问和v有路径、相连通且路径长度为1,2,3。。。的顶点。
和层次遍历一样,也要借助队列,代码如下:
void graph_bfs(struct Graph* g)
{
int i, data;
int flags[MAX_VEXS];
struct Queue q;
struct Arc* ptr;
memset(flags, 0, sizeof(int)*MAX_VEXS);
queue_init(&q);
for(i=0; i<g->nvexs; i++)
{
if(!flags[i])
{
flags[i] = 1;
graph_visit(g, i);
queue_enqueue(&q, i);
while(!queue_is_empty(&q))
{
queue_dequeue(&q, &data);
ptr = g->vexs[data].first_arc;
while(ptr!=NULL)
{
if(!flags[ptr->ivex])
{
flags[ptr->ivex] = 1;
graph_visit(g, ptr->ivex);
queue_enqueue(&q, ptr->ivex);
}
ptr = ptr->next;
}
}
}
}
}