图的遍历:
定义:从图中的某一顶点出发,沿着边访问访问图中其余顶点,且使每个顶点仅被访问一次。
通常有两种遍历次序方案:
•深度优先遍历(dfs)---类似于前序遍历
•广度优先遍历(bfs)---类似于层序遍历
•深度优先遍历(dfs)
算法思想描述:
访问起始顶点v
当 v 还有邻接顶点未被访问时:(起始条件)
•深度遍历未访问的邻接顶点w
当 v 的所有邻接顶点都被访问时:
•若图中所有顶点均已访问,算法结束(终止条件)
•若图中还有未访问的顶点,以未访问顶点作为起始顶点深度遍历
•广度优先遍历(bfs)
算法思想描述:
1.访问其实顶点v0
2.依次访问v0的各个邻接点v01,v02...
3.假设最近一次访问的顶点依次为vi1,vi2...,则依次访问vi1,vi2...的未被访问的邻接点
4.重复3,直到所有顶点均被访问
在邻接链表中
实现深度优先遍历(DFS)与广度优先遍历(BFS):
static void dfs_recursive(tl_graph* graph, int v, int *visited, graph_printf* p_func)
{
int i = 0;
p_func(graph->v[v]);
visited[v] = 1;
printf(", ");
for(i=0; i<LinkList_Length(graph->la[v]); i++)
{
t_list_node* node = (t_list_node*)LinkList_Get(graph->la[v], i);
if(!visited[node->v])
{
dfs_recursive(graph, node->v, visited, p_func);
}
}
}
void DFS_traverse(LGraph* graph, int v, graph_printf* p_func)
{
tl_graph* t_graph = (tl_graph*)graph;
int *visited = NULL;
int ok = 1;
ok = (ok) && (t_graph != NULL) && (p_func != NULL);
ok = (ok) && (0 <= v) && (v < t_graph->count);
/*借鉴其申请数组空间的方式*/
ok = (ok) && ((visited = (int*)calloc(t_graph->count, sizeof(int))) != NULL);
if(ok)
{
int i = 0;
dfs_recursive(t_graph, v, visited, p_func);
for(i=0; i<t_graph->count; i++)
{
if(!visited[i])
{
dfs_recursive(t_graph, i, visited, p_func);
}
}
printf("\n");
}
free(visited);
}
static void bfs_recursive(tl_graph* graph, int v, int visited[], graph_printf* p_func)
{
LinkQueue* queue = LinkQueue_Create();
if(queue != NULL)
{
int i = 0;
t_list_node* node = NULL;
visited[v] = 1;
/*将在图中下标为v的顶点放入队列,
又vk可能为0,而在实现队列时,传入队列的参数不能为零,
则加上graph->v的基地址(graph->v只是一个无用的地址),从而避免v为0时的错误。
在取出队列元素是应减去该基地址*/
LinkQueue_Append(queue, graph->v + v);
while( LinkQueue_Length(queue) > 0 )
{
/*传入的是标号地址,传出自然也是标号地址*/
v = (l_vertex**)LinkQueue_Retrieve(queue) - graph->v;
p_func(graph->v[v]);
printf(", ");
for(i=0; i<LinkList_Length(graph->la[v]); i++)
{
node = (t_list_node*)LinkList_Get(graph->la[v], i);
if(!visited[node->v])
{
LinkQueue_Append(queue, graph->v + node->v);
visited[node->v] = 1;
}
}
}
}
LinkQueue_Destroy(queue);
}
void BFS_traverse(LGraph* graph, int v, graph_printf* p_func)
{
tl_graph* t_graph = (tl_graph*)graph;
int *visited = NULL;
int ok = 1;
ok = (ok) && (t_graph != NULL) && (p_func != NULL);
ok = (ok) && (0 <= v) && (v < t_graph->count);
/*借鉴其申请数组空间的方式*/
ok = (ok) && ((visited = (int*)calloc(t_graph->count, sizeof(int))) != NULL);
if(ok)
{
int i = 0;
bfs_recursive(t_graph, v, visited, p_func);
for(i=0; i<t_graph->count; i++)
{
if(!visited[i])
{
bfs_recursive(t_graph, i, visited, p_func);
}
}
printf("\n");
}
free(visited);
}
在邻接矩阵中实现深度优先遍历(DFS)与广度优先遍历(BFS):
/*参数说明:
graph:指向图头结点的指针
v:顶点在整个顶点数组下的标号
visited:标记访问的顶点
p_func:打印结点信息函数
*/
static void dfs_recursive(tm_graph* graph, int v, int *visited, graph_printf* p_func)
{
int i = 0;
p_func(graph->v[v]);
visited[v] = 1;
printf(", ");
for(i=0; i<graph->count; i++)
{
if((graph->matrix[v][i] != 0) && (!visited[i]))
{
dfs_recursive(graph, i, visited, p_func);
}
}
}
void DFS_traverse(MGraph* graph, int v, graph_printf* p_func)
{
tm_graph* t_graph = (tm_graph*)graph;
int *visited = NULL;
int ok = 1;
ok = (ok) && (t_graph != NULL) && (p_func != NULL);
ok = (ok) && (0 <= v) && (v < t_graph->count);
/*借鉴其申请数组空间的方式*/
ok = (ok) && ((visited = (int*)calloc(t_graph->count, sizeof(int))) != NULL);
if(ok)
{
int i = 0;
dfs_recursive(t_graph, v, visited, p_func);
for(i=0; i<t_graph->count; i++)
{
if(!visited[i])
{
dfs_recursive(t_graph, i, visited, p_func);
}
}
printf("\n");
}
free(visited);
}
static void bfs_recursive(tm_graph* graph, int v, int visited[], graph_printf* p_func)
{
LinkQueue* queue = LinkQueue_Create();
if(queue != NULL)
{
int i = 0;
visited[v] = 1;
LinkQueue_Append(queue, graph->v + v);
while( LinkQueue_Length(queue) > 0 )
{
v = (m_vertex**)LinkQueue_Retrieve(queue) - graph->v;
p_func(graph->v[v]);
printf(", ");
for(i=0; i<graph->count; i++)
{
if((graph->matrix[v][i]) && (!visited[i]))
{
LinkQueue_Append(queue, graph->v + i);
visited[i] = 1;
}
}
}
}
LinkQueue_Destroy(queue);
}
void BFS_traverse(MGraph* graph, int v, graph_printf* p_func)
{
tm_graph* t_graph = (tm_graph*)graph;
int *visited = NULL;
int ok = 1;
ok = (ok) && (t_graph != NULL) && (p_func != NULL);
ok = (ok) && (0 <= v) && (v < t_graph->count);
/*借鉴其申请数组空间的方式*/
ok = (ok) && ((visited = (int*)calloc(t_graph->count, sizeof(int))) != NULL);
if(ok)
{
int i = 0;
bfs_recursive(t_graph, v, visited, p_func);
for(i=0; i<t_graph->count; i++)
{
if(!visited[i])
{
bfs_recursive(t_graph, i, visited, p_func);
}
}
printf("\n");
}
free(visited);
}
注:
1、对于层次遍历的操作,均需要借助队列实现
2、使用队列时的弊端(是因为实现时造成的弊端)
实现广度优先遍历时,传入队列元素的值不能为0 ,则需注意传入的图下标的值不能为零。可在下标值的基础上上增加一定的数值,之后用的时候再减去原先加上的值。