感兴趣的绝大多数算法都对数据进行操作。 因此,有一些特殊的组织数据的方法在算法的设计和分析中起着至关重要的作用。 由此可见,数据结构只是组织数据的简单方法。
它们是线性的或非线性的 。 数组和链接列表是线性数据结构的示例。 另一方面,图和树是非线性数据结构的形式。
- 例如,一个常见的数据结构是list或array ,它是值的有序序列。 以下是数字列表:0、1、1、2、3、5、8、13。列表的概念并不只针对一种语言,在日常生活中,编程之外也使用了它-愿望清单,购物列表等。
算法是逻辑上执行问题的方法。 它们与数据结构不同。 如果算法运行更快或更有效(使用更少的时间,内存或两者兼有),通常会“更好”。
但是在本文中,这全都涉及到研究非线性数据结构:图形
分为图表
图是一个系统,其中从任意点A到另一个任意点B可能有多种方法。
图通常定义为一对集合(V,E)。 V是一组称为顶点或节点的任意对象,E是一组顶点对,我们称其为边或弧(很少见)。 在无向图中,边是无序对,或者是两个顶点的集合。 我通常用uv代替{u,v}来表示u和v之间的无向边。
在有向图中,边是有序的成对的顶点。 在本文中,我将使用u→v代替(u,v)来表示从u到v的有向边,反之亦然。
图也可以是无向或有向的,循环或无环的(主要是有向的)或加权的。
遍历图
为了访问作为连接组件的每个节点或顶点,使用了基于树的算法。 您可以通过遍历图形的所有顶点,在检查时仍未访问的每个顶点上执行算法,轻松地做到这一点。
图的遍历通常使用两种算法:深度优先搜索(DFS)和广度优先搜索(BFS)。
深度优先搜索(DFS)算法
深度优先搜索(DFS)是一种用于搜索图形或树数据结构的算法 。 该算法从树的根(顶部)节点开始,一直沿其向下到达给定分支(路径)的距离,然后回溯直至找到未探索的路径,然后对其进行探索。 算法将执行此操作,直到浏览完整个图形为止。
可以用图形来思考计算机科学中的许多问题。 例如,分析网络,映射路线,调度和查找生成树就是图问题。 为了分析这些问题,深度优先搜索之类的图形搜索算法很有用。 - 来源
最简单的伪代码为:
深度优先搜索是许多人在解决诸如迷宫之类的问题时自然使用的一种常见方式。
首先,我们在迷宫中选择一条路径(就本例而言,让我们根据预先设置的规则选择一条路径),然后遵循该路径,直到遇到死角或到达迷宫的尽头。 如果给定的路径不起作用,我们将回溯并从过去的交汇处选择另一条路径,然后尝试使用该路径。
为了将其转化为图遍历算法,我们基本上用“邻居”代替了“子”。 但是为了防止无限循环,我们只想访问每个顶点一次。 就像在BFS中一样,我们可以使用标记来跟踪已经访问过的顶点,因此我们不再再次访问它们。 同样,就像在BFS中一样,我们可以使用此搜索来构建具有某些有用属性的生成树。
dfs(vertex v)
{
visit(v);
for each neighbor w of v
if w is unvisited
{
dfs(w);
add edge vw to tree T
}
}
这是使用递归的Python实现:
这是DFS工作原理的基本概述。 如果您想更深入地学习,可以在Internet以及Medium上找到一些很棒的东西。
广度优先搜索(BFS)算法
它从树的根部(或图的某个任意节点,有时称为“搜索关键字”)开始,并在移至下一个深度级别的节点之前先探索当前深度的所有邻居节点。
唯一的问题是,与树不同,图可能包含循环,因此我们可能会再次来到同一节点。 为了避免多次处理节点,我们使用布尔访问数组。 为简单起见,假设所有顶点都可以从起始顶点到达。
我们在BFS中所做的是一个简单的分步过程:
- 从顶点S开始。 让这个顶点位于所谓的…。 “ 0级”。
- 查找可从此起始顶点S立即访问的所有其他顶点,即它们仅相隔一条边(相邻的顶点)。
- 将这些相邻的顶点标记为“ Level 1”。
- 由于图中有一个环或一个环,您可能会回到相同的顶点。 如果发生这种情况,您的BFS将花费∞时间。 因此,您将只转到那些未将“级别”设置为某个值的顶点。
- 标记哪个是您当前所在顶点的父顶点,即您从中访问当前顶点的顶点。 对级别1的所有顶点执行此操作。
- 现在,找到与“ Level 1”上所有顶点相距单个边的所有顶点。 这些新的顶点集将位于“第2级”。
- 重复此过程,直到用完图形。\
看到这个-https://www.programiz.com/dsa/graph-bfs
使用队列的Python实现
有向图和无向图
无向图是指边没有方向的图。 边缘( x , y )与边缘( y , x )相同。 也就是说,它们不是有序对,而是无序对,即两个顶点{ x , y }的集合(在循环的情况下为2多重集)。 无向图中没有循环的最大边数为n ( n -1)/ 2。
对于无向图中的任意边u和v ,我们将其称为v的ua邻居,反之亦然。 节点的度数是其邻居数。 在有向图中,我们有两种邻居。 对于任何u-> v的有向边,我们称为v的ua的前任和u的va的后继。
循环图和非循环图
在图的许多属性中,有两个对于大量应用很重要:连通性和非循环性。 两者都是基于路径的概念。
循环图是包含至少一个图循环的图 。 还要记住,循环图不能是树的一种形式,因为树的节点只能通过DFS或BFS(遍历方法)访问一次。
非循环图是没有循环的图(循环是一个完整的电路)。 当从一个节点到另一个节点跟随图形时,您将永远不会访问相同的节点两次。
什么是有向无环图?
有向无环图是具有方向且缺乏循环的无环图。
树是有向无环图的形成
上图的部分是:
- 整数 =顶点的集合。
- 顶点集 = {1,2,3,4,5,6,7}。
- 边集 = {(1,2,3,(1,3),(2,4),(2,5),(3,6),(4,7),(5,7),(6,7 )}。
有向无环图具有拓扑顺序 。 这意味着对节点进行排序,以便起始节点的值比结束节点的值低。 如果DAG具有包含所有节点的定向路径,则它具有唯一的拓扑顺序。 在这种情况下,顺序与节点在路径中出现的顺序相同。
在计算机科学中 ,DAG也称为等待图形 。 当DAG用于检测死锁时,说明资源必须等待另一个进程继续。
我们如何检测图中的周期?
事实证明,深度优先搜索算法特别擅长检测循环的原因是因为它有效地发现了后沿。 我们将在本文后面探讨DFS算法
邻接矩阵和邻接表表示
如果图中有很多边,使用按边列表或邻接表来表示图来执行图算法可能会很麻烦。 为了简化计算,可以使用矩阵表示图形。 这里将介绍两种通常用于表示图形的矩阵。 一种是基于顶点的邻接关系,另一种是基于顶点和边的入射角。
给定一个邻接矩阵,我们只需在矩阵的适当缝隙中观察,即可在Θ(1)时间内确定两个顶点是否通过边连接。 通过扫描相应的行(或列),我们还可以列出在Θ(V)时间内顶点的所有邻居。
从给定图像上方了解邻接矩阵…
让我们了解如何根据给定的图像构造邻接矩阵。 为简单起见,我仅针对顶点“ a”进行了讨论。 同样适用于所有顶点。
由于页面的限制,我没有包括→d和→e的分析。 正如我们可以从图像得出的结论,分别有一个→d和→→e的边。
那邻接表呢?
邻接表数据结构应立即使您想起带有链表的哈希表;这两个数据结构是相同的。
邻接列表是链接列表的数组,每个顶点一个列表。 每个链表都存储相应顶点的邻居。
例如,对于 a 顶点,存在通往邻居的边,如 b,d and e 。 因此,其相应的链表包含通过边连接的顶点。
提醒→对于无向图,每个边(u,v)都会存储两次,一次存储在u的邻居列表中,一次存储在v的邻居列表中; 对于有向图,每个边仅存储一次。
加权图
加权图(或加权图)是为其边缘分配编号的图(或图)。 这些数字称为权重或成本。 对这样的图形的兴趣是由众多实际应用激发的,例如找到运输或通信网络中两个点之间的最短路径或 旅行推销员问题 。
现实生活中的图形示例
Google地图-这只是一张大图! 其中“ 边”代表街道,“顶点”代表十字路口。
图论是互联网的基础。 它在网络代码(构建路由表等)中被大量使用,但是它涉及到各种各样的地方,例如构建互联网搜索引擎或社交媒体平台。
对于深入研究树木,这篇文章是我选择的首选文章之一-https: //medium.freecodecamp.org/all-you-need-to-know-about-tree-data-structures-bceacb85490c
最重要的事实:
- 所有的树都是图。 并非所有图形都是树。
- 树是一种图形,只有将其连接起来。 例如,由顶点A和B组成且无边的图不是树,尽管它是非循环图。
- 单个顶点也被认为是一棵树(无循环,空连接)。 因此,两个未连接的顶点构成了两棵树的森林。
- 树是一种特殊的图,其中永远不会有多条路径,对于A和B的所有可能组合,从A到B总是只有一种方法。
资源:
我们已经与达特茅斯大学的教授汤姆·科门(Tom Cormen)和德文·巴尔克姆(Devin Balkcom)合作,教授入门计算机科学…… www.khanacademy.org
http://www.cs.uiuc.edu/~jeffe/teaching/algorithms
From: https://hackernoon.com/graphs-in-cs-and-its-traversal-algorithms-cfee5533f74e