数据结构六——图

本文详细介绍了图的分类及其表示方法,包括有向图、无向图、有权图、无权图的邻接矩阵和邻接表。接着阐述了图的遍历算法,如广度优先搜索(BFS)和深度优先搜索(DFS),并提供了实现细节。此外,还讨论了Dijkstra算法和A*算法在最短路径问题的应用,以及拓扑排序的Kahn算法和DFS算法的实现,帮助理解图的理论与实践。
摘要由CSDN通过智能技术生成

实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法
实现图的深度优先搜索、广度优先搜索
实现 Dijkstra 算法、A* 算法
实现拓扑排序的 Kahn 算法、DFS 算法

一、图的分类与表示方法
图是由顶点和边组成的一种数据结构,一组顶点V 表示顶点的集合,一组边E 表示边的集合。
图按照不同的特征可以分为以下类别:
有向图、无向图
有权图、 无权图
连通图、非连通图

图的表示
图在程序中表示一般有两种方式

  1. 邻接矩阵:在n个顶点的图中有一个n*n大小的矩阵。在一个无权图中, 矩阵坐标中每个位置值为1代表两个点是相连的, 0表示两个点是不相连的。在一个有权图中,矩阵坐标中每个位置值代表该两点之间的权重,0 表示该两点不相连。在无向图中, 邻接矩阵关于对角线相等

  2. 邻接表:对于每个点, 存储着一个链表,用来指向所有该店直接相连的点。对于有权图来说, 链表中元素值对应着权重。

通常采用邻接表表示法,因为用这种方法表示稀疏图(图中边数远小于点个数)比较紧凑。但当遇到稠密图(|E|接近于|V|^2)或必须很快判别两个给定顶点手否存在连接边时,通常采用邻接矩阵表示法,例如求最短路径算法中,就采用邻接矩阵表示。

邻接表表示法也有潜在的不足之处,即如果要确定图中边(u,v)是否存在,只能在顶点u邻接表Adj[u]中搜索v,除此之外没有其他更快的办法。这一不足可通过图的邻接矩阵表示法来弥补,但要(在渐进意义下)以占用更多的存储空间为代价。

邻接表和邻接矩阵的关系就像是链表和数组,在时间上和空间上分别占有优势。邻接表相当于链表,邻接矩阵相当于数组,其比较关系见前面的文字数据结构二 https://mp.csdn.net/postedit/89175155

二、图的广度优先搜索(BFS)和深度优先搜索(DFS)算法
和树的遍历类似,图的遍历也是从图中某点出发,然后按照某种方法对图中所有顶点进行访问,且仅访问一次。
但是图的遍历相对树而言要更为复杂。因为图中的任意顶点都可能与其他顶点相邻,所以在图的遍历中必须记录已被访问的顶点,避免重复访问。

根据搜索路径的不同,我们可以将遍历图的方法分为两种:广度优先搜索和深度优先搜索。
1 广度优先搜索(BFS)
广度优先搜索依赖的是队列解决问题。队列中的每一个节点需要包含记录以下内容:该节点到起点的距离dist,该节点的前驱节点past,该节点在当前路径下是否被访问过visit(0表示没有访问过,1表示当前路径下正在访问,2表示该节点周围的所有节点都已经被访问过)。
步骤如下:
初始化:
起点值初始化(past=NULL,dist=0,visit=1)
其他节点值初始化(past=NULL,dist=无穷,visit=0)
起点入队
循环1:直到队列中没有元素
从队伍中输出一个节点作为当前节点
循环2:访问与当前节点连通但是【没有被访问过】的节点(visit=0的节点)
将即将访问的节点记为正在访问的状态
将即将访问的节点的状态更新(past=当前节点,dist=即将访问的节点到当前节点的距离,visit=1)
即将访问的节点入队
将当前节点的visit记为2(因为与它连接的所有节点都被访问过)

邻接矩阵存储表示


typedef struct AMGraph
{
	char vexs[MVNum];            //顶点表
	int arcs[MVNum][MVNum];      //邻接矩阵
	int vexnum, arcnum;          //当前的顶点数和边数
}AMGraph;

/*找到顶点v的对应下标*/
int LocateVex(AMGraph &G, char v)
{
	int i;
	for (i = 0; i < G.vexnum; i++)
		if (G.vexs[i] == v)
			return i;
}

/*采用邻接矩阵表示法,创建无向图G*/
int CreateUDG_1(AMGraph &G)
{
	int i, j, k;
	char v1, v2;
	cin>> &G.vexnum>> &G.arcnum;           //输入总顶点数,总边数
	for (i = 0; i < G.vexnum; i++)
		cin>> &G.vexs[i];			//依次输入点的信息
	for (i = 0; i < G.vexnum; i++)
		for (j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = 0;			//初始化邻接矩阵边,0表示顶点i和j之间无边
	for (k = 0; k < G.arcnum; k++)
	{		
		cin>> &v1>> &v2;			//输入一条边依附的顶点
		i = LocateVex(G, v1);				//找到顶点i的下标
		j = LocateVex(G, v2);				//找到顶点j的下标
		G.arcs[i][j] = G.arcs[j][i] = 1;	        //1表示顶点i和j之间有边,无向图不区分方向
	}
	return 1;
}

/*采用邻接矩阵表示图的广度优先遍历*/
void BFS_AM(AMGraph &G, char v0)
{
	/*从v0元素开始访问图*/

	int u, i, v, w;
	v = LocateVex(G, v0);                            //找到v0对应的下标
	printf("%c ", v0);                              //打印v0
	visited[v] = 1;		                        //顶点v0已被访问
	q.push(v0);			                //将v0入队

	while (!q.empty())
	{
		u = q.front();				//将队头元素u出队,开始访问u的所有邻接点
		v = LocateVex(G, u);			//得到顶点u的对应下标
		q.pop();				//将顶点u出队
		for (i = 0; i < G.vexnum; i++)
		{
			w = G.vexs[i];
			if (G.arcs[v][i] && !visited[i])//顶点u和w间有边,且顶点w未被访问
			{
				printf("%c ", w);	//打印顶点w
				q.push(w);		//将顶点w入队
				visited[i] = 1;		//顶点w已被访问
			}
		}
	}
}

邻接表法

/*找到顶点对应的下标*/
int LocateVex(ALGraph &G, char v)
{
	int i;
	for (i = 0; i < G.vexnum; i++)
		if (v == G.vertices[i].data)
			return i;
}

/*邻接表存储表示*/
typedef struct ArcNode	        //边结点
{
	int adjvex;		//该边所指向的顶点的位置
	ArcNode *nextarc;	//指向下一条边的指针
	int info;		//和边相关的信息,如权值
}ArcNode;

typedef struct VexNode		//表头结点
{
	
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值