数据结构:图(广度优先搜索)

图-广度优先搜索

  • [1. 图是什么](#1. 图是什么)
  • [2. 广度优先搜索(BFS)](#2. 广度优先搜索(BFS))

图和数的区别:树中除根节点没有前驱外,其余的每个结点只有唯一的一个前驱(双亲)结点,每个结点可以有多个子结点。图中任意两个结点之间都可能有直接关系,一个结点的前驱和后继的数目是没有限制的。

1. 图是什么

图由节点(node)和边(edge)组成。一个节点可能与众多节点直接相连,这些节点被称为邻居。

Rama是Alex的邻居。Adit不是Alex的邻居,因为他们不直接相连。但Adit既是Rama的邻居,又是Tom的邻居。

1.1 基本概念

图G是由集合V和E构成的二元组,记作 G=(V,E),其中V是图中顶点的非空有限集合,E是图中边的有限集合。

  1. 有向图。若图中的每条边都有方向,则称为有向图。有向边也称为弧,弧线的起点为弧尾,终点为弧头。方向不一样,即使路径相同也是不同的弧。
  2. 无向图。若图中的每条边都没有方向,则称为无向图。
  3. 完全图。若一个无向图具有n个顶点,而每一个顶点与其他n-1个顶点之间都有边则称为无向完全图。含有n个顶点的无向完全图共有 n(n-1)/2 条边;有n个顶点的有向完全图中弧的数目为 n(n-l),即任意两个不同顶点之间都存在方向相反的两条弧。
  4. 度、出度和入度。度是指关联于该顶点的边的数目,记作 D(v)。若 G为有向图,顶点的度表示该顶点的入度和出度之和。顶点的入度是以该顶点为终点的有向边的数目,而顶点的出度指以该顶点为起点的有向边的数目,分别记为ID(v)和 OD(v)。
  5. 路径。从一个结点到另一个结点经过的边的有序集合称为路径。路径的长度是路径上边或弧的数目。第一个定点和最后一个顶点相同的路径称为回路或环。若一条路径除起点和终点相同外,其他的结点都不相同,这种路径称为一条简单路径。
  6. 子图;其中一个图是另一个图的一部分。
  7. 连通图。从一个结点到另一个结点之间有路径,则称这两个结点时连通的。如果无向图中任意两个结点都是连通的,则称为连通图。
  8. 强连通图。在有向图中,如果任意两个结点都存在路劲,则称为强连通图。
  9. 网:边或弧具有权值的图称为网。

图中的结点之间不存在顺序关系。

1.2 存储结构

图的两种存储结构:邻接矩阵和邻接表。

邻接矩阵

邻接矩阵表示法是利用一个矩阵来表示图中顶点之间的关系。对于具有n个顶点的图G=(V,E)来说,其邻接矩阵是一个n阶方阵,且满足:
A [ i ] [ j ] = { 1 , 若( v i , v j )或 < v i , v j > 是 E 中的边 0 , 若( v i , v j )或 < v i , v j > 不是 E 中的边 A[i][j]=\begin{cases} 1, &若(v_i,v_j)或<v_i,v_j>是E中的边\\ 0, &若(v_i,v_j)或<v_i,v_j>不是E中的边\\ \end{cases} A[i][j]={1,0,若(vi,vj)或<vi,vj>是E中的边若(vi,vj)或<vi,vj>不是E中的边

由邻接矩阵的定义可知,无向图的邻接矩阵是对称的,而有向图的邻接矩阵则不一定具有该性质。无向图结点的度为相对应行或列上1的数目,有向图结点的出度为相对应行上1的数目,有向图结点的入度为相对应列上1的数目。

网(权重图)的邻接矩阵定义:
A [ i ] [ j ] = { W i j , 若( v i , v j )或 < v i , v j > 是 E 中的边 ∞ , 若( v i , v j )或 < v i , v j > 不是 E 中的边 A[i][j]=\begin{cases} W_{ij}, &若(v_i,v_j)或<v_i,v_j>是E中的边\\ \infty, &若(v_i,v_j)或<v_i,v_j>不是E中的边\\ \end{cases} A[i][j]={Wij,∞,若(vi,vj)或<vi,vj>是E中的边若(vi,vj)或<vi,vj>不是E中的边

  • 数据类型定义
cpp 复制代码
#define MaxN 50     //图中顶点的最大数量
typedef int AdjMatrix[MaxN][MaxN]  //邻接矩阵
或
typedef double AdjMatrix[MaxN][MaxN]
typedef struct{
	int Vnum,Enum;
	AdiMatrix Arcs;
}Graph;

邻接表

邻接链表是为图的每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶 v i v_i vi的边(对于有向图是以 v i v_i vi为尾的弧)。邻接链表中的结点有表结点和表头结点两种类型。

  • adjvex:指示与顶点 v i v_i vi邻接的顶点的序号;
  • nextarc:指示下一条边或弧的结点。
  • info:存储和边或弧有关的信息,如权值等
  • data:存储顶点 v i v_i vi的名或其他有关信息。
  • firstarc:指示链表中的第一个结点。

数据类型:

cpp 复制代码
#define MaxN 50   //图中顶点的最大数量
typedef struct ArcNode{       //邻接链表的表结点
	int adjvex;               //邻接顶点编号
	double weight;            //边上权重值
	struct ArcNode *nextarc;  //下一个邻接顶点的指针
}EdgeNode;

typedef struct VNode{       //邻接链表的头结点
	char data;              //顶点表示的数据,以一个字符表示
	struct ArcNode *firstarc;  //指示第一条依附于该顶点的指针
}AdjList[MaxN];

typedef struct{
	int Vnum, Enum;         //图中实际的顶点和边数目
	AdjList Vertices;
}Graph;

实例:

2. 广度优先搜索(BFS)

广度优先搜索:解决最短路径的算法,是一种用于图的查找算法。在查找的过程需要按添加顺序进行检查,因此利用队列来实现,利用图来表示关系,利用矩阵/散列表来存储关系。

  1. 第一类问题:从节点A出发,有前往节点B的路径吗?

  2. 第二类问题:从节点A出发,前往节点B的哪条路径最短?

    在广度优先搜索的执行过程中,搜索范围从起点开始逐渐向外延伸,即先检查一度关系,再检查二度关系。一度关系在二度关系之前加入查找名单。

实例1:在人际圈中找人(采用Python中散列表实现)

python 复制代码
graph = {}
graph["you"] = ["alice", "bob", "claire"]
graph["bob"] = ["anuj", "peggy"]
graph["alice"] = ["peggy"]
graph["claire"] = ["thom", "jonny"]
graph["anuj"] = []
graph["peggy"] = []
graph["thom"] = []  //目标人物
graph["jonny"] = []

def search(name):
	search_queue = deque()
	search_queue += graph[name]
	searched = []                             //用于记录检查过的人
	while search_queue:
		person = search_queue.popleft()
		if not person in searched:            //没有检查过才检查
			if person_is_seller(person):
				print person + " is a mango seller!"
				return True
			else:
				search_queue += graph[person]
				searched.append(person)        //将此人标记过检查
return False

实例2:编写国际跳棋AI,计算最少走多少步就可获胜。

实例3:编写拼写检查器,计算最少编辑多少个地方就可将错拼的单词改成正确的单词,如将READED改为READER需要编辑一个地方。

  • 运行时间:广度优先搜索的运行时间为O(人数 + 边数),这通常写作O(V + E),其中V为顶点(vertice)数,E为边数。
相关推荐
凡人的AI工具箱8 小时前
15分钟学 Go 第 21 天:标准库使用
开发语言·后端·算法·golang·1024程序员节
zhousiyuan05158 小时前
手撕FFT
算法
战术摸鱼大师9 小时前
线性代数&群论应用:正逆运动学 & 变换矩阵
线性代数·算法·矩阵
机器学习之心9 小时前
分类预测 | WOA-LightGBM基于鲸鱼算法优化轻量级梯度提升机算法数据分类预测Matlab程序
算法·matlab·分类·woa-lightgbm·轻量级梯度提升机算法
瞌睡不来9 小时前
C++ 整型大数运算(大整数运算)项目
c++·学习·算法·小项目
想做白天梦9 小时前
LeetCode(704)的二分查找 (简单)
数据结构·算法·leetcode
谢尔登9 小时前
【数据结构与算法】力扣 143. 重排链表
算法·leetcode·链表
M-bao9 小时前
Java 实现协同过滤算法推荐算法
算法·推荐算法
大小胖虎9 小时前
数据结构——(第八章:排序)
数据结构·算法·排序算法·归并排序·堆排序·快速排序
轮到我狗叫了10 小时前
分治归并,LCR170交易逆序对的总数 力扣315.计算右侧小于当前元素的个数力扣493.翻转对
算法·1024程序员节