图的创建和遍历
图是一种重要的数据结构,用于表示节点之间的关系。在本篇文章中,我们将介绍如何创建图并实现深度优先搜索(DFS)和广度优先搜索(BFS)算法。
创建图
首先,让我们看看如何创建一个图。
图由顶点集和边集组成。顶点集通常是一个一维数组,边集通常是一个二维数组。以下是创建图的代码示例:
typedef struct Graph
{
char *v;//顶点集 一维数组
char *e;//边集 二维数组
int cnt;//顶点的数量
}Graph;
Graph *create_graph(const char *str)
{
Graph *graph = malloc(sizeof(Graph));
graph->cnt = strlen(str);
graph->v = malloc(graph->cnt * sizeof(char));
strcpy(graph->v, str);
graph->e = calloc(graph->cnt ,graph->cnt);
return graph;
}
在上面的代码中,我们定义了一个 Graph
结构体,包含顶点集、边集和顶点数量,并实现了创建图的函数 create_graph
。
深度优先搜索(DFS)
深度优先搜索是一种图遍历算法,它从起始顶点开始,沿着一条路径尽可能深地访问顶点,直到无法继续为止。以下是深度优先搜索的代码示例:
//深度优先遍历
void dfs_helper(Graph *graph, int vertex, bool visited[])
{
visited[vertex] = true;//标记已遍历的为true
printf("%c ", graph->v[vertex]);
for (int i = 0; i < graph->cnt; i++)
{
// 遍历当前顶点的所有邻接顶点
if (graph->e[vertex * graph->cnt + i] && !visited[i])
{
dfs_helper(graph, i, visited);
}
}
}
void dfs_show(Graph *graph, char v)
{
bool visited[graph->cnt];
memset(visited, false, sizeof(visited));// 初始化访问标记数组
for (int i = 0; i < graph->cnt; i++)
{
if (graph->v[i] == v)
{
dfs_helper(graph, i, visited);
break;
}
}
}
在上面的代码中,我们定义了深度优先搜索的函数 dfs_show
,用于遍历图并输出遍历结果。
广度优先搜索(BFS)
广度优先搜索是另一种图遍历算法,它从起始顶点开始,逐层访问所有邻接顶点。以下是广度优先搜索的代码示例:
//广度优先遍历
void bfs_show(Graph *graph)
{
bool visited[graph->cnt];
memset(visited,false,sizeof(visited));
ListQueue *queue=create_list_queue();
for(int i=0;i<graph->cnt;i++)
{
if(!visited[i])
{
visited[i]=true;
printf("%c ",graph->v[i]);
push_list_queue(queue,i);
//遍历队列中的顶点
while(!empty_list_queue(queue))
{
int current=head_list_queue(queue);
pop_list_queue(queue);
// 遍历当前顶点的所有邻接顶点
for(int j=0;j<graph->cnt;j++)
{
// 如果存在边且邻接顶点未被访问,则访问该邻接顶点并入队
if (graph->e[current * graph->cnt + j] && !visited[j])
{
visited[j]=true;
printf("%c ",graph->v[j]);
push_list_queue(queue,j);
}
}
}
}
}
destroy_list_queue(queue);
}
在上面的代码中,我们定义了广度优先搜索的函数 bfs_show
,用于遍历图并输出遍历结果。
示例代码
下面是一个完整的示例代码,包括图的创建、添加边、计算入度和出度、深度优先搜索和广度优先搜索的实现:
#include <stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include"link_array_queue.h"
typedef struct Graph
{
char *v;//顶点集 一维数组
char *e;//边集 二维数组
int cnt;//顶点的数量
}Graph;
Graph *create_graph(const char *str)
{
Graph *graph = malloc(sizeof(Graph));
graph->cnt = strlen(str);
graph->v = malloc(graph->cnt * sizeof(char));
strcpy(graph->v, str);
graph->e = calloc(graph->cnt ,graph->cnt);
return graph;
}
//添加边
bool add_graph(Graph *graph,char v1,char v2)
{
int x=-1,y=-1;
for(int i=0;i<graph->cnt;i++)//标记下标
{
if(v1==graph->v[i])
x=i;
if(v2==graph->v[i])
y=i;
}
if(x==-1||y==-1)return false;//有一个未找到,返回错误
//有向图
graph->e[x*graph->cnt+y]=1;
//无向图,再加一个反方向的
//graph->e[y*graph->cnt+x]=1;
return true;
}
//计算顶点的入度
int id_graph(Graph *graph,char v)
{
for(int y=0;y<graph->cnt;y++)
{
if(v==graph->v[y])
{
int id=0;
for(int x=0;x<graph->cnt;x++)
{
id+=graph->e[x*graph->cnt+y];
}
return id;
}
}
}
//计算顶点的出度
int od_graph(Graph *graph,char v)
{
for(int x=0;x<graph->cnt;x++)
{
if(v==graph->v[x])
{
int od=0;
for(int y=0;y<graph->cnt;y++)
{
od+=graph->e[x*graph->cnt+y];
}
return od;
}
}
}
//
void show_graph(Graph *graph)
{
printf(" ");
for(int i=0;i<graph->cnt;i++)
{
printf(" %c",graph->v[i]);
}
printf("\n");
for(int i=0;i<graph->cnt;i++)
{
printf("%c",graph->v[i]);
for(int j=0;j<graph->cnt;j++)
{
printf(" %d",graph->e[j+graph->cnt*i]);
}
printf("\n");
}
}
//深度优先遍历
void dfs_helper(Graph *graph, int vertex, bool visited[])
{
visited[vertex] = true;//标记已遍历的为true
printf("%c ", graph->v[vertex]);
for (int i = 0; i < graph->cnt; i++)
{
// 遍历当前顶点的所有邻接顶点
if (graph->e[vertex * graph->cnt + i] && !visited[i])
{
dfs_helper(graph, i, visited);
}
}
}
void dfs_show(Graph *graph, char v)
{
bool visited[graph->cnt];
memset(visited, false, sizeof(visited));// 初始化访问标记数组
for (int i = 0; i < graph->cnt; i++)
{
if (graph->v[i] == v)
{
dfs_helper(graph, i, visited);
break;
}
}
}
//广度优先遍历
void bfs_show(Graph *graph)
{
bool visited[graph->cnt];
memset(visited,false,sizeof(visited));
ListQueue *queue=create_list_queue();
for(int i=0;i<graph->cnt;i++)
{
if(!visited[i])
{
visited[i]=true;
printf("%c ",graph->v[i]);
push_list_queue(queue,i);
//遍历队列中的顶点
while(!empty_list_queue(queue))
{
int current=head_list_queue(queue);
pop_list_queue(queue);
// 遍历当前顶点的所有邻接顶点
for(int j=0;j<graph->cnt;j++)
{
// 如果存在边且邻接顶点未被访问,则访问该邻接顶点并入队
if (graph->e[current * graph->cnt + j] && !visited[j])
{
visited[j]=true;
printf("%c ",graph->v[j]);
push_list_queue(queue,j);
}
}
}
}
}
destroy_list_queue(queue);
}
int main(int argc,const char* argv[])
{
char *str="ABCDEFG";
Graph *graph=create_graph(str);
add_graph(graph,'A','B');
add_graph(graph,'A','D');
add_graph(graph,'B','D');
add_graph(graph,'B','E');
add_graph(graph,'C','D');
add_graph(graph,'C','F');
add_graph(graph,'D','C');
add_graph(graph,'D','G');
add_graph(graph,'E','G');
add_graph(graph,'F','G');
add_graph(graph,'G','F');
show_graph(graph);
printf("B的入度:%d\n",id_graph(graph,'B'));
printf("C的出度:%d\n",od_graph(graph,'C'));
dfs_show(graph,'A');
printf("\n");
bfs_show(graph);
return 0;
}
通过以上介绍,我们学习了如何创建图并实现深度优先搜索和广度优先搜索算法。希望本文能帮助您更好地理解图的创建和遍历。