hnust 1966: 广度优先搜索

hnust 1966: 广度优先搜索

题目描述
输入一个图,用邻接表存储(实际上也可以选择邻接矩阵),并实现BFS操作。

拷贝前面已经实现的代码,主函数必须如下,完成剩下的部分。

int main()
{
Graph g;
CreateUDG(g);
BFS(g, 0);//从0号顶点开始遍历
DestroyUDG(g);
return 0;
}//main

输入
输入的第一行是两个整数,分别是图的总顶点数n和总边数e

第二行是n个空格分开的字符串,是顶点的名字,依次对应编号0~n-1。

随后有e行,每行两个空格分开的顶点名字,表示一条边的两个顶点。

具体见样例。

输出

输出图的BFS序列,遍历次序按教材,每个顶点后面跟一个空格。

具体见样例。

样例输入 Copy
8 9
v1 v2 v3 v4 v5 v6 v7 v8
v1 v2
v1 v3
v2 v4
v2 v5
v3 v6
v3 v7
v4 v8
v5 v8
v6 v7
样例输出 Copy
v1 v2 v3 v4 v5 v6 v7 v8
提示
样例对应教材6.5的图G4

解题过程

注:本题按照书上算法解析完成,广度优先搜索的细化代码及函数分解请看合集《2024.6 hnust 23级 数据结构 课程设计》“推箱子游戏-广度优先搜索版本”
图的广度优先搜索(BFS)需要借助到队列来遍历:
①首先,选取图中某一顶点vi作为出发点,访问后将其入队并标记为已访问(使用队列用于避免重复访问,存放已经访问过的各邻接顶点);
②依次访问与vi邻接的顶点,即当队列不为空时检查出队顶点的所有邻接顶点,访问未被访问的邻接顶点并将其入队,重复该过程;【可概括为由起始顶点开始,按照广度优先的顺序逐层遍历与当前顶点相邻的顶点将其访问】
③当队列为空时跳出循环,即所有已被访问的顶点的邻接顶点均被访问到,则此时遍历完成。

(二)BFS的空间复杂度和时间复杂度
对于一个图G=(V,E),由顶点集V和边集E组成。
1、BFS算法的空间复杂度
通过BFS遍历的空间复杂度为O(|V|)。

2、BFS算法的时间复杂度
时间复杂度取决于图的存储结构,若通过邻接矩阵表示图,则查找顶点的邻接顶点所需时间为O(|V|),总时间复杂度为O(|V2|)(邻接矩阵为方阵n×n),这和DFS算法的时间复杂度是一样的;若通过邻接表表示图,则每个顶点都入队一次,即所需时间为O(|V|),搜索顶点的邻接顶点所需时间为O(|E|),其时间复杂度为O(|V|+|E|)。

这段C++代码实现了一个基于广度优先搜索(BFS)的无向图的拓扑排序算法。以下是对代码的详细解析:

  1. 头文件和命名空间

    • 包含 <bits/stdc++.h> 头文件,它包含了标准库中的大部分内容。
    • 使用 using namespace std; 来避免在标准库类型和函数前加 std::
  2. 读取图的参数

    • 读取两个整数 ne,分别代表图中顶点的数量和边的数量。
  3. 存储顶点信息

    • 创建一个字符串数组 nodes 来存储顶点的名称。
  4. 输入顶点名称

    • 使用循环读取 n 个顶点的名称。
  5. 建立顶点位置映射

    • 使用 map(映射)来存储每个顶点名称与其在数组中的索引位置。
  6. 创建无向图

    • 使用 map 来创建一个邻接表 G,表示无向图中的边。
  7. 对邻接表进行排序

    • 对每个顶点的邻接表进行排序,以便在后续的搜索中按顺序访问。
  8. 初始化访问标记

    • 使用 map 初始化所有顶点的访问状态为未访问。
  9. 使用队列实现BFS

    • 使用 queue 来实现BFS,首先将起始顶点压入队列,并标记为已访问。
  10. BFS搜索

    • 当队列不为空时,执行循环:
      • 弹出队列前端元素作为当前访问的顶点,并输出。
      • 遍历当前顶点的所有邻接顶点。
      • 如果邻接顶点未被访问,将其标记为已访问,并压入队列。
  11. 输出访问顺序

    • 在访问过程中,每访问一个顶点,就输出其名称。
  12. 程序结束

    • 当队列为空时,表示所有顶点都被访问完毕,程序结束。

代码逻辑分析

  • 这段代码通过BFS实现了拓扑排序,适用于无向图。
  • 使用队列来存储待访问的顶点,使用映射来记录顶点的访问状态和位置信息。

潜在问题

  • 代码中注释掉的部分提供了另一种实现拓扑排序的方法,但在当前实现中未使用。

改进建议

  • 考虑使用 std::vector 替代数组,以提高代码的安全性和灵活性。
  • 考虑使用 std::unordered_map 替代 std::map,以提高查找效率。
  • 如果需要处理更大的图或更复杂的图结构,可以考虑优化内存使用和搜索算法。
  • 代码中的排序部分可能不是必要的,因为拓扑排序的目的是线性化图,而不是排序顶点。如果不需要对顶点进行排序,可以省略排序逻辑。

AC代码

#include<bits/stdc++.h>
using namespace std;
  
int main(int argc, char const *argv[])
{
    map < string , std::vector<string> >  G;
    int n ,e;
    cin>> n >> e;  //输入:8 9
  
    string nodes[n];
    for (int i = 0; i < n; ++i)
    {
        cin >> nodes[i];  //输入:v1 v2 v3 v4 v5 v6 v7 v8
    }
  
    map <string , int > location;
    for (int i = 0; i < n; ++i)   //排序数组
    {
        location[nodes[i]] = i;
    }
  
    for (int i = 0; i < e; ++i)  //创建无向图
    {
        string l,r;
        cin >> l >> r;
        G[l].push_back(r);
        G[r].push_back(l);
    }
  
    for (int i = 0; i < n; ++i)  //对无向图的排序
    {
        int j = G[nodes[i]].size();
        for (int p = 0; p < j; ++p)
        {
            for (int q = 0; q < j; ++q)
            {
                if(location[G[nodes[i]][q]] > location[G[nodes[i]][p]])
                {
                    string temp;
                    temp = G[nodes[i]][q];
                    G[nodes[i]][q] = G[nodes[i]][p];
                    G[nodes[i]][p] = temp;
                }
            }
        }
    }
  
    map < string , bool > vis;  //是否被访问
    queue < string > q;
    q.push(nodes[0]);
    vis[nodes[0]] = true;
    // string rev[n];
    // int r = 0;
  
    while(q.size())
    {
        string curr;
        curr = q.front();  q.pop();
        // rev[r++] = curr;
        cout << curr << " ";
  
        for(auto next : G[curr])
        {
            if(!vis[next])
            {
                vis[next] = true;
                q.push(next);
            }
        }
    }
    return 0;
}
 
  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值