图是一种数据结构,其中节点可以具有零个或多个相邻元素。两个节点之间的连接称为边。节点也可以称为顶点。

图分为三种:无向图、有向图、带权图

图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)

邻接矩阵

邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于n个顶点的图而言,矩阵的行和列表示的是1……n个点。邻接矩阵需要为每个顶点都分配n个边的空间,其实有很多边都是不存在的,会造成空间的一定损失。


邻接表

连接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组+链表组成


说明:

  1. 标号为0的节点的相关联的节点为1,2,3,4

  2. 标号为1的节点为0,4

  3. 标号为2的节点的相关联的节点为0,4,5

  4. ……

代码实现图结构


/*** 邻接矩阵表示图* @author sixiaojie* @date 2022-01-07-19:05*/
public class Graph {/** 存储顶点集合 */private ArrayList<String> vertexList;/** 存储图对应的邻接矩阵 */private int[][] edges;/** 表示边的数目 */private int numOfEdges;public static void main(String[] args) {// 顶点个数int n = 5;String[] vertexs = {"A","B","C","D","E"};Graph graph = new Graph(n);// 添加顶点for (String vertexValue : vertexs) {graph.insertVertex(vertexValue);}// 添加边 A-B A-C B-C B-D B-Egraph.insertEdge(0,1,1);// A-Bgraph.insertEdge(0,2,1);// A-Cgraph.insertEdge(1,2,1);// B-Cgraph.insertEdge(1,3,1);// B-Dgraph.insertEdge(1,4,1);// B-E// 显示graph.showGraph();}/*** 构造器*/public Graph(int n) {// 初始化矩阵和vertexListedges = new int[n][n];vertexList = new ArrayList<String>(n);numOfEdges = 0;}/*** 插入顶点* @param vertex*/public void insertVertex(String vertex){vertexList.add(vertex);}/*** 添加边* @param v1 第一个顶点对应的下标* @param v2 第二个顶点对应的下标* @param weight 权值*/public void insertEdge(int v1,int v2,int weight){edges[v1][v2] = weight;edges[v2][v1] = weight;numOfEdges ++ ;}/*** 返回顶点个数* @return*/public int getNumOfVertex(){return vertexList.size();}/*** 返回边的数目* @return*/public int getNumOfEdges(){return numOfEdges;}/*** 返回顶点i(下标)对应的数据0->'A',1->'B',2->'C'* @param index* @return*/public String getValueByIndex(int index){return vertexList.get(index);}/*** 返回v1,v2的权值* @param v1* @param v2* @return*/public int getWeiht(int v1, int v2){return edges[v1][v2];}/*** 显示对应的矩阵*/public void showGraph(){for (int[] link : edges) {System.out.println(Arrays.toString(link));}}
}

图的遍历

图的遍历是指,从给定图中任意指定的顶点(称为初始点)出发,按照某种搜索方法沿着图的边访问图中的所有顶点,使每个顶点仅被访问一次。遍历过程中得到的顶点序列称为图遍历序列。

图的遍历过程中,根据搜索方法的不同,又可以划分为两种搜索策略:

  • 深度优先搜索

