数据结构知识点-图

图的存储结构

邻接矩阵(数组表示法)

用一个一维数组存储途中定点的信息,用一个二维数组(邻接矩阵)存储图中各顶点之间的邻接关系。
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n的方阵,定义为:

在这里插入图片描述
类型定义:

enum GraphType{DG, UG, DN, UN};
typedef char VertexType;
typedef struct 
{
	VertexType vexs[MAX];//顶点表
	int arcs[MAX][MAX];//邻接矩阵
	int vexnum, arcnum;//顶点数和边数
	GraphType kind;//图的类型
}MGraph;

无向图的邻接矩阵

在这里插入图片描述

在这里插入图片描述
无向图
无向图邻接矩阵的特点:主对角线为0,且一定是对称矩阵。

如何求顶点i的度?:邻接矩阵第i行/第i列的非零元素个数。

如何判断顶点i和j之间是否存在边?:测试邻接矩阵中的arcs[ i ][ j ] 是否为1.

如何求顶点i的所有邻接点?:将数组中第i行元素扫描一遍,若arcs[i][j]为1,则顶点j为顶点i的邻接点。
有向图
有向图的邻接矩阵一定不对称吗?不一定,例如有向完全图。

如何求顶点i的出度?:邻接矩阵的第i行元素之和

如何求顶点i的入度?:邻接矩阵的第i列元素之和

如何判断从顶点i到顶点j是否存在边?:测试邻接矩阵中的arcs[ i ][ j ] 是否为1.

网图的邻接矩阵可定义为
在这里插入图片描述

邻接表

所有边表的头指针和存储顶点信息的一维数组构成了顶点表。
将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表

在这里插入图片描述
在这里插入图片描述

typedef struct 
{
	VertexType data;
	EdgeList firstedge;
}VexNode;
typedef struct 
{
	int adjvex;//邻接点域,边的重点在下一个顶点表的下标
	Node *next;
}Node, *EdgeList;

网图的邻接表

在这里插入图片描述

图的遍历

图的遍历是在从图中某一顶点出发,对图中所有顶点访问一次且仅访问一次。

图的遍历要解决的关键问题

  1. 因图中可能存在回路,某些顶点可能会被重复访问,如何避免遍历因回路而陷入死循环?:附设访问标志数组visited[n]
  2. 在图中,一个顶点可以和其他多个顶点相连,当这样的顶点访问过后,如何选取下一个要访问的顶点?:深度优先遍历和广度优先遍历

深度优先遍历 DFS(MGraph G, int v)

基本思想:

  1. 访问顶点v
  2. 从v的未被访问的邻接点中选取一个顶点i,从i出发进行深度优先遍历
  3. 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
//连通图的深度优先遍历递归算法
bool visited[MAX] = {false};
void DFS(MGraph G, int v)
{
	cout<<G.vexs[v];
	visited[v] = true;
	for(int i = 0; i < G.vexnum; i++)
	{
		if(G.arcs[v][i]!=0 && !visited[i])
			DFS(G, i);
	}
}

广度优先遍历

基本思想:

  1. 访问顶点v
  2. 依次访问v的各个未被访问的邻接点
  3. 分别从这些邻接点出发,依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问。直至图中所有与顶点v有路径相通的顶点都被访问到。

首先要理解搜索步,一个完整的搜索步包括两个处理
a) 获得当前位置上,有几条路可供选择
b) 根据选择策略,选择其中一条路,并走到下个位置
相当于在漆黑的夜里,你只能看清你站的位置和你前面的路,但你不知道每条路能够通向哪里。

搜索的任务就是,给出初始位置和目标位置,要求找到一条到达目标的路径。
深度优先就是,从初始点出发,不断向前走,如果碰到死路了,就往回走一步,尝试另一条路,直到发现了目标位置。这种不撞南墙不回头的方法,即使成功也不一定找到一条好路,但好处是需要记住的位置比较少。

广度优先就是,从初始点出发,把所有可能的路径都走一遍,如果里面没有目标位置,则尝试把所有两步能够到的位置都走一遍,看有没有目标位置;如果还不行,则尝试所有三步可以到的位置。这种方法,一定可以找到一条最短路径,但需要记忆的内容实在很多,要量力而行。
宽泛意义上:深度优先一般是解决连通性问题,而广度优先一般是解决最短路径问题。

最小生成树

生成树的代价:设G=(V,E)是一个无向连通图,生成树上各边的权值之和成为该生成树的代价。
最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树。

Prim算法的基本思想:

  1. 初始时,从V中任取一个顶点(如v1),将其放入U中,使得T的初始状态为U={v1}, TE = {},初始状态的最小生成树可以看成是一颗只含有一个顶点的树。
  2. 重复执行:
    选择一条权值最小的交叉边(vi, vj),其中,vi∈U,vj∈V-U,并把该边(vi, vj)和其不再最小生成树尚的顶点vj分别加入T的顶点集U和边集TE中,直到图G中的n个顶点均被加入到最小生成树T中为止。

Prim算法的关键:

  • 如何找到连接U和V-U的最短边

可用下述方法构造候选最短边集:对应V-U中的每个顶点,保留从该顶点到U中各顶点的最短边。

引入一个辅助数组miniedges[],用于存放集合V-U中的各顶点到集合U中顶点的最小交叉边及其权值:

typedef struct 
{
	VertexType vex;
	float lowcost;
}Edge;
  1. 初始化辅助数组miniedges[]
  2. 输入顶点v,将顶点v加入集合U中
  3. 重复执行下列操作n-1次
    - 选取出全职最小的候选交叉边,取其对应的定点序号k,
    - 将顶点k加入到集合U中
    - 调整数组miniedges[]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值