for循环语句java图形_Java图形开发人员指南,用于其中的图形和检测循环

for循环语句java图形

在我第一次接受全栈软件工程职位的现场采访时,我被要求编写一个函数,该函数可以检测有向图中是否存在循环。

读者:我没有成功编写该函数。

坦白说,我有一个什么样的图形,甚至朦胧的,在最佳的想法。 在我一生的大部分时间里,我都以为这张图是这样的:

资料来源: http : //bit.ly/2HFsh9w

原来,图实际上是这样的:

资料来源: http : //bit.ly/1OCkA1r

我知道,我认为第一个看起来也更有趣。 但是图实际上是一个非常酷的数据结构。 它们在计算机科学中无处不在,用于推荐引擎Google Maps ,当然还有GraphQL 。 问题是,没有多少文章详细介绍Javascript中图的实现/技巧。 所以我决定写一个。

那图到底是什么?

关于图的最基本知识是它们由顶点组成 顶点是图的东西 :一个整数,对象,一个网站等边连接一对顶点。

图形可以是:

  1. 加权或未加权-这是指图形的边缘是否用值标记。 如果是,则对其进行加权。
  2. 有向还是无向-这是指边缘的行为像桥(无向)还是保龄球道(有向)。
  3. 循环或非循环-这是指图形中是否存在循环。

表示图形的主要方法有两种:使用邻接表 ,它是与每个节点相关联的数组(或对象,如果需要的话)的集合

{
a: [b,c,d],
b: [c,f],
d: [e],
e: [a,f],
f: [a, c, d, e]
}

或带有邻接矩阵,这是一个二维数组,其中顶点之间的边用1表示

[ [0, 1, 0, 0, 0, 0, 1, 0, 1, 0],
[1, 0, 0, 0, 1, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 1, 1, 1, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0, 0, 1, 0, 0] ]

每种表示形式都有其优缺点 。 一般而言,具有大量边的图的表现比矩阵更好,而具有较少边的图的表现比列表更好。 邻接列表往往更常见,而今天我们将使用它。

制作图表

因此,让我们开始吧! 呜。 我们要做的第一件事是…制作一张图表。

Graph构造函数内部的逻辑很简单:只是实例化为对象文字的邻接列表。 接下来的两种方法并不复杂:添加顶点的方法将每个顶点初始化为一个空数组,添加边缘的方法将一个顶点推入另一个顶点的数组。 像这样

制作一个看起来像这样的图:

或换一种说法:

RIP Microsoft画图

现在我们有了一个图! 好极了。 不仅仅是任何图:未加权的有向无环图。

遍历图

现在我们有了一个图,我们将需要找出一种访问不同顶点的方法—毕竟,我们的最终目标是检测该图是否为周期性的,这意味着沿着顶点在顶点之间遍历。图的边缘。

有两种遍历图形的方式: 广度优先遍历,先访问顶点的每个子级,然后再访问该子级中的每个子级;以及深度优先遍历,即遵循由边连接的一系列顶点,直到我们到达顶点为止在继续到原始顶点的下一个子节点之前,不能再进行任何操作。 我们在有向图中检测循环的算法将使用深度优先遍历的修改版本,因此让我们快速看一下该遍历方法的外观。

这里有两个函数:dfs函数和_dfsUtil函数。

dfs函数仅做三件事:

  1. 创建一个名为“ nodes”的数组; 每个元素都是我们图中的一个顶点
  2. 创建一个称为“ visited”的对象文字
  3. 在图形的每个顶点上调用我们的效用函数。

与二叉树(例如)相反,在执行图的深度优先遍历时,要记住的重要一点是,我们需要跟踪已经访问过的节点,而不是第二次访问它们,即使另一个顶点在该节点上有一条边。 例如,如果我们不跟踪所访问的顶点,那么从起点“ A”遍历图形将导致我们四次访问“ B”,而不仅仅是一次! 🙅🙅🙅

A -> B
A -> D -> B
A -> D -> E -> B
A -> C -> E -> B

这就是为什么我们将实用程序函数作为参数传递访问数组的原因。 效用函数是我们访问顶点的地方,将其标记为已访问,获取其边缘,检查给定的边是否已被访问,如果尚未访问,则以该顶点为新起点递归调用我们的效用函数,并更新的“访问”数组。

但是...周期检测?

对! 检测周期。 我们如何修改深度优先搜索功能来确定图是循环的还是非循环的?

和以前一样,我们将为图形中的每个顶点调用循环检测实用程序函数。 如果效用函数从不返回true,我们只能确定图是非循环的。 但是,我们还将创建一个名为“ recStack”的对象文字。

我们在这里做几件事:

  1. 在第45行,我们正在检查以确保我们尚未访问此节点。 如果有,则无需再次检查。
  2. 在第46和47行上,我们在访问堆栈和recStack中将顶点设为true。 在这个新的实用函数中,recStack代表“递归堆栈”,它一直在跟踪后端,我们访问的顶点以使我们到达当前的顶点。
  3. 和以前一样,我们将获取当前顶点的邻居并遍历它们。 但是,这一次,我们不仅要检查是否已经访问过它们,还要检查是否在recStack中存在特定的边缘,这意味着我们已经访问过它。 这是我们发现周期的指标。
  4. 如果顶点不在我们的recStack中,那么我们会将其从递归堆栈中弹出(第59行),这样,当我们遍历图的另一条路径时,我们就不会得到假阳性。

嘿,请记住:这是我们检测图形中是否存在循环的功能。

我看过的大多数计算机科学入门资源中都没有涉及图形,这实在令人遗憾。 他们真的很酷,遍及整个学科,而且在入门级软件开发职位的面试中很普遍(或者至少在我的经验中如此)。 因此,对我的(有抱负的)初级开发人员来说:在进行下一次面试之前,请先学习一些图表。 你永远不会知道。

这是副本: https : //repl.it/@samisthesam/Cycle-detection-in-a-directed-graph

感谢 Sulamita Morales 的咨询和道义支持

翻译自: https://hackernoon.com/the-javascript-developers-guide-to-graphs-and-detecting-cycles-in-them-96f4f619d563

for循环语句java图形

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值