【算法导论】图的广度优先搜索遍历(BFS)
图的存储方法:邻接矩阵、邻接表
例如:有一个图如下所示(该图也作为程序的实例):
则上图用邻接矩阵可以表示为:
用邻接表可以表示如下:
邻接矩阵可以很容易的用二维数组表示,下面主要看看怎样构成邻接表:
邻接表存储方法是一种顺序存储与链式存储相结合的存储方法。在这种方法中,只考虑非零元素,所以在图中的顶点很多而边很少时,可以节省存储空间。
邻接表存储结构由两部分组成:对于每个顶点vi, 使用一个具有两个域的结构体数组来存储,这个数组称为顶点表。其中一个域称为顶点域(vertex),用来存放顶点本身的数据信息;而另一个域称为指针域(link),用来存放依附于该顶点的边所组成的单链表的表头结点的存储位置。邻接于vi的顶点vj链接成的单链表称为vi的邻接链表。邻接链表中的每个结点由两个域构成:一是邻接点域(adjvex),用来存放与vi相邻接的顶点vj的序号j (可以是顶点vj在顶点表中所占数组单元的下标);
其二是链域(next),用来将邻接链表中的结点链接在一起。具体的程序实现如下:
void CreateAdjTable(vexnode ga[N],int e)//创建邻接表
{
int i,j,k;
edgenode *s;
printf("\n输入顶点的内容:");
for(i=0;i<N;i++)
{
ga[i].vertex=getchar();//读入顶点的内容
ga[i].link=NULL;//初始化
}
printf("\n");
for(k=0;k<e;k++)
{
printf("输入边的两个顶点的序号:");
scanf("%d%d",&i,&j);//读入边的两个顶点的序号
s=(edgenode *)malloc(sizeof(edgenode));
s->adjvex=j;
s->next=ga[i].link;
ga[i].link=s;
s=(edgenode *)malloc(sizeof(edgenode));
s->adjvex=i;
s->next=ga[j].link;
ga[j].link=s;
}
}
广度优先搜索遍历(BFS):
在这种方法的遍历过程中,先被访问的顶点,其邻接点也先被访问,具有先进先出的特性,所以可以使用一个队列来保存已访问过的顶点,以确定对访问过的顶点的邻接点的访问次序。为了避免重复访问一个顶点,也使用了一个辅助数组visited[n]来标记顶点的访问情况。下面分别给出以邻接矩阵和邻接表为存储结构时的广度优先搜索遍历算法BFS_matrix和BFS_AdjTable:
具体程序实现如下:
#include<stdio.h>
#include<stdlib.h>
#define N 5
//邻接矩阵存储法
typedef struct
{
char vexs[N];//顶点数组
int arcs[N][N];
}graph;
//邻接表存储法
typedef struct Node
{
int adjvex;
struct Node *next;
}edgenode;
typedef struct
{
char vertex;
edgenode *link;
}vexnode;
//队列操作
typedef struct node
{
int data;
struct node *next;
}linklist;
typedef struct
{
linklist *front,*rear;
}linkqueue;
void SetNull(linkqueue *q)//队列置空
{
q->front=(linklist *)malloc(sizeof(linklist));
q->front->next=NULL;
q->rear=q->front;
}
int Empty(linkqueue *q)
{
if(q->front==q->rear)
return 1;
else
return 0;
}
int Front(linkqueue *q)//取队头元素
{
if(Empty(q))
{
printf("queue is empty!");
return -1;
}
else
return q->front->next->data;
}
void ENqueue(linkqueue *q,int x)//入队
{
linklist * newnode=(linklist *)malloc(sizeof(linklist));
q->rear->next=newnode;
q->rear=newnode;
q->rear->data=x;
q->rear->next=NULL;
}
int DEqueue(linkqueue *q)//出队
{
int temp;
linklist *s;
if(Empty(q))
{
printf("queue is empty!");
return -1;
}
else
{
s=q->front->next;
if(s->next==NULL)
{
q->front->next=NULL;
q->rear=q->front;
}
else
q->front->next=s->next;
temp=s->data;
return temp;
}
}
void BFS_matrix(graph g,int k,int visited[N])//图按照邻接矩阵存储时的广度优先遍历
{
int i=0;
linkqueue q;
SetNull(&q);
printf("%c\n",g.vexs[k]);
visited[k]=1;
ENqueue(&q,k);
while(!Empty(&q))
{
i=DEqueue(&q);
for(int j=0;j<N;j++)
{
if(g.arcs[i][j]==1&&visited[j]!=1)
{
printf("%c\n",g.vexs[j]);
visited[j]=1;
ENqueue(&q,j);
}
}
}
}
void CreateAdjTable(vexnode ga[N],int e)//创建邻接表
{
int i,j,k;
edgenode *s;
printf("\n输入顶点的内容:");
for(i=0;i<N;i++)
{
ga[i].vertex=getchar();//读入顶点的内容
ga[i].link=NULL;//初始化
}
printf("\n");
for(k=0;k<e;k++)
{
printf("输入边的两个顶点的序号:");
scanf("%d%d",&i,&j);//读入边的两个顶点的序号
s=(edgenode *)malloc(sizeof(edgenode));
s->adjvex=j;
s->next=ga[i].link;
ga[i].link=s;
s=(edgenode *)malloc(sizeof(edgenode));
s->adjvex=i;
s->next=ga[j].link;
ga[j].link=s;
}
}
void BFS_AdjTable(vexnode ga[],int k,int visited[N])//图按照邻接表存储时的广度优先遍历
{
int i=0;
edgenode *p;
linkqueue q;
SetNull(&q);
printf("%c\n",ga[k].vertex);
visited[k]=1;//标记是否被访问过
ENqueue(&q,k);//入队
while(!Empty(&q))
{
i=DEqueue(&q);
p=ga[i].link;
while(p!=NULL)
{
if(visited[p->adjvex]!=1)
{
printf("%c\n",ga[p->adjvex].vertex);
visited[p->adjvex]=1;
ENqueue(&q,p->adjvex);
}
p=p->next;
}
}
}
void main()
{
graph g;
vexnode ga[N];
int visited[5]={0};
int visited1[5]={0};
g.vexs[0]='A';
g.vexs[1]='B';
g.vexs[2]='C';
g.vexs[3]='D';
g.vexs[4]='E';
int a[5][5]={{0,1,0,1,1},{ 1,0,1,0,1},{ 0,1,0,0,0},{ 1,0,0,0,0},{ 1,1,0,0,0}};
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
g.arcs[i][j]=a[i][j];
printf("图按照邻接矩阵存储时的广度优先遍历:\n");
BFS_matrix(g,0,visited);
CreateAdjTable(ga,5);
printf("图按照邻接表存储时的广度优先遍历:\n");
BFS_AdjTable(ga,0,visited1);
}
其结果如下图:
从上面可以看出,两种方式的结果不同,但都是正确的,因为这与邻接点访问的顺序有关。
注:如果程序出错,可能是使用的开发平台版本不同,请点击如下链接: 解释说明
原文:http://blog.csdn.net/tengweitw/article/details/17228937
作者:nineheadedbird
【算法导论】图的广度优先搜索遍历(BFS)的更多相关文章
- 图的广度优先搜索(BFS)
把以前写过的图的广度优先搜索分享给大家(C语言版) #include<stdio.h> #include<stdlib.h> #define MAX_VERTEX_NUM 20 ...
- 基于visual Studio2013解决算法导论之046广度优先搜索
题目 广度优先搜索 解决代码及点评 // 图的邻接表表示.cpp : 定义控制台应用程序的入口点. // #include <iostream> #include <stac ...
- 图的广度优先/层次 遍历(BFS) c++ 队列实现
在之前的博文中,介绍了图的深度优先遍历,并分别进行了递归和非递归实现.BFS 无法递归实现,最广泛的实现是利用队列(queue).这与DFS的栈实现是极其相似的,甚至代码几乎都很少需要改动.从给定的起 ...
- 【算法导论】图的深度优先搜索遍历(DFS)
关于图的存储在上一篇文章中已经讲述,在这里不在赘述.下面我们介绍图的深度优先搜索遍历(DFS). 深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj:访问vj之后,又访问vj的一个邻接点, ...
- Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph)
Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree ...
- 数据结构之 图论---基于邻接矩阵的广度优先搜索遍历(输出bfs遍历序列)
数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索( ...
- Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)
Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...
- C语言数据结构与算法之深度、广度优先搜索
一.深度优先搜索(Depth-First-Search 简称:DFS) 1.1 遍历过程: (1)从图中某个顶点v出发,访问v. (2)找出刚才第一个被顶点访问的邻接点.访问该顶点.以这个顶点为新的顶 ...
- Z1. 广度优先搜索(BFS)解题思路
/** BFS 解题思路 特点:从某些特定的节点开始,感染相邻的节点; 被感染的节点,再感染其相邻的节点,以此类推. 题目常见于数据结构包括 二维数组.树.图 **/ /** 1). 二维数组特定节点 ...
随机推荐
- CF | Alyona and Numbers
After finishing eating her bun, Alyona came up with two integers n and m. She decided to write down ...
- Gradle 1.12用户指南翻译——第四十八章. Wrapper 插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- android 自定义ViewGroup之浪漫求婚
*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 1.最终效果 有木有发现还是很小清新的感觉 2.看整体效果这是一个scrollView,滑动时每个子view都有一个或多个动画效果 ...
- 剑指Offer——如何做好自我介绍
剑指Offer--如何做好自我介绍 前言 自我特点+经历梳理 各位老师好,我叫某某某,XX人.研究生三年级,就读于某某大学信息科学与工程学院软件工程专业.主要使用的开发语言是Java,熟悉基本数据 ...
- 28 自定义View画坐标和柱状图
自定义View类 RectView.java package com.qf.sxy.day29_customview.widget; import android.content.Context; i ...
- html5全解析
htm是软件开发中非常基础的知识,也是很重要的知识,在web中是很重要的知识点,在此梳理一下主要内容: 1.HTML是什么? 全称为HyperText Markup Language,超文本标记语言, ...
- Microsoft Dynamics CRM 2013/2015 选项集的多选
CRM中的选项集多选一直是客户需求中的必选项,但从CRM进国内的3.0时代开始到目前的2015版本均没有提供该功能,但既然客户要了就得想办法满足,既然CRM本身的功能上不支持,那我们只有使用非官方支持 ...
- 为什么不要在viewDidLoad方法中设置开始监听键盘通知
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 一个普遍的错误是,程序猿(媛)试图在view controll ...
- Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52349221 前言:从本篇开始,将进入Multimedia框架,包含 ...
- pig脚本不需要后缀名(python tempfile模块生成pig脚本临时文件,执行)
pig 脚本运行不需要后缀名 pig脚本名为tempfile,无后缀名 用pig -f tempfile 可直接运行 另外,pig tempfile也可以直接运行 这样就可以用python临时文件存储 ...