  • 广度优先搜索

深度优先搜索(DFS,Depth First Search)

深度优先搜索,从起点出发,从规定的方向中选择其中一个不断地向前走,直到无法继续为止,然后尝试另外一种方向,直到最后走到终点。就像走迷宫一样,尽量往深处走。

DFS 解决的是连通性的问题,即,给定两个点,一个是起始点,一个是终点,判断是不是有一条路径能从起点连接到终点。

假设我们有这么一个图,里面有A、B、C、D、E、F、G、H 8 个顶点,点和点之间的联系如下图所示, 对这个图进行深度优先的遍历。


依赖栈(Stack),特点是后进先出(LIFO)。

第一步,选择一个起始顶点,例如从顶点 A 开始。把 A 压入栈,标记它为访问过(用红色标记),并输出到结果中。


第二步,寻找与 A 相连并且还没有被访问过的顶点,顶点 A 与 B、D、G 相连,而且它们都还没有被访 问过,我们按照字母顺序处理,所以将 B 压入栈,标记它为访问过,并输出到结果中。


第三步,现在我们在顶点 B 上,重复上面的操作,由于 B 与 A、E、F 相连,如果按照字母顺序处理的话,A 应该是要被访问的,但是 A 已经被访问了,所以我们访问顶点 E,将 E 压入栈,标记它为访问过,并输出到结果中。


第四步,从 E 开始,E 与 B、G 相连,但是B刚刚被访问过了,所以下一个被访问的将是G,把G压入 栈,标记它为访问过,并输出到结果中。


第五步,现在我们在顶点 G 的位置,由于与 G 相连的顶点都被访问过了,类似于我们走到了一个死胡同,必须尝试其他的路口了。所以我们这里要做的就是简单地将 G 从栈里弹出,表示我们从 G 这里已经无法继续走下去了,看看能不能从前一个路口找到出路。


如果发现周围的顶点都被访问了,就把当前的顶点弹出。

第六步,现在栈的顶部记录的是顶点 E,我们来看看与 E 相连的顶点中有没有还没被访问到的,发现它们都被访问了,所以把 E 也弹出去。


第七步,当前栈的顶点是 B,看看它周围有没有还没被访问的顶点,有,是顶点 F,于是把 F 压入栈, 标记它为访问过,并输出到结果中。


第八步,当前顶点是 F,与 F 相连并且还未被访问到的点是 C 和 D,按照字母顺序来,下一个被访问的点是 C,将 C 压入栈,标记为访问过,输出到结果中。


第九步,当前顶点为 C,与 C 相连并尚未被访问到的顶点是 H,将 H 压入栈,标记为访问过,输出到结果中。


第十步,当前顶点是 H,由于和它相连的点都被访问过了,将它弹出栈。


第十一步,当前顶点是 C,与 C 相连的点都被访问过了,将 C 弹出栈。


第十二步,当前顶点是 F,与 F 相连的并且尚未访问的点是 D,将 D 压入栈,输出到结果中,并标记为访问过。


第十三步,当前顶点是 D,与它相连的点都被访问过了,将它弹出栈。以此类推,顶点 F,B,A 的邻居都被访问过了,将它们依次弹出栈就好了。最后,当栈里已经没有顶点需要处理了,我们的整个遍历结束。


广度优先搜索(BFS,Breadth First Search)

直观地讲,它其实就是一种“地毯式”层层推进的搜索策略,即先查找离起始顶点最近的,然后是次近的,依次往外搜索。假设我们有这么一个图,里面有A、B、C、D、E、F、G、H 8 个顶点,点和点之间的联系如下图所示, 对这个图进行深度优先的遍历。


依赖队列(Queue),先进先出(FIFO)。

一层一层地把与某个点相连的点放入队列中,处理节点的时候正好按照它们进入队列的顺序进行。

第一步,选择一个起始顶点,让我们从顶点 A 开始。把 A 压入队列,标记它为访问过。


第二步,从队列的头取出顶点 A,打印输出到结果中,同时将与它相连的尚未被访问过的点按照字母大小顺序压入队列,同时把它们都标记为访问过,防止它们被重复地添加到队列中。


第三步,从队列的头取出顶点 B,打印输出它,同时将与它相连的尚未被访问过的点(也就是 E 和 F) 压入队列,同时把它们都标记为访问过。


第四步,继续从队列的头取出顶点D,打印输出它,此时我们发现,与 D 相连的顶点 A 和 F 都被标记访问过了,所以就不要把它们压入队列里。


第五步,接下来,队列的头是顶点 G,打印输出它,同样的,G 周围的点都被标记访问过了。我们不做任何处理。


第六步,队列的头是 E,打印输出它,它周围的点也都被标记为访问过了,我们不做任何处理。


第七步,接下来轮到顶点 F,打印输出它,将 C 压入队列,并标记 C 为访问过。


第八步,将 C 从队列中移出,打印输出它,与它相连的 H 还没被访问到,将 H 压入队列,将它标记为访问过。


第九步,队列里只剩下 H 了,将它移出,打印输出它,发现它的邻居都被访问过了,不做任何事情。


社交网络可以用图来表示。这个问题就非常适合用图的广度优先搜索算法来解决,因为广度优先搜索是 层层往外推进的。首先,遍历与起始顶点最近的一层顶点,也就是用户的一度好友,然后再遍历与用户 距离的边数为 2 的顶点,也就是二度好友关系,以及与用户距离的边数为 3 的顶点,也就是三度好友关系。

每天进步一点点【图的深度优先搜索与广度优先搜索】相关推荐

  1. 深度优先遍历和广度优先遍历_图与深度优先搜索和广度优先搜索

    什么是图? 图是一种复杂的非线性表结构.由若干给定的点一级任意两点间的连线所构成.图通常用来描述事物之间的特定关系, 代表的就是事物, 线就是事物之间所具有的关系.例如社交网络就是一种典型的图关系, ...

