图的深度优先搜索(DFS)和广度优先搜索(BFS)详解

1.图的表示
1.1 邻接矩阵
邻接矩阵是图的顺序存储结构
image.png
图的深度优先搜索(DFS)和广度优先搜索(BFS)详解_第1张图片
“0”和“1”代表列index结点是否有边指向行index结点。
代码表达:

typedef struct{
    int edges[maxSize][maxSize];//邻接矩阵
    int n,e;//顶点数和边数
    int vex[maxSize];//存放顶点信息
}MGraph;

1.2 邻接表
如下图右半部分就是邻接表的存储形式
image.png
所谓邻接表就是对图中的每个顶点i建立一个单链表,每个单链表的第一个结点存放有关顶点的信息,把这一结点看做链表的表头,其余结点存放有关边的信息。因此,邻接表由单链表的表头形成的顶点表和单链表其余结点形成的边表两部分组成。顶点表存放顶点信息和指向第一条边结点指针;边表结点存放与当前顶点相邻接顶点的序号和指向下一个边结点的指针。
代码表达:

//1.顶点表
typedef struct VNode{
    int data;//顶点信息
    ArcNode *firstarc;//指向第一条边的指针
}VNode;
//2.边表
typedef struct ArcNode{
    int adjvex;//
    ArcNode *nextarc;//指向下一条边的指针
}ArcNode;
//3.邻接表
typedef struct{
    VNode adjlist[maxSize];//保存顶点表就可以获取所有边
    int n,e;//顶点数和边数
}AGraph;

2.图的遍历(邻接表)
2.1 深度优先搜索遍历(DFS depth-first)
算法运行的流程图如下:
image.png
如上图,从节点0开始进行深度优先遍历访问节点顺序:0,1,4,5。
先走完所有firstarc,遇到空则返回走nextarc的firstarc,直到走完。
代码:

int visit[maxSize];//初始全为0,全部未访问
void DFS(AGraph *G,int v){//v是起点编号
    ArcNode *p;
    visit[v] = 1; //标记已访问
    Visit(v); //访问结点,可以是输出结点信息
    p=G->adjlist[v].firstarc;//指向顶点v的第一条边
    while(p!=NULL){
        if(visit[p->adjvex]==0)//若顶点未访问,则递归访问它
            DFS(G,p->adjvex);
        p=p->nextarc;//p指向顶点v的下一条边的终点
            
    }
}

图的深度优先搜索遍历类似于二叉树的先序遍历,基本思想是:首先访问触发点v,并将其标记为已访问过;然后选取与v邻接的未被访问的任意一个顶点w,并访问它;再选取与w邻接的未被访问的任一顶点并访问,以此重复进行。当一个顶点所有的邻接顶点都被访问过时,则依次退回到最近被访问过的顶点,若该顶点还有其他邻接顶点未被访问,则从这些未被访问的顶点中取一个并重复上述访问过程,直至图中所有顶点都被访问过为止。
2.2 广度优先搜索遍历(BFS breath-first)
算法运行的流程图如下:
image.png
如上图,从节点0开始进行广度优先遍历访问节点顺序:0,1,4,5。
先入队结点0,访问结点0,然后出队结点0,依次入队结点0的firstarc和nextarc对应顶点,访问firstarc和nextarc对应顶点;出队、循环直到队列为空。
图的广度优先搜索遍历类似于树的层次遍历。基本思想:首先访问起始顶点v,然后选取与v邻接的全部顶点w1,...,wn进行访问,再依次访问与w1,...,wn邻接的全部顶点(已经访问过的除外),以此类推,直到所有顶点都被访问过为止。

void BFS(AGraph *G, int v, int visit[maxSize]){//visit[]初始化全为0
    ArcNode *p;
    int que[maxSize],front=0,rear=0;//队列简单写法
    int j;
    visit[v] = 1; //标记已访问
    Visit(v); //访问结点,可以是输出结点信息
    rear=(rear+1)%maxSize;
    que[rear]=v;//当前节点v入队
    while(front!=rear){//队列非空
        front=(front+1)%maxSize;
        j=que[front];//队头出队
        p=G->adjlist[j].firstarc;//p指向出队顶点j的第一条边
        while(p!=null){
            if(visit[p->adjvex]==0){//当前邻接顶点未被访问,则进队
                visit[p->adjvex] = 1; 
                Visit(p->adjvex);
                rear=(rear+1)%maxSize;
                que[rear]=p->adjvex;//当前节点v入队
            }
            p=p->nextarc;//p指向j的下一条边
        }
    }
}

广度优先搜索遍历图需要使用到队列,算法的执行过程可简单概括如下:
1)任取图中一个顶点访问,入队,并将这个顶点标记为已访问。
2)当队列不空时循环执行:出队,依次检查出队顶点的所有邻接顶点,访问没有被访问过的邻接顶点并将其入队。
3)当队列为空时跳出循环,广度优先搜索即完成。

以上算法是针对连通图,对非连通图无法访问全部结点。只需要对图的所有顶点遍历执行上述搜索即可:

void dfs(AGraph *g){
    for(int i= 0;in;++i)
        if(visit[i]==0)
            DFS(g,i);//深度遍历
            BFS(g,i,visit);//或广度遍历
}

你可能感兴趣的:(图的深度优先搜索(DFS)和广度优先搜索(BFS)详解)