图的DFS和BFS算法

前言


文章主要介绍数据结构知识板块中图的两种不同存储结构下(邻接表和邻接矩阵)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;
        }

        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算法均基于其思想,因为是按层进行搜索,所以很容易求得最短路径。

猜你喜欢

转载自blog.csdn.net/gerald_jones/article/details/80158868