图的存储方法:邻接矩阵、邻接表

例如:有一个图如下所示(该图也作为程序的实例):

则上图用邻接矩阵可以表示为:

邻接表可以表示如下:

邻接矩阵可以很容易的用二维数组表示,下面主要看看怎样构成邻接表

邻接表存储方法是一种顺序存储与链式存储相结合的存储方法。在这种方法中,只考虑非零元素,所以在图中的顶点很多而边很少时,可以节省存储空间

        邻接表存储结构由两部分组成:对于每个顶点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):

        图的广度优先搜索遍历类似于树的按层次遍历。在假设初始状态是图中所有顶点都未被访问的条件下,这种方法从图中某一顶点vi出发,先访问vi,然后访问vi的邻接点vj。在所有的vj都被访问之后,再访问vj的邻接点vk,依次类推,直到图中所有和初始出发点vi有路径相通的顶点都被访问为止。若图是非连通的,则选择一个未曾被访问的顶点作为起始点,重复以上过程,直到图中所有顶点都被访问为止。 

        在这种方法的遍历过程中,先被访问的顶点,其邻接点也先被访问,具有先进先出的特性,所以可以使用一个队列来保存已访问过的顶点,以确定对访问过的顶点的邻接点的访问次序。为了避免重复访问一个顶点,也使用了一个辅助数组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)的更多相关文章

  1. 图的广度优先搜索(BFS)

    把以前写过的图的广度优先搜索分享给大家(C语言版) #include<stdio.h> #include<stdlib.h> #define MAX_VERTEX_NUM 20 ...

  2. 基于visual Studio2013解决算法导论之046广度优先搜索

     题目 广度优先搜索 解决代码及点评 // 图的邻接表表示.cpp : 定义控制台应用程序的入口点. // #include <iostream> #include <stac ...

  3. 图的广度优先/层次 遍历(BFS) c++ 队列实现

    在之前的博文中,介绍了图的深度优先遍历,并分别进行了递归和非递归实现.BFS 无法递归实现,最广泛的实现是利用队列(queue).这与DFS的栈实现是极其相似的,甚至代码几乎都很少需要改动.从给定的起 ...

  4. 【算法导论】图的深度优先搜索遍历(DFS)

    关于图的存储在上一篇文章中已经讲述,在这里不在赘述.下面我们介绍图的深度优先搜索遍历(DFS). 深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj:访问vj之后,又访问vj的一个邻接点, ...

  5. Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph)

    Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree ...

  6. 数据结构之 图论---基于邻接矩阵的广度优先搜索遍历(输出bfs遍历序列)

    数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索( ...

  7. Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)

    Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...

  8. C语言数据结构与算法之深度、广度优先搜索

    一.深度优先搜索(Depth-First-Search 简称:DFS) 1.1 遍历过程: (1)从图中某个顶点v出发,访问v. (2)找出刚才第一个被顶点访问的邻接点.访问该顶点.以这个顶点为新的顶 ...

  9. Z1. 广度优先搜索(BFS)解题思路

    /** BFS 解题思路 特点:从某些特定的节点开始,感染相邻的节点; 被感染的节点,再感染其相邻的节点,以此类推. 题目常见于数据结构包括 二维数组.树.图 **/ /** 1). 二维数组特定节点 ...

随机推荐

  1. 设计模式一日一练:中介者模式(Mediator)

    Mediator模式,用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 比较典型的例子是联合国.QQ群等.比如,如果中国有 ...

  2. 移动开发之【微信小程序】的原理与权限问题以及相关的简易教程

    这几天圈子里到处都在传播着这样一个东西,微信公众平台提供了一种新的开放能力,开发者可以快速开发一个小程序,取名曰:微信公众平台-小程序 据说取代移动开发安卓和苹果,那这个东东究竟是干吗用的?但很多人觉 ...

  3. 计算机网络之动态主机配置协议DHCP

    为了将软件协议做成通用的和便于移植,协议软件的编写者不会把所有细节都固定在源代码中,而是把协议软件参数化,这就使得在很多台计算机上使用同一个经过编译的二进制代码成为可能. 一台计算机和另一台计算机的区 ...

  4. Ubuntu安装telent服务器时出现:apt-get:Package has no installation

    当我在终端敲下这条命令的时候,系统就提示telnetd:apt-get:Package has no installation sudo apt-get install xinetd telnetd ...

  5. 查看4k对齐,激活.net framework 3.5

    查看是否4k对齐 Win+R,打开运行窗口,在窗口中输入“msinfo32",组件”--“存储”--“磁盘”.然后可以在右边栏看到“分区起始偏移”,我们图例中有2个数值,分别是:32256字 ...

  6. 剑指offer-面试题7:俩个栈实现队列(java)

    详细分析请参照C语言版,这里仅仅给出实现代码,注释很详细,不得不说java各种api用起来真是爽飞了 1 package com.xsf.SordForOffer; 2 3 import java.u ...

  7. EBS开发常用编译命令

    一.编译FORM 1.将脚本写成shell脚本 cd $AU_TOP/forms/ZHS export FORMS_PATH=.:$FORMS_PATH:$AU_TOP/forms/ZHS frmcm ...

  8. Android View框架总结(六)View布局流程之Draw过程

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52236145 View的Draw时序图 ViewRootImpl.p ...

  9. Android简易实战教程--第十七话《自定义彩色环形进度条》

    转载请注明出处:http://blog.csdn.net/qq_32059827/article/details/52203533   点击打开链接 在Android初级教程里面,介绍了shape用法 ...

  10. Cocos2D结合CoreGraphics实现RPG人物中空黑洞吸入效果

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 之前的博文中我们实现了RPG人物的复古效果. 现在我们再完点h ...