<数据结构学习>图的广度优先遍历(邻接表建图)

目录

题目描述

问题分析

问题解决


题目描述

本实验实现邻接表表示下无向图的广度优先遍历。

程序的输入是图的顶点序列和边序列(顶点序列以*为结束标志,边序列以-1,-1为结束标志)。程序的输出为图的邻接表和广度优先遍历序列。例如:

程序输入为:
a
b
c
d
e
f
*
0,1
0,4
1,4
1,5
2,3
2,5
3,5
-1,-1

程序的输出为:
the ALGraph is
a 4 1
b 5 4 0
c 5 3
d 5 2
e 1 0
f 3 2 1
the Breadth-First-Seacrh list:aebfdc

问题分析

解决这个问题需要两步。

首先需要完成邻接表建图。然后用建好的图进行广度优先遍历。

都是比较基础的操作,下面我们直接看着代码解释。

问题解决

首先,我们需要用邻接表建图。邻接表包括顶点数组和每个顶点所连的一串边。图解如下

其中,每个顶点的信息包括两部分:所存数据和所连的第一条边指针。

每条边的信息也包括两部分:所连的顶点的下标和指向下一条边的指针。

由此,我们可以定义两个结构体:

struct edge //边的结构体
{
    int ver; //所连顶点下标
    struct edge* next;  //下一条边
};
struct vertex //顶点结构体
{
    char data;  //顶点数据
    struct edge* firstedge;  //所连第一条边
};

 然后,我们就可以定义整个图的结构体了

struct Graph  //图的结构体
{
    struct vertex adjlist[MAXNUM];  //顶点组成的数组,MAXNUM为最多顶点数
    int vernum=0,edgenum=0;  //顶点数,边数
};

接下来,我们就可以开始完成那两个任务了。

首先是建图:

void CreateGraph(struct Graph &G)
{
    struct edge *e = nullptr;
    int i,j;
    char v;
    cin>>v;
    while(v!='*') //v='*'代表顶点输入完毕
    {
        G.adjlist[G.vernum].data=v; //给顶点赋值
        G.adjlist[G.vernum].firstedge=nullptr;  // 初始化顶点所连第一条边
        cin>>v;
        G.vernum++;
    }
    scanf("%d,%d",&i,&j);
    while(i!=-1&&j!=-1) //顶点下标组都为-1代表输入完毕
    {
        e=new edge;  //无向图要建立两次边,这是第一次
        e->ver=j;
        e->next=G.adjlist[i].firstedge; 
        G.adjlist[i].firstedge=e;
        //每条边都插在第一条边的位置,所以每个顶点之后所连的边是倒序的

        e=new edge;  //无向图要建立两次边,这是第二次
        e->ver=i;
        e->next=G.adjlist[j].firstedge;
        G.adjlist[j].firstedge=e;

        scanf("%d,%d",&i,&j);
        G.edgenum++;  //边数++
    }
}

然后是BFS:

void BFS(Graph &G,int vt)
{
    queue<int> Q; //建队列
    edge *e;
    Q.push(vt); //起始顶点入队
    visited[vt]=1; //访问状态设置为已访问
    while(Q.empty()==0)  //队列不为空时
    {
        vt=Q.front(); //队首元素出队
        cout<<G.adjlist[vt].data; //输出其数据
        Q.pop();
        e=G.adjlist[vt].firstedge;
        while (e!=nullptr)  //顺着它所连接的边遍历
        {
            if(visited[e->ver]==0) //若其所连边有没访问过的,入队,并更改访问状态
            {
                visited[e->ver]=1;
                Q.push(e->ver);
            }
            e=e->next;
        }
    }
 
    for(int i=0;i<G.vernum;i++)  //一定要注意!!检查是否还有没访问过的点!!递归BFS
    {
        if(visited[i]==0)
        {
            BFS(G,i);
        }
    }
}

BFS时要注意几点,首先是要记得设置访问状态。(这个访问数组在main函数里记得初始化,一会也会强调)

还有就是要注意有非联通子图的情况!一开始用队列做我没考虑到这点,最后还是用递归拯救了一下。

如果一直WA的话可以尝试一下包含非连通子图和孤立点的测试用例。

最后是main函数:

