##前言
文章主要介绍数据结构知识板块中图的两种不同存储结构下(邻接表和邻接矩阵)BFS和DFS遍历算法。BFS和DFS应用领域不再说明,深搜和广搜的遍历算法十分重要。
##DFS
原理:深度优先搜索,顾名思义即为一条道走到黑的搜索策略,行不通退回来换另外一条道再走到黑,依次直到搜索完成。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。可以通过图示清晰的说明。
图解遍历下图的全部节点:
基于邻接矩阵的DFS算法代码实现
void DFS(GraphAMatrix G,int i,int *visited)
{
int j;
if(visited[i])
return ;//若结点被遍历过 返回
else
{
cout<<i<<endl;
visited[i]=1;
//遍历与该结点相邻的结点 (从第一个开始)
for(j=0;j<G.numVertexs;j++)
{
if(!visited[i]&&G.Edge[i][j])
DFS(G,j,visited);//从相邻结点的第一个进行递归式深搜遍历
}
}
}
void DFS_GreahDG(GreapAMstrix G)
{
int i,j,e;
int *visited;//为每一个结点设置一个初始标志为未遍历
visited=(int *)malloc(sizeof(int)*G.numVertexs);
memset(visited,0,sizeof(int)*G.numVertexs);
//对每一个未被遍历结点进行DFS深度搜索
for(i=0;i<G.numVertexs;i++)
{
if(!visited[i])
DFS(G,i,visited);//调用深搜算法
}
free(visited);//释放指针
printf("\n");
}
基于邻接表的DFS算法实现(全)
#include<iostream>
#include<stdlib.h>
#define maxvn 10
using namespace std;
typedef char VertexType;
//定义图的存储数据类型
typedef struct ArcNode{
int adjvesx;
struct ArcNode *nextarc;
int info;
}ArcNode;
typedef struct VNode{
VertexType data;
ArcNode *firstarc;
}VNode,AdjList[maxvn];
typedef struct{
AdjList vertices;
int Vnum,Anum;
}AdjGraph;
//定义一个全局标识数组
int visited[maxvn];
int LocateVex(char u,AdjGraph G)
{
int i;
for(i=0;i<G.Vnum;i++)
{
if(u==G.vertices[i].data)
return i;
}
if(i==G.Vnum)
{
cout<<"ERROR!"<<endl;
exit(1);
}
return 0;
}
//创建图
void CreatAdjGraph_adjList(AdjGraph &G)
{
ArcNode *p;
cout<<"Please input Vnum and Anum:"<<endl;
cin>>G.Vnum>>G.Anum;
cout<<"Please input Vertices:"<<endl;//创建表头
for(int i=0;i<G.Vnum;i++)
{
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
cout<<"Please input Arc[i][j]:"<<endl;//创建链表
for(int k=0;k<G.Anum;k++)
{
p=(ArcNode*)malloc(sizeof(ArcNode));
char v1,v2;
cin>>v1>>v2;
int i=LocateVex(v1,G);
int j=LocateVex(v2,G);
int w;
cin>>w;
p->adjvesx=j;
p->info=w;
p->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p;
}
}
//深搜算法
void DFS(AdjGraph G,int i)
{
ArcNode*p;
visited[i]=1;
p=G.vertices[i].firstarc;
while(p)
{
if(!visited[p->adjvesx])
{
visited[p->adjvesx]=1;
cout<<p->adjvesx<<endl;
DFS(G, p->adjvesx);
}
p=p->nextarc;
}
return;
}
//调用深搜算法
void DFSTraverse(AdjGraph G)
{
for(int i=0;i<G.Vnum;i++)
visited[i]=0;
for(int i=0;i<G.Vnum;i++)
{
if(!visited[i])
DFS(G,i);
}
}
//主函数
int main()
{
AdjGraph G;
CreatAdjGraph_adjList(G);
DFSTraverse(G);
return 0;
}
##BFS
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
我们可以图示清楚的了解算法的具体实施过程:
基于邻接矩阵的BFS:
void BFS_Graph(GraphAMatrix G){
//图的广度优先遍历
int i,j,e;//i j 为循环控制变量 e为取队列元素变量
CQueue Q;
int *visited = (int *)malloc(sizeof(int)*G.numVertexes);//标记数组
InitCQueue(&Q);
for(int i=0;i<G.numVertexes;i++){
//遍历所有顶点 非连通图的情况化 要遍历全部加上循环
if(!visited[i]){
printf("%d",i);
visited[i] = 1;
EnCQueue(&Q,i);//起点入队列
while(!CQueue(Q)){//循环操作
DeQueue(&Q,&e);//出队列
for(int j=0;j<G.numVertexes;j++){
//遍历顶点集合
if(!visited[j]&&G.edges[e][j]){
//判断当前结点是否被访问过 且与出队结点是否相连
printf("%d",j);
visited[j] = 1;
EnCQueue(&Q,j);
}
}
}
}
}
free(visited);
printf("\n");
}
基于邻接表的BFS
void BFS_GraphADJList(GraphADJList G){
//图的广度优先遍历
int i,j,e;//i j 为循环控制变量 e为取队列元素变量
CQueue Q;
EdgeNode *p;
int *visited = (int *)malloc(sizeof(int)*G.numVertexes);//标记数组
InitCQueue(&Q);
for(int i=0;i<G.numVertexes;i++){
//遍历所有顶点 非连通图的情况化 要遍历全部加上循环
if(!visited[i]){
printf("%d",i);
visited[i] = 1;
EnCQueue(&Q,i);//起点入队列
while(!CQueue(Q)){//循环操作
DeQueue(&Q,&e);//出队列
p = G.adjList[e].firstedge;//从顶点的链表的第一个边结点开始
while(p){
j = p->adjvex;//记录当前边的终点序号
if(!visited[j]){
printf("%d",j);
visited[j] = 1;
EnCQueue(&Q,j);
}
p = p->next;//移动到下一条边
}
}
}
}
free(visited);
printf("\n");
}
##DFS与BFS比较
DFS深度优先搜索,空间需求较低,不需要BFS需要一个队列保存搜索过程中搜索记录;其次,深搜在搜索过程中要考虑回溯,在搜索HTML链接,爬取数据方面适用颇多;多用于解决连通性问题。
BFS广度优先搜索,空间需求较高,根据其搜索模式,便于求解最短路径问题,上文提到的Dijkstral和prim算法均基于其思想,因为是按层进行搜索,所以很容易求得最短路径。