Bootstrap

数据结构--图的遍历 BFS

数据结构–图的遍历 BFS

树的广度优先遍历

从 1 结点进行 b f s bfs bfs的顺序:
【1】
【2】【3】【4】
【4】【6】【7】【8】

图的广度优先遍历

从 2 号点开始 b f s bfs bfs的顺序:
【2】
【1】【6】
【5】【3】【7】
【4】【8】

树 vs 图

不存在“回路”,搜索相邻的结点时,不可能搜到已经访问过的结点
树的⼴度优先遍历(层序遍历):
①若树⾮空,则根节点⼊队
②若队列⾮空,队头元素出队并访问,同时将该元素的孩⼦依次⼊队
③重复②直到队列为空

搜索相邻的顶点时,有可能搜到已经访问过的顶点

代码实现

⼴度优先遍历(Breadth-First-Search, BFS)要点:

  1. 找到与⼀个顶点相邻的所有顶点
  2. 标记哪些顶点被访问过
  3. 需要⼀个辅助队列
    •FirstNeighbor(G,x):求图G中顶点x的第⼀个邻接点,若有则返回顶点号。
    若x没有邻接点或图中不存在x,则返回-1。
    •NextNeighbor(G,x,y):假设图G中顶点y是顶点x的⼀个邻接点,返回除y之外
    顶点x的下⼀个邻接点的顶点号,若y是x的最后⼀个邻接点,则返回-1
bool visited[MAX_VERTEX_NUM];
//广度优先遍历
void BFS(Graph G, int v)
{
    //从顶点v出发,广度优先遍历图G
    visit(v);
    //访问初始顶点v
    visited[v] = TRUE;
    //对v做已访问标记
    Enqueue(Q, v);
    //顶点v入队列Q
    while(!isEmpty(Q))
    {
        DeQueue(Q, v);
        //顶点v出队列
        for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) //检测v所有邻接点
            if(!visited[w]) //w为v的尚未访问的邻接顶点visit(w);//访问顶点W
            {
                visited[w] = TRUE; //对w做已访问标记EnQueue(Q,w);   //顶点w入队列
            }//if
    }//while
}

遍历序列的可变性

同⼀个图的邻接矩阵表示⽅式唯⼀,因此⼴度优先遍历序列唯⼀ \color{red}同⼀个图的邻接矩阵表示⽅式唯⼀,因此⼴度优先遍历序列唯⼀ 个图的邻接矩阵表示式唯,因此度优先遍历序列唯

同⼀个图邻接表表示⽅式不唯⼀,因此⼴度优先遍历序列不唯⼀ \color{red}同⼀个图邻接表表示⽅式不唯⼀,因此⼴度优先遍历序列不唯⼀ 个图邻接表表示式不唯,因此度优先遍历序列不唯

算法存在的问题

如果是⾮连通图,则⽆法遍历完所有结点

bool visited[MAX_VERTEX_NUM];
//广度优先遍历
void BFS(Graph G, int v)
{
    //从顶点v出发,广度优先遍历图G
    visit(v);
    //访问初始顶点v
    visited[v] = TRUE;
    //对v做已访问标记
    Enqueue(Q, v);
    //顶点v入队列Q
    while(!isEmpty(Q))
    {
        DeQueue(Q, v);
        //顶点v出队列
        for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) //检测v所有邻接点
            if(!visited[w]) //w为v的尚未访问的邻接顶点visit(w);//访问顶点W
            {
                visited[w] = TRUE; //对w做已访问标记EnQueue(Q,w);   //顶点w入队列
            }//if
    }//while
}

BFS算法(Final版)