int main()
{
    Graph G;
    CreateGraph(G); //建图
    cout << "the ALGraph is\n";  
    for (int i = 0; i <G.vernum; i++)  //输出图
    {  
        if(G.adjlist[i].firstedge!=nullptr)//输出注意格式!!很坑!!
        {
            cout << G.adjlist[i].data << " ";
        }
        else cout << G.adjlist[i].data; 
        edge *e = G.adjlist[i].firstedge;  
        while (e != nullptr) 
        {  if(e->next!=nullptr)//输出注意格式!!
            {
                cout << e->ver <<" "; 
            }
            else cout << e->ver;  
            e = e->next;  
        }  
        cout << "\n";  
    }
    for(int i=0;i<G.vernum;i++)  //初始化visited数组
    {
        visited[i]=0;
    }
    cout << "the Breadth-First-Seacrh list:";  
    BFS(G, 0); // 从顶点0开始遍历
    cout<<endl;
    return 0;
}

main函数其实没啥好说的,但是一定要注意格式!!试出来这个错的时候我感觉大为震撼哈哈哈真的很难debug。就是输出图的时候如果是孤立点,后面不要空格,直接换行。还有这条边后面如果没有边了,也直接换行,不要空格。

最后是完整代码:

#include <iostream>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std;
const int MAXNUM = 1000;
int visited[MAXNUM];
struct edge
{
    int ver;
    struct edge* next;
};

struct vertex
{
    char data;
    struct edge* firstedge;
};
struct Graph
{
    struct vertex adjlist[MAXNUM];
    int vernum=0,edgenum=0;
};
void CreateGraph(struct Graph &G)
{
    struct edge *e = nullptr;
    int i,j;
    char v;
    cin>>v;
    while(v!='*')
    {
        G.adjlist[G.vernum].data=v;
        G.adjlist[G.vernum].firstedge=nullptr;
        cin>>v;
        G.vernum++;
    }
    scanf("%d,%d",&i,&j);
    while(i!=-1&&j!=-1)
    {
        e=new edge;
        e->ver=j;
        e->next=G.adjlist[i].firstedge;
        G.adjlist[i].firstedge=e;

        e=new edge;
        e->ver=i;
        e->next=G.adjlist[j].firstedge;
        G.adjlist[j].firstedge=e;

        scanf("%d,%d",&i,&j);
        G.edgenum++;
    }
}
void BFS(Graph &G,int vt)
{
    queue<int> Q;
    edge *e;
    Q.push(vt);
    visited[vt]=1;
    while(Q.empty()==0)
    {
        vt=Q.front();
        cout<<G.adjlist[vt].data;
        Q.pop();
        e=G.adjlist[vt].firstedge;
        while (e!=nullptr)
        {
            if(visited[e->ver]==0)
            {
                visited[e->ver]=1;
                Q.push(e->ver);
            }
            e=e->next;
        }
    }
 
    for(int i=0;i<G.vernum;i++)
    {
        if(visited[i]==0)
        {
            BFS(G,i);
        }
    }
}

int main()
{
    Graph G;
    CreateGraph(G);
    cout << "the ALGraph is\n";  
    for (int i = 0; i <G.vernum; i++) 
    {  
        if(G.adjlist[i].firstedge!=nullptr)//格式
        {
            cout << G.adjlist[i].data << " ";
        }
        else cout << G.adjlist[i].data; 
        edge *e = G.adjlist[i].firstedge;  
        while (e != nullptr) 
        {  if(e->next!=nullptr)//格式
            {
                cout << e->ver <<" "; 
            }
            else cout << e->ver;  
            e = e->next;  
        }  
        cout << "\n";  
    }
    for(int i=0;i<G.vernum;i++)
    {
        visited[i]=0;
    }
    cout << "the Breadth-First-Seacrh list:";  
    BFS(G, 0); // 从顶点0开始遍历
    cout<<endl;
    return 0;
}

反思总结

对c++基础语法不太熟,做这道题的时候学到了几点:

1、c++声明结构体变量的时候不写struct也可以(当然定义的时候一定要写)

2、c++的空指针在c++11里推荐用nullptr,不推荐用NULL

3、有‘,’隔开两个输入数据的时候最简单可以用c里的scanf(“%x,%x”,&x,&x);

      也可以用cin>>i; cin.ignore(1,','); cin>>j;    //cin.ignore(1,',')的意思是最多跳过一个字符,如果是‘,’就跳过,其他不跳过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值