首页 > 其他分享 >【头歌实训:邻接表存储图的广度优先遍历】

【头歌实训:邻接表存储图的广度优先遍历】

时间:2024-10-22 19:47:10浏览次数:3  
标签:遍历 BFS 头歌 实训 邻接 visited 顶点 rear

头歌实训:邻接表存储图的广度优先遍历

文章目录


任务描述
相关知识
邻接表存储图
图的遍历
广度优先遍历过程:
算法设计思路:
编程要求
测试说明
输入格式:
输出格式:
样例输入:
样例输出:
源代码:

任务描述

本关任务:请你实现 bfs.cpp 里的void BFS( AdjGraph* G, VertexType V)函数。 约定:顶点编号小的先输出。

相关知识

为了完成本关任务,你需要掌握:1.如何使用邻接表存储图,2.如何遍历图。

邻接表存储图

一个包含5个顶点的无向图如图所示。

在这里插入图片描述

图1 一个包含5个顶点的无向图

图 2 给出了对图 1 的无向图的邻接表存储结构图:每个顶点的名称由一个整数描述,对图中每个顶点i建立一个单链表, 将顶点i的所有邻接点链起来。

在这里插入图片描述

每个单链表上添加一个表头结点(表示顶点信息)。并将所有表头结点构成一个数组, 下标为i的元素表示顶点i的表头结点。

在这里插入图片描述

图2 图1的无向图的邻接表

图的邻接表存储方法是一种顺序分配与链式分配相结合的存储方法,如图3所示。

在这里插入图片描述

图3 图的邻接表表示形式

一个带权的有向图(网)的邻接表存储形式如图4所示。

在这里插入图片描述

图4 带权有向图的邻接表存储结构图

图的邻接表存储类型定义如下:

typedef struct ANode
{ int adjvex; //该边的终点编号
struct ANode *nextarc; //指向下一条边的指针
int weight; //该边的权值等信息
} ArcNode;
typedef struct Vnode
{ Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边
} VNode;
typedef struct
{ VNode adjlist[MAXV] ; //邻接表
int n, e; //图中顶点数n和边数e
} AdjGraph;
一个邻接表通常用指针引用:

在这里插入图片描述

给定指向该结构的指针G,就可以对图进行操作。

图的遍历

所谓图的遍历(graph traversal),也称为搜索(search),就是从图中某个顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次。遍历可以采取两种方法进行:深度优先搜索(DFS,depth first search)和广度优先搜索(BFS,breadth first search)。

广度优先遍历过程:

广度优先搜索(BFS,Breadth First Search)是一个分层的搜索过程,没有回退过程,是非递归的。其访问过程如下:
(1)访问初始点v, 接着访问v的所有未被访问过的邻接点v1, v2, …, vt。
(2)按照v1, v2, …, vt的次序, 访问每一个顶点的所有未被访问过的邻接点。   
(3)依次类推, 直到图中所有和初始点v有路径相通的顶点都被访问过为止。

算法设计思路:

广度优先搜索遍历体现先进先出的特点, 用队列实现。

在这里插入图片描述

如何确定一个顶点是否访问过? 设置一个visited[] 全局数组, visited[i]=0表示顶点i没有访问; visited[i]=1表示顶点i已经访问过。

如果用邻接表存储图,则 BFS 算法实现的伪代码如下:

BFS(图 G, 顶点 i ) //从顶点 i 进行广度优先搜索
{
visited[ i ] = 1; //将顶点 i 的访问标志置为 1
将顶点 i 入队列;
while( 队列不为空 )
{
取出队列头的顶点,设为 k
p = 顶点 k 的边链表表头指针
while( p 不为空 )
{
//设指针 p 所指向的边结点所表示的边的另一个顶点为顶点 j
if( 顶点 j 未访问过 )
{
将顶点 j 的访问标志置为 1
将顶点 j 入队列
}
p = p->nextarc; //p 移向下一个边结点
} //end of while
} //end of while
} //end of BFS
对图1运行该算法的结果(从顶点2出发): 2 1 3 4 0。

编程要求

请你在右侧的代码窗口中实现bfs.cpp里的void BFS( AdjGraph* G, VertexType V)函数。 注意遵守约定:顶点编号小的先输出。

注:本关提供C++ STL队列容器queue,你可以直接使用。

测试说明

本关的测试过程如下:
1.平台编译 step2/bfs.cpp 并生成可执行文件;
2.平台运行该可执行文件,并以标准输入方式提供测试输入;
3.平台获取该可执行文件的输出,然后将其与预期输出对比,如果一致则测试通过;否则测试失败。
输入输出格式说明:

输入格式:

输入V,开始遍历的起始顶点编号。

输出格式:

输出对图进行广度优先遍历的顶点序列,每个顶点编号前面有一个空格。

以下是平台对 step2/bfs.cpp 的测试样例:

样例输入:

在这里插入图片描述

测试输入:2

样例输出:

预期输出:BFS from 2: 2 0 3 5 4 1 6

开始你的任务吧,祝你成功!

源代码:

#include "bfs.h"

/*
 * 从顶点V出发进行广度优先搜索。
 * 函数BFS应从编号为V的顶点出发广度优先遍历图,
 * 遍历访问邻接点时,要求按序号递增的顺序。
 * 题目保证V是图中的合法顶点。
 */