bool visited[MAX_VERTEX_NUM];
void BFSTraverse(Graph G)   //对图G进行广度优先遍历for(i=0;i<G.vexnum;++i)visited[i]=FALSE;InitQueue(Q);
{
    //访问标记数组初始化//初始化辅助队列Q//从0号顶点开始遍历
    for(i = 0; i < G.vexnum; ++i)if(!visited[i])BFS(G, i);
    //对每个连通分量调用一次BFS//vi未访问过,从vi开始BFS
}
//广度优先遍历
void BFS(Graph G, int v)
{
    //从顶点v出发,广度优先遍历图G
    visit(v);
    //访问初始顶点v
    visited[v] = TRUE;
    //对v做已访问标记
    Enqueue(Q, v);
    //顶点v入队列Q
    while(!isEmpty(Q))
    {
        DeQueue(Q, v);
        //顶点v出队列
        for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) //检测v所有邻接点
            if(!visited[w])    //w为v的尚未访问的邻接顶点visit(w);//访问顶点w
            {
                visited[w] = TRUE; //对w做已访问标记EnQueue(Q,w);   //顶点w入队列
            }//if
    }//while
}

复杂度分析

空间复杂度:最坏情况,辅助队列⼤⼩为 O(|V|)

邻接矩阵 \color{red}邻接矩阵 邻接矩阵存储的图:
访问 |V| 个顶点需要O(|V|)的时间
查找每个顶点的邻接点都需要O(|V|)的时间,⽽总共有|V|个顶点
时间复杂度= O ( ∣ V ∣ 2 ) \color{red}O(|V|^2) O(V2)

邻接表 \color{red}邻接表 邻接表存储的图:
访问 |V| 个顶点需要O(|V|)的时间
查找各个顶点的邻接点共需要O(|E|)的时间,
时间复杂度= O ( ∣ V ∣ + ∣ E ∣ ) \color{red}O(|V|+|E|) O(V+E)

⼴度优先生成树

广度优先生成树(Breadth-First Search Tree)是一种图算法,用于以广度优先的方式遍历和生成图的树形结构。该算法从图中的一个起始节点开始,逐层遍历图中的节点,直到遍历完所有与起始节点可达的节点。

广度优先生成树的过程如下:

  1. 选择一个起始节点作为根节点,并将其标记为已访问。
  2. 将起始节点入队列。
  3. 从队列中取出一个节点作为当前节点。
  4. 遍历当前节点的所有邻接节点:
    • 如果邻接节点未被访问过,则将其标记为已访问,并将其加入队列。
    • 将当前节点与邻接节点之间的边添加到生成树中。
  5. 重复步骤3和步骤4,直到队列为空。

广度优先生成树的特点是,它按照节点的层级顺序生成树,即先生成根节点,然后生成与根节点相邻的节点,再生成与这些节点相邻的节点,依次类推。因此,生成的树形结构具有层级感,节点之间的距离相对较近。

广度优先生成树在图算法中有广泛应用,例如最短路径算法、网络分析、社交网络分析等。它能够帮助我们理解和分析图结构,了解节点之间的关系和层级结构。

⼴度优先生成森林

广度优先生成森林(Breadth-First Search Forest)是在一个连通图中进行广度优先搜索的结果,其中可能包含多个生成树。每个生成树都是从一个起始节点开始,通过广度优先搜索遍历图中的节点而形成的树状结构。

广度优先生成森林的过程与广度优先生成树类似,只是在遍历图的过程中,如果发现还有未访问的节点,就选择其中一个未访问的节点作为新的起始节点,继续生成一棵新的生成树。这样,通过多次广度优先搜索,可以生成多棵独立的生成树,组成一个森林。

广度优先生成森林的特点是,它可以同时生成多个以不同起始节点为根的生成树,这些生成树之间可能没有直接的连接。每个生成树都是从一个起始节点开始,按照广度优先的方式遍历与其可达的节点,形成一个独立的树形结构。

广度优先生成森林在图算法中也有广泛应用,特别是在处理非连通图时。通过生成森林,我们可以获得图中所有连通分量的结构信息,并且可以对每个连通分量进行进一步的分析和处理。广度优先生成森林可以帮助我们理解和分析图的整体结构,以及不同连通分量之间的关系。

对⾮连通图的⼴度优先遍历,可得到⼴度优先⽣成森林

知识回顾与重要考点

;