  2. 数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)

    目录 一.图的遍历概念 二.深度优先搜索(DFS) (一)DFS算法步骤 1.邻接表DFS算法步骤 2.邻接矩阵DFS算法步骤 (二)深度优先生成树.森林 (三)DFS的空间复杂度和时间复杂度 三.广 ...

  3. 八数码深度优先搜索_深度优先搜索和广度优先搜索

    深度优先搜索和广度优先搜索 关于搜索&遍历 对于搜索来说,我们绝大多数情况下处理的都是叫 "所谓的暴力搜索" ,或者是说比较简单朴素的搜索,也就是说你在搜索的时候没有任何所 ...

  4. 算法十——深度优先搜索和广度优先搜索

    文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 搜索算法 算法是作用于数据结构之上的.深度优先搜索.广度优先搜索是作用于图这种数据结构之上的.图上的搜索 ...

  5. 分别用邻接矩阵和邻接表实现图的深度优先遍历和广度优先遍历_数据结构与算法学习笔记:图...

    图: 图结构区别于线性结构和树型结构,区别可见下图 逻辑上的图(graph)结构由顶点(vertex)和边(edge)组成. 一个图结构G包含顶点集合V和边集合E,任何两个顶点之间可以有一个边表示两者 ...

  6. 深度优先搜索和广度优先搜索

    深度优先搜索和广度优先搜索 ​ 在人工智能的运筹学的领域中求解与图相关的应用中,这两个算法被证明是非常有用的,而且,如需高效地研究图的基本性质,例如图的连通性以及图是否存在环,这些算法也是必不可少的. ...

  7. 深度优先搜索与广度优先搜索区别和案例

    今天周末,心血来潮打开LeetCode做一道题: https://leetcode-cn.com/problems/number-of-enclaves/ 看到题,我的第一想法是: 从边缘的陆地开始, ...

  8. 迷宫问题:深度优先搜索和广度优先搜索

    迷宫问题:深度优先搜索和广度优先搜索 1.深度优先搜索可以使用栈实现,栈顶元素为当前节点 2.当前节点搜索下一节点,判断节点是否走得通,如果走得通任意方向走一步,走不通一直弹出栈内元素,直到走得通 3 ...

  9. 学会二叉树不知道干啥?二叉树的深度优先搜索和广度优先搜索,我要打十个乃至二十个(打开你的LeetCode撸起来)学练并举

    目录 一. 图解二叉树的深度优先搜索 二. 二叉树的广度优先搜索  (层序遍历) 三. 打开LeetCode 撸起来 至此, 咱多少被刚刚的后序非递归搞得可能有点小晕晕的, 没事,层序简单呀....  ...

最新文章

  1. 推荐几个开源类库,超好用,远离996!
  2. Dickey-Fuller检验+迪基-福勒检验
  3. 嘲笑一下SUN科技日开发者大会 O(∩_∩)O~
  4. 找到一篇有关A*算法文章,不错~收藏
  5. CF467C George and Job
  6. sublime配置python运行环境
  7. renderthread是什么_Android5.0中 hwui 中 RenderThread 工作流程
  8. php编写个人所得税单元测试,php趣味编程-php求个人所得税
  9. 如何pspice模型转成saber模型
  10. linux脚本实现多重管道,制作Linux shell时流重定向和管道
  11. 最大似然参数估计的求解
  12. 封校大学生无聊玩起图像大找茬——游戏脚本(一起领略Python脚本的风采吧)
  13. apex乱码_[请教]apex安装简体中文语言包的步骤
  14. aspcms用mysql_aspcms增加手机版支持与电脑公用一个后台
  15. 《我爱我的祖国》受捧 再现专线另类舌尖上中国
  16. 面向初学者的 MQL4 语言系列之4——自定义指标
  17. 羊车门问题python_用Python实现羊车门问题
  18. Linux系统有哪些?盘点常用的 8 个Linux系统!
  19. 基于Webrtc的多人视频会议的简单实现
  20. 天翼云服务器挂载硬盘

热门文章

  1. 初识Matlab-简介|软件界面介绍|搜索路径|帮助系统
  2. 基于多机CUP分布式训练
  3. varbinary转换成字符串
  4. js中获取当前点击的li标签以及li标签中a标签的id
  5. 总结了11句话,送给通信新员工
  6. Microservices Ecosystem Transit Map
  7. 《塞尔达传说:旷野之息》技术分析:游戏神作是怎么炼成的
  8. 2022.12.16 英语单词背诵
  9. A*算法求解15数码问题
  10. 牛客巅峰赛12th C.一起来看流星雨(旋转卡壳三分)