void BFS( AdjGraph* G, VertexType V)
{
    /*******************begin*******************/
    int Q[11], head, rear, *visited = (int *)malloc(sizeof(int) * G->n);
    //利用循环队列存储未遍历完的结点,队头队尾指针head和rear,遍历数组visited初值为0
    for(int i = 0; i < G->n; i++) visited[i] = 0;
    head = rear = 0;//初始化队头和队尾指针
    Q[rear] = V;    //第一个访问的元素入栈
    rear = (rear + 1) % 11; //队尾指针后移
    visited[V] = 1; //遍历数组置为1
    printf(" %d", V);   //打印第一个元素
    while(head != rear) //但队列非空时遍历
    {
        ArcNode *p = G->adjlist[Q[head]].firstarc;  //临时指针p存放以及遍历结点的相邻结点
        while(p)    //当p非空时遍历它
        {
            if(visited[p->adjvex] == 0) //当遍历数组为0说明未被遍历过即可直接遍历同时入队以及使遍历数组置为1
            {
                printf(" %d", p->adjvex);
                Q[rear] = p->adjvex;
                rear = (rear + 1) % 11;
                visited[p->adjvex] = 1;
            }
            p = p->nextarc; //p向后移
        }
        head = (head + 1) % 11; //出队刚才遍历完的结点
    }
    /*******************end*******************/
}

int main()
{
    AdjGraph* G;
    VertexType V;

    G = CreateGraph();
    scanf("%d", &V);
    printf("BFS from %d:", V);
    BFS(G, V);

    return 0;
}

标签:遍历,BFS,头歌,实训,邻接,visited,顶点,rear
From: https://blog.csdn.net/guang_Lee/article/details/143166617

相关文章

  • 数组的往返(数组来回遍历)C语言版
    文章目录前言题目描述一、数组的往返是什么?二、实现1.具体代码2.完整题解代码总结以及一些疑问前言本篇文章灵感来源于第十三届蓝桥杯省赛C++B组第六题修剪灌木,我的方法是老老实实地走完这个流程得到答案题目描述爱丽丝要完成一项修剪灌木的工作。有N棵灌......
  • mysql对结果集进行遍历(mysql双重for循环如何写)
    原文链接:mysql对结果集进行遍历(mysql双重for循环如何写)–每天进步一点点0.背景有这么一个需求:对以下的类型结果集进行更新。更新的原则是type为c的currentValue的值=(type为b的currentValue)/((type为b的currentValue)+(type为a的currentValue))*100。上面这个需求......
  • springboot+vue安卓实训教学管理系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着移动互联网技术的飞速发展,智能手机已成为人们日常生活中不可或缺的一部分。在教育领域,安卓平台因其广泛的用户基础和强大的应用开发能力,成为构建实训教学管理系统的理想选择。传统的实训教学管理方式往往依赖于纸质记录或PC端软件......
  • go 反射 遍历对象属性 切片 Map
    packagemainimport"fmt"import"reflect"funcmain(){p1:=Person{Name:"test1",Age:20,Address:"1323"}p2:=Person{Name:"demo2",Age:24,Address:"adsd"}varlist[]*Pers......
  • 图论之搜索遍历
    前言一个重要的板块,倒是有很多有趣的题,从搜索开始吧MazeTacToeS暴力即可,\(3^9\times25\times25\)绰绰有余,把状态转换为三进制\(dfs\)ConnectedComponents?根据鸽巢原理,必定有一个点被割去的边\(\le\frac{m}{n}\),然后我们找到这个点,对于连接他的边均在同一个联......
  • 二叉树的中序遍历
    给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。示例1:输入:root=[1,null,2,3]输出:[1,3,2]示例2:输入:root=[]输出:[]示例3:输入:root=[1]输出:[1]提示:树中节点数目在范围 [0,100] 内-100<=Node.val<=100进阶: 递归算法很简单,你可以通......
  • 岛屿数量(深度优先遍历)
    给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。示例1:输入:grid=[["1","1","1","1","0"],["1","1",&qu......
  • python中怎么遍历字典
    遍历字典:keys() 、values()、items()1、xxx.keys():返回字典的所有的key,返回一个序列,序列中保存有字典的所有的键。效果图:代码:# keys() 该方法会返回字典的所有的key#   该方法会返回一个序列,序列中保存有字典的所有的键d = {'name':'孙悟空','age':1......
  • C语言手撕实战代码_线索二叉树_先序中序线索二叉树_树的先根遍历_后根遍历_树的度_孩
    文章目录1.设计算法构造一棵先序线索二叉树2.先序线索二叉树的先序遍历算法3.设计算法构造一棵中序线索二叉树4.遍历中序线索二叉树5.树的先根遍历和后根遍历6.树T的叶子结点个数7.计算一棵以孩子兄弟表示的树T的度,该算法的时间复杂度为O(n)8.计算树孩子兄弟链表表示的T......
  • Java遍历Map集合的方法
    Java中遍历  Map 集合的常用方式主要有以下几种:1.使用 keySet()方法遍历 遍历Map的key集合,然后通过key获取value。Map<String,Integer>map=newHashMap<>();map.put("one",1);map.put("two",2);map.put("three",3);for(Stringkey......