浅谈【数据结构】图-图的遍历
目录
1、图的遍历
2、深度优先搜索算法
3、广度优先搜索算法
谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注
没错,说的就是你,不用再怀疑!!!
希望我的文章内容能对你有帮助,一起努力吧!!!
1、图的遍历
图的遍历是对树的遍历的推广,是按照一种规划(或者说是一种次序)访问图中各顶点一次,并且只能 访问一次,亦或者是将网状结构按照某种规划进行线性化。
对于图的遍历通常有两种方式:
- 广度优先搜索算法(Breath First search)BFS
- 深度优先搜索算法(Depth First search)DFS
两者是现代人工智能AI的基础。
2、深度优先搜索算法
深度优先搜索算法(Depth First search)DFS
设初始化的时候,图中各个顶点均为被访问过。从图中某个顶点(V0)出发,访问V0,然后搜索V0的 邻接顶点Vi,再以Vi为基础访问Vi的邻接顶点(依次下去...)(深度优先)。若某个顶点没有邻接顶点 (邻接顶点均被访问完毕),则回溯到它上一个顶点,然后再从它的上一个顶点开始继续进行邻接顶点 的访问,直到所有的顶点都被访问完毕。
***DFS示例代码***
#include <iostream>
#include <cstring>
// 关系类型
typedef struct relation
{
int index; // 下标
int weight; // 权值
struct relation *next; // 下一个关系的顶点的下标指针
}Relation_t;
// 顶点类型
typedef struct
{
std::string data; // 顶点数据
Relation_t *first; // 该顶点的关系集
}Vertex_t;
// 当前顶点数
int current_count = 0;
/*
@brief 创建一个图:邻接表
@param count 该图的最大顶点数量
@return 成功返回创建好的图指针
*/
Vertex_t *creatGraph(int count)
{
// 申请空间
Vertex_t *graph = new Vertex_t[count];
// 初始化
memset(graph,0,sizeof(Vertex_t)*count);
std::cout << "请输入顶点数据空格分开(“结束”输入):";
// 接受顶点
while(1)
{
std::string data = "结束";
std::cin >> data;
if(data == "结束")
break;
if(current_count == count)
break;
// 新增顶点位置
graph[current_count].data = data;
graph[current_count].first = nullptr;
current_count++;
}
// 增加关系
while(1)
{
std::cout << "请输入顶点关系(结束 结束 -1):";
// 出发顶点和终止顶点 权值
std::string start;
std::string end;
int data;
std::cin >> start >> end >> data;
if(start=="结束"||end=="结束"||data == -1)
break;
// 存储关系
// 获取start和end在图数组的什么位置
int index_s = 0,index_e = 0;
for(;index_s < current_count;index_s++)
if(graph[index_s].data == start)
break;
for(;index_e < current_count;index_e++)
if(graph[index_e].data == end)
break;
// 两个顶点的下标找到了
if(index_s == current_count||index_e == current_count)
continue;
// 添加关系
Relation_t *rt = new Relation_t;
rt->index = index_e;
rt->weight = data;
rt->next = nullptr;
// 当至少存在出度顶点的时候
if(graph[index_s].first)
{
Relation_t *rt_ptr = graph[index_s].first;
while(rt_ptr->next)
rt_ptr = rt_ptr->next;
// 存进关系链表
rt_ptr->next = rt;
}
else{ // 一个出度结点都没有的时候
graph[index_s].first = rt;
}
}
return graph;
}
void printrelation(Vertex_t *graph)
{
if(!graph)
std::cout << "空图" << std::endl;
for(int count_v = 0;count_v < current_count;count_v++)
{
std::cout << "顶点<"<< graph[count_v].data <<">:";
Relation_t *rt_ptr = graph[count_v].first;
while(rt_ptr)
{
std::cout<< "<"<< graph[count_v].data <<","<<
graph[rt_ptr->index].data <<">"
<< "("<<rt_ptr->weight<<")";
rt_ptr = rt_ptr->next;
}
std::cout << std::endl;
}
}
// 计算下标
int getIndex(Vertex_t *graph,std::string vertex_v)
{
for(int index = 0;index < current_count;index++)
{
if(vertex_v == (graph[index]).data)
return index;
}
return -1;
}
/*
逻辑:
设初始化的时候,图中各个顶点均为被访问过。
从图中某个顶点(V0)出发,访问V0,然后搜索V0的邻接顶点Vi,再以Vi为基础访问Vi的邻接顶点(依次下去...)(深度优先)。
若某个顶点没有邻接顶点(邻接顶点均被访问完毕),
则回溯到它上一个顶点,然后再从它的上一个顶点开始继续进行邻接顶点的访问,直到所有的顶点都被访问完毕。
@brief 深度优先搜索算法
@param graph 需要进行深度优先搜索的图指针
*/
void DFS(Vertex_t *graph,std::string v0)
{
int v0_pos = getIndex(graph,v0);
if(v0_pos == -1)
return;
// 标志位数组,且初始化所有顶点都为未被访问
static bool *flags=new bool[current_count];
// 访问V0
std::cout << graph[v0_pos].data << " ";
flags[v0_pos] = true;
Relation_t *currnet_relation = graph[v0_pos].first;
while(currnet_relation)
{
// 递归下去进行访问
if(flags[currnet_relation->index] == false)
DFS(graph,graph[currnet_relation->index].data);
// 递归结束返回,再次访问下一个邻接点
currnet_relation = currnet_relation->next;
}
std::cout << std::endl;
}
int main()
{
Vertex_t *graph = creatGraph(10);
DFS(graph,"A");
delete []graph;
return 0;
}
3、广度优先搜索算法
广度优先搜索算法(Breath First search)BFS
类似于树的层次遍历,初始化的时候,图中的各项顶点均未被访问,从图某个顶点开始(V0)依次的访 问V0的各个邻接点(广度优先)
然后分别冲这些被访问过的顶点出发,仍然按照广度优先的策略访问其他的顶点...直到所有能访问的顶 点均被访问完毕。
***BFS示例代码***
#include <iostream>
#include <cstring>
#include <queue>
// 关系类型
typedef struct relation
{
int index; // 下标
int weight; // 权值
struct relation *next; // 下一个关系的顶点的下标指针
}Relation_t;
// 顶点类型
typedef struct
{
std::string data; // 顶点数据
Relation_t *first; // 该顶点的关系集
}Vertex_t;
// 当前顶点数
int current_count = 0;
/*
@brief 创建一个图:邻接表
@param count 该图的最大顶点数量
@return 成功返回创建好的图指针
*/
Vertex_t *creatGraph(int count)
{
// 申请空间
Vertex_t *graph = new Vertex_t[count];
// 初始化
memset(graph,0,sizeof(Vertex_t)*count);
std::cout << "请输入顶点数据空格分开(“结束”输入):";
// 接受顶点
while(1)
{
std::string data = "结束";
std::cin >> data;
if(data == "结束")
break;
if(current_count == count)
break;
// 新增顶点位置
graph[current_count].data = data;
graph[current_count].first = nullptr;
current_count++;
}
// 增加关系
while(1)
{
std::cout << "请输入顶点关系(结束 结束 -1):";
// 出发顶点和终止顶点 权值
std::string start;
std::string end;
int data;
std::cin >> start >> end >> data;
if(start=="结束"||end=="结束"||data == -1)
break;
// 存储关系
// 获取start和end在图数组的什么位置
int index_s = 0,index_e = 0;
for(;index_s < current_count;index_s++)
if(graph[index_s].data == start)
break;
for(;index_e < current_count;index_e++)
if(graph[index_e].data == end)
break;
// 两个顶点的下标找到了
if(index_s == current_count||index_e == current_count)
continue;
// 添加关系
Relation_t *rt = new Relation_t;
rt->index = index_e;
rt->weight = data;
rt->next = nullptr;
// 当至少存在出度顶点的时候
if(graph[index_s].first)
{
Relation_t *rt_ptr = graph[index_s].first;
while(rt_ptr->next)
rt_ptr = rt_ptr->next;
// 存进关系链表
rt_ptr->next = rt;
}
else{ // 一个出度结点都没有的时候
graph[index_s].first = rt;
}
}
return graph;
}
void printrelation(Vertex_t *graph)
{
if(!graph)
std::cout << "空图" << std::endl;
for(int count_v = 0;count_v < current_count;count_v++)
{
std::cout << "顶点<"<< graph[count_v].data <<">:";
Relation_t *rt_ptr = graph[count_v].first;
while(rt_ptr)
{
std::cout<< "<"<< graph[count_v].data <<","<<
graph[rt_ptr->index].data <<">"
<< "("<<rt_ptr->weight<<")";
rt_ptr = rt_ptr->next;
}
std::cout << std::endl;
}
}
// 计算下标
int getIndex(Vertex_t *graph,std::string vertex_v)
{
for(int index = 0;index < current_count;index++)
{
if(vertex_v == (graph[index]).data)
return index;
}
return -1;
}
/*
逻辑:
类似于树的层次遍历,初始化的时候,图中的各项顶点均未被访问,
从图某个顶点开始(V0)依次的访问V0的各个邻接点(广度优先)
然后分别冲这些被访问过的顶点出发,仍然按照广度优先的策略访问其他的顶点...直到所有能访问的顶点均被访问完毕。
@brief 广度优先搜索算法
@param graph 需要进行广度优先搜索的图指针
*/
void BFS(Vertex_t *graph,std::string v0)
{
int v0_pos = getIndex(graph,v0);
if(v0_pos == -1)
return;
// 搞个队列
std::queue<int> q;
// 入队V0
q.push(v0_pos);
// 标志位数组,且初始化所有顶点都为未被访问
static bool *flags=new bool[current_count];
// 访问V0
flags[v0_pos] = true;
int current_pos = v0_pos;
while(q.size())
{
Relation_t *currnet_relation=graph[current_pos].first;
// 当前关系是否存在 循环的作用:是将该顶点的所有边都入队
while(currnet_relation)
{
// 是否被访问过
if(flags[currnet_relation->index] == false)
{
q.push(currnet_relation->index);
flags[currnet_relation->index] = true;
}
// 递归结束返回,再次访问下一个邻接点
currnet_relation = currnet_relation->next;
}
// 出队,打印、标记
current_pos = q.front();
q.pop();
std::cout << graph[current_pos].data << " ";
}
std::cout << std::endl;
}
int main()
{
Vertex_t *graph = creatGraph(10);
BFS(graph,"A");
delete []graph;
return 0;
}