graph算法
❶ 数据结构——图graph(基础概念)
【各种东拼西凑来的】
图(Graph)是由顶点和连接顶点的边构成的离散结构。在计算机科学中,图是最灵活的数据结构之一,很多问题都可以使用图模型进行建模求解。例如:生态环境中不同物种的相互竞争、人与人之间的社交与关系网络、化学上用图区分结构不同但分子式相同的同分异构体、分析计算机网络的拓扑结构确定两台计算机是否可以通信、找到两个城市之间的最短路径等等。
图的结构很简单,就是由顶点$V$集和边$E$集构成,因此图可以表示成$G=(V, E)$。
注意: 顶点有时也称为节点或者交点,边有时也称为链接。
无向图
我们可以说这张图中,有点集$V=\{1, 2, 3, 4, 5, 6\}$,边集$E=\{(1, 2), (1, 5), (2, 3), (2, 5), (3, 4), (4, 5), (4, 6)\}$。在无向图中,边$(u, v)$和边$(v, u)$是一样的,因此只要记录一个就行了。简而言之,对称。
有向图
也很好理解,就是加上了方向性,顶点$(u, v)$之间的关系和顶点$(v,u)$之间的关系不同,后者或许不存在。例如,地图应用中必须存储单行道的信息,避免给出错误的方向。
加权图 :
权:与图的边或弧相关的数叫做权。
与加权图对应的就是无权图,或叫等权图。如果一张图不含权重信息,我们就认为边与边之间没有差别。不过,具体建模的时候,很多时候都需要有权重,比如对中国重要城市间道路联吵隐笑系的建模,总不能认为从北京去上海和从北京去广州一样远(等权)。
还有很多细化的概念,比如:无向图中,任意两个顶点间都有边,称为 无向完全图 ;加权图起一个新名字,叫 网(network) ……然而,如无必要,毋增实体。
邻接(adjacency) :邻接是 两个顶点之间 的一种关系。如果图包含$(u,v)$,则称顶点$v$与顶点$u$邻接。当然,在无向图中,这也意味着顶点$u$与顶点$v$邻接。
关联(incidence) :关联是 边和顶点之间 的关系。在有向图中,边$(u,v)$从顶点$u$开始关联到$v$,或者相反,从$v$关联到$u$。注意,有向图中,边不一定是对称的,有去无回是完全有可能的。细化这个概念,就有了顶点的 入度(in-degree) 和 出度(out-degree) 。无向图中,顶点的度就是与顶点相关联的边的数目,没有入度和出度。在有向图中,我们以图1-2为例,顶点10有2个入度,$3\rightarrow10$,$11\rightarrow10$,但是升含没有从10指向其它顶点的边,因此顶点10的出度为0。
路径(path) :依次遍历顶点序列之间的边所形成的轨迹。注意,依次就意味着有序,先1后2和先2后1不一样。
简单路径 : 没有重复顶点的路径称为简单路径。说白了,这一趟路里没有出现绕了一圈回到同一点的情况,也就是没有 环 。
环/回路 :包含相同的顶点两次或者两次以上。图1-3中的顶点序列$<1,2,4,3,1>$,1出现了两次,当然还有其它的环,比如$<1,4,3,1>$。
简单回路/简单环: 除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路
无环图 :没有环的图,携毕其中, 有向无环图 有特殊的名称,叫做 DAG(Directed Acyline Graph) (最好记住,DAG具有一些很好性质,比如很多动态规划的问题都可以转化成DAG中的最长路径、最短路径或者路径计数的问题)。
两个连通分支:
连通的 :无向图中每一对不同的顶点之间都有路径。如果这个条件在有向图里也成立,那么就是 强连通 的。
连通分量 :无向图中的极大连通子图。
两点强连通:在有向图G中,如果两点互相可达
强连通图: 如果有向图G的每两个顶点都强连通(任意两点互相可达),称G是一个 强连通图 。
强连通分量: 非强连通有向图的极大强连通子图,称为强连通 分量 (strongly connected components)。
关节点(割点) :某些特定的顶点对于保持图或连通分支的连通性有特殊的重要意义。如果 移除某个顶点 将使图或者分支 失去连通性 ,则称该顶点为 关节点 。(在某图中,若删除顶点V以及V相关的边后,图的一个连通分量分割为两个或两个以上的连通分量,则称顶点V为该图的一个关节点)。
桥(割边) :和关节点类似,删除一条边,就产生比原图更多的连通分支的子图,这条边就称为 割边 或者 桥 。
双连通图 :在无向连通图中,如果删除该图的任何一个结点都不能改变该图的连通性,则该图为双连通的无向图。个人理解就是一个双连通图没有割点,没有桥的图。
1.2 一些有趣的图概念
这一部分属于图论的内容,基础图算法不会用到,但是我觉得挺有意思的,小记如下。【这部分我没看,照搬过来了】
同构 4 :图看起来结构不一样,但它是一样的。假定有$G_1$和$G_2$,那么你只要确认对于$G_1$中的所有的两个 相邻点 $a$和$b$,可以通过某种方式$f$映射到$G_2$,映射后的两个点$f(a)$、$f(b)$也是相邻的。换句话说,当两个简单图同构时,两个图的顶点之间保持相邻关系的一一对应。
图1-7就展示了图的同构,这里顶点个数很少判断图的同构很简单。我们可以把v1看成u1,自然我们会把u3看出v3。用数学的语言就是$f(u_1)=v_1$,$f(u_3)=v_3$。u1的另外一个连接是到u2,v1的另外一个连接是到v4,不难从相邻顶点的关系验证$f(u_2)=v_4$,$f(u_4)=v_2$。
欧拉回路(Euler Circuit) :小学数学课本上的哥尼斯堡七桥问题,能不能从镇里的某个位置出发 不重复的经过所有桥(边)并且返回出发点 。这也就小学的一笔画问题,欧拉大神解决里这个问题,开创了图论。结论很简单:至少2个顶点的连通多重图存在欧拉回路的充要条件是 每个顶点的度都是偶数 。证明也很容易,大家有兴趣可以阅读相关资料。结论也很好理解,从某个起点出发,最后要回起点,中间无论路过多少次起点,都会再次离开,进、出的数目必然相等,故一定是偶数。
哈密顿回路(Hamilton Circuit) :哈密顿回路条件就比欧拉回路严格一点, 不能重复经过点 。你可能会感到意外,对于欧拉回路,我们可以轻而易举地回答,但是 我们却很难解决哈密顿回路问题,实际上它是一个NP完全问题 。这个术语源自1857年爱尔兰数学家威廉·罗万·哈密顿爵士发明的智力题。哈密顿的智力题用到了木质十二面体(如图1-8(a)所示,十二面体有12个正五边形表面)、十二面体每个顶点上的钉子、以及细线。十二面体的20个顶点用世界上的不同城市标记。智力题要求从一个城市开始,沿十二面体的边旅行,访问其他19个城市,每个恰好一次,最终回到第一个城市。
因为作者不可能向每位读者提供带钉子和细线的木质十二面体,所以考虑了一个 等价的问题 :对图1-8(b)的图是否具有恰好经过每个顶点一次的回路?它就是对原题的解,因为这个平面图 同构 于十二面体顶点和边。
着名的 旅行商问题(TSP) 要求旅行商访问一组城市所应当选取的最短路线。这个问题可以归结为求完全图的哈密顿回路,使这个回路的边的权重和尽可能的小。同样,因为这是个NP完全问题,最直截了当的方法就检查所有可能的哈密顿回路,然后选择权重和最小的。当然这样效率几乎难以忍受,时间复杂度高达$O(n!)$。在实际应用中,我们使用的启发式搜索等 近似算法 ,可以完全求解城市数量上万的实例,并且甚至能在误差1%范围内估计上百万个城市的问题。
关于旅行商问题目前的研究进展,可以到 http://www.math.uwaterloo.ca/... 。
1.3 小结
以为可以一带而过,结果写了那么多。也没什么好总结的了,当然这些也至是图论概念的一小部分,还有一些图可能我们以后也会见到,比如顺着图到网络流,就会涉及二分图,不过都很好理解,毕竟有图。
1、数组(邻接矩阵)
2、邻接表
3、十字链表
4、邻接多种表
❷ GraphCut——GrabCut
此种算法是对图像进行分割操作,其将一幅图像转换成图形结构来描述,通过找到图中的最小割,从而将图像中的前景与背景进行分割。
1、GraphCut
如上图所示,将图中的像素点作为图中的点集,相邻像素通过边相连,另外多出的两个点S,T分别代表的是归于前景的点和归于背景的点。对每个边设置相应的权重,图割的目的就在于利用最小割的方法将边缘部分进行分割,此时的能量值(损失值)最小,由此得到对应的S,T集合,达到分割的目的。过程如下图所示(其中B,O代表事先设置的种子点,由此知道分割出来的部分哪个代表背景,哪个代表目标;B代表该点属于背景点,O代表该点属于目标点):
2、GrabCut:
GrabCut是基于GraphCut的改进算法,通过交互的方式得出前景与背景。
为什么画个框就能分割出前景与背景呢?
在框选出区域后,则将选框以外的部分视为背景区域,将选框以内的区域视为可能的前景区域。然后通过计算前景高斯混合模型(GMM)和背景GMM,然后对每一个像素的rgb值代入单个的高斯模型进行计算,选取值最大的那个模型作为该像素点的归属,然后再建立一个图,对该图求解最小隐此割,如此循环直至收敛,由此判断得出选框内的前景区域与背景区域。
那关键在于如何得出前景与背景的GMM呢?
不同于GraphCut中的一次性求解图的最衡野小割问题,GrabCut中采用的是迭代优化的方式逐步求解得出GMM。其具体过程如下图所示:·
*其实对于这两个算法的具体实现并不是很清楚,在这儿只是想大体了解有这样的一种分割的算法,故也就不深究其是如何具体实现的了~另外Opencv中已经实现了GrabCut算法,可以去玩玩~~
的确玩了一回,在进行区域分割的时候,通过将图咐携喊像进行二值化处理后,将其作为掩模来进行grabcut操作。但是处理速度比较慢,并且分割的准确性主要依赖二值图像的质量~。
❸ graphgraphics区别
1、区别使用范围:graph主要用于算法、数据结裤睁构、网络等领域;graphics则用于计算机图形学、设计等领域。
2、了解概念和定义:graph和graphics分别代表不同的概念和定义,需要在实际运用汪碰中使用正确的术语。
3、学习相关应用技术:要对graph和胡陵岁graphics相关的应用技术有足够的了解,才能更好地运用和发挥其应用价值。
❹ GraphX和Graphscope哪个算法更厉害
GraphScope的性能更优, GraphLab将数据抽象成Graph结构,非常的厉害
❺ python graph怎么看
图结构(Graph)——算法学中最强大的框架之一。树结构只是图的一种特殊情况。
如果我们可将自己的工作诠释成一个图问题的话,那么该问题至少已经碰判接近解决方案了。而我们我们的问题实例可以用树结构(tree)来诠释,那么我们基本上已经拥有了一个真正有效的解决方案了。
邻接表及加权邻接字典
对于图结构的实现来说,最直观的方式之一就是使用邻接列表。基本上就是针对每个节点设置一个邻接列表。下面我们来实现一个最简单的:假设我们现有 n 个节点,编号分别为 0, …, n-1.
节点当然可以是任何对象,可被赋予任何标签或名称。但使用 0, …, n-1 区间内的整数来实现的话,会简单许多。因为如果我们能用数字来代表节点,我们索引起来显然要方便许多。
然后,每个邻接(邻居)列表都只是一个数字列表,我们可以将它们编入一个大小为 n 的主列表,并用节点编号对其进行索引。由于这些列表内的节点的顺序是任意的,所以,实际上,我们是使用列表来实现邻接集(adjacency sets)。这里之所以还是使用列表这个术语,主要是因为传统。幸运的是,Python 本身就提供独立的 set 类型。
我们以下图为例,说明图结构的各种表示方笑凳改法(当我们在执行与图相关的工作时,粗孝需要反复遵从一个主题思想,即一个图的最佳表示方法应该取决于我们要用它来做什么):
a, b, c, d, e, f, g, h = range(8)N = [ {b, c, d, e, f}, {c, e}, {d}, {e}, {f}, {c, g, h}, {f, h}, {f, g}]1234567891011
在图论中,N(v)代表的是v的邻居节点集;
>>> b in N[a] # neighborhood membershipTrue>>> len(N[f]) # out-degree:出度31234
加权邻接字典
使用dict类型来代替set或list来表示邻接集。在 dict 类型中,每个邻居节点都会有一个键和一个额外的值,用于表示与其邻居节点(或出边)之间的关联性,如边的权重。
a, b, c, d, e, f, g, h = range(8)
N = [
{b:2, c:1, d:3, e:9, f:4},
{c:4, e:4},
{d:8},
{e:7},
{f:5},
{c:2, g:2, h:2},
{f:1, h:6},
{f:9, g:8}
]123456789101112
客户端调用:
>>> b in N[a] # neighborhood membership
True
>>> len(N[f]) # out-degree
3
>>> N[a][b] # Edge weight for (a, b)
2123456
邻接矩阵
邻接矩阵是图的另一种表示方法,这种表示方法的主要不同在于,它不再列出每个节点的所有邻居节点。
a, b, c, d, e, f, g, h = range(8)
N =[
[0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 1, 1, 0],
]12345678910111213
关于邻接矩阵:
(1)主对角线为自己到自己,为0
(2)行和为出度
(3)列和为入度
❻ c++实现的图(graph)的算法,怎么能可视化演
#pragma comment(lib,"user32")#pragma comment(lib,"gdi32")#include <stdio.h>#include <stdlib.h>#include <windows.h>HWND WINAPI GetConsoleWindow();void HideTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = FALSE; SetConsoleCursorInfo(hStdOut, &cciCursor); }}void ShowTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = TRUE; SetConsoleCursorInfo(hStdOut, &cciCursor); }}int main() { HWND hwnd; HDC hdc; HFONT hfont; system("color F0"); system("cls"); HideTheCursor(); hwnd = GetConsoleWindow(); hdc = GetDC(hwnd); hfont = CreateFont(48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "华文楷体"); SelectObject(hdc,hfont); TextOut(hdc,10,10,"地球人都知道!",14); MoveToEx(hdc,5,5,NULL); LineTo(hdc,300, 5); LineTo(hdc,300, 60); LineTo(hdc, 5, 60); LineTo(hdc, 5, 5); DeleteObject(hfont); ReleaseDC(hwnd,hdc); getchar(); system("color 07"); system("cls"); ShowTheCursor(); return 0;}
❼ graphx 实现floyd算法,并记录路径
https://my.oschina.net/uchihamadara/blog/834852
这里使用graphx 实现了好几个图路径算法念闭,但是都没有记录路径。
图算法包括pregel包,其实都是皮颤基于aggreationMessage 来做的。
我们的算法也是,在发送的消息里面,需要记录路径
核心思想,就是设计传递的消息体,
不但要包含,当前最短路径,还需要记录最短路径涉及的 path 记录。仔握裂
Map[VertexId, (Double,List[VertexId]) ]
这个Double是当前最短路径的值, List<VertexId> 就是走过的路径节点集合。
这个list 可以扩展设计,比如包含path 的 节点和边,以及你想要的属性。都是可以的。
❽ 几种常见的Graph Embedding方法
在介绍Graph Embedding之前,我们先回顾什么是Embedding? Embedding在数学上是一个函数,将一个空间的点映射到另一个空间,通常是从高维抽象的空间映射到低维的具象空间。Embeding的意义将高维数据转换到低维利于算法的处理;同时解决one-hot向量长度随样本的变化而变化,以及无法表示两个实体之间的相关性这一问题。
最常见的embeding方法是word2vec,根据语料库中单词的共现关系求出每个单词的embedding,常用的word2vec模型有cbow和skip-gram两种,cbow根据上下文预测贺芹中心词,skip-gram根据中心词预测上下文(详见word2vec 中的数学原理详解)。因此既然自然语言中的单词可以通过共现关系进行embedding,那么将graph类比成整个语料库,图中的节点类比成单词,我们是否也可以通过耐岁共现关系对graph中的node进行embedding?对于word2vec而言,语料库中的每个句子都可以描述单词之间的共现,对于graph,这种共现关系如何描述呢?接下来我们将对多种不同的graph embedding方式进行展开。
Graph Embedding 的中心思想就是找到一种映射函数,该函数将网络中的每个节点转换为低维度的潜在表示。利于计算存储,不用再手动提特征(自适应性),下图是graph embeding的几种常见分类:
DeepWalk 通过将节点视为单词并生成短随机游走作为句子来弥补网络嵌入和单词嵌入之间的差距。然后,可以将诸如 Skip-gram 之类的神经语言模型应用于这些随机游走以获得网络嵌入。其优点是首先其可以按需生成随机游走。由于 Skip-gram 模型也针对每个样本进行了优化,因此随机游走和 Skip-gram 的组合使 DeepWalk 成为在线算法。其次,DeepWalk 是可扩展的,生成随机游走和优化 Skip-gram 模型的过程都是高效且平凡的并行化。最重要的是,DeepWalk 引入了深度学习图形的范例。
用SkipGram的方法进行网络中节点的表示学习。那么,根据SkipGram的思路,最重要的就是定义Context,也就是Neighborhood。NLP中,Neighborhood是当前Word周围的字,本文用随机游走得到Graph或者Network中节点的Neighborhood。
(1)随机游走随机均匀地选取网络节点,并生成固定长度的随机游走序列,将此序列类比为自然语言中的句子(节点序列=句子,序列中的节点=句子中的单词),应用skip-gram模型学习节点的分布式表示。
(2)前提昌拍睁:如果一个网络的节点服从幂律分布,那么节点在随机游走序列中的出现次数也服从幂律分布,并且实证发现NLP中单词的出现频率也服从幂律分布。
预测上下 文节点)--------- output:representation
node2vec在DW的基础上,定义了一个bias random walk的策略生成序列,仍然用skip gram去训练。
论文分析了BFS和DFS两种游走方式,保留的网络结构信息是不一样的。 DeepWalk中根据边的权重进行随机游走,而node2vec加了一个权重调整参数α:t是上一个节点,v是最新节点,x是候选下一个节点。d(t,x)是t到候选节点的最小跳数。 通过不同的p和q参数设置,来达到保留不同信息的目的。当p和q都是1.0的时候,它等价于DeepWalk。
利用SkipGram的方法,来为Networks抽取Representation。那么,自然,根据SkipGram的思路,最重要的就是定义这个Context,或者说是Neighborhood。从文本的角度来说,这个Neighborhood当然就是当前Word周围的字,这个定义非常自然。但是对于Graph或者Network来说就来得没那么容易了。
(1)先区分两个概念:
一阶相似度:直接相连节点间,例如6与7。
定义节点vi和vj间的联合概率为
v代表节点,u代表节点的embedding。上面式子的意思是两节点越相似,内积越大,sigmoid映射后的值越大,也就是这两节点相连的权重越大,也就是这两个节点间出现的概率越大???。
二阶相似度:通过其他中介节点相连的节点间例如5与6。
用的是一个条件概率
(2)目标是让NRL前后节点间相似度不变,也节点表示学习前如果两个节点比较相似,那么embedding后的这两个节点表示向量也要很相似。--此文中用的是KL散度,度量两个概率分布之间的距离。
以保证其一阶相似度为例子:
embedding前:节点vi和vj间的经验联合概率为
所以,最小化:
前面说了很多GE的模型,从古典方法,到只考虑结构的模型,再到考虑节点和变extra info的模型,再到深度模型,大家可能觉眼花缭乱,并不知道实际中应该用哪个模型。
这里我提一句,你选择的模型一定要和你的实际问题相关:
1.比如你的问题更加关注内容相似性(局部邻域相似性)那么你可以选择node2vec,LINE,GraRep等;
2.如果你的问题更加关注结构相似性,你可以选择struc2vec,这里可以简单说以下为什么蚂蚁金服风控模型使用struc2vec相比node2vec有质的提升,这是因为在风控领域,你可信并不能代表你的邻居可信(有些“大 V”节点的邻居众多),但是一个直观的感觉是,如果两个人在图中处于相似的地位(比如两个“大 V”),那么这两个人应该都可信或都不可信,并且一般来说这样两个人(节点)相距较远;
3.再者如果你的模型需要考虑节点和边的额外信息,那么你可选择CANE,CENE,Trans-net等;
4.如果你想处理大规模易变图,你可以采用GraphSAGE,或者先使用其他GE方法,再使用GraphSAGE归纳学习;
如果你想微调你的模型,你可选择GraphGAN;
甚至你可以选择很多GE方法,并将得到的embedding向量进行聚合,比如concat等方式。
Graph Embedding作为知识图谱的经典方法之一,其应用非常广泛。当今国内外互联网搜索引擎公司已经意识到知识图谱的战略意义,纷纷构建知识图谱,如Google知识图谱(Google Knowledge Graph),网络“知心”和搜狗的“知立方”,以此来改进搜索质量,知识图谱对搜索引擎形态日益产生重要的影响。
了解更多关于知识图谱、Graph Embedding干货知识,锁定8月20日(星期四)下午14:00公开课!
❾ Graph简述
remarks: 从bear导入的,不可见图为草稿,重点部分都有写。
连通图漏没首(connected graph):如果从任意一个顶点都存在一条路径到达另一个任意顶点(undirected graph)
树:是一幅无环无向连通图察晌
森林:1个or几个树
简单路径(simple path):一条没有重复顶点的路径
简单环(simple cycle):一条(除了起点和终点必须相同之外)不含有重复顶点和边的环
adjacent: when 2 v are connected by a single edge
biconnectivity/ biconnected graph: 移除一条边也不会使graph成为unconnected的graph
subgraph(of graph G):只取G中的几个顶点构成的图
spanning subgraph:取G中所有顶点构成的图
spanning tree:是G的subgraph+是tree=由G中所有顶点构成的无环无向连通图(spanning tree不唯一)
directed edge: 有箭头的边,eg. flight(从A点到B点)
undirected edge: 无箭头的边,eg. flight route(A和B的距离)
directed graph
undirected graph
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WUgPCDy8-1605523062295)(Graph/24905163-e121bc7bba6f78d1.png)]
space: O(V^2)
add edge: O(1)
check if adjacent: O(1)
iteration: O(V)
eg: [ [0,1], [0, 2], [0, 5], [1, 2], [2, 3], [2, 4], [3, 4], [3, 5] ]
Edge里含两个int变量
space: O(E)
add edge: O(1)
check if adjacent: O(E)
iteration: O(E)
0: 6--->5--->2--->1
1: 3--->0
2: 0
3: 5--->1
4: 6--->5
5: 4--->3--->0
6: 7--->4--->0
7: 8--->6
8: 10--->7
9: 11--->返数10
10: 12--->9--->8
11: 9
12: 10
a) 使用的空间和V+E成正比
b) 添加一条边所需的时间为常数
c) 遍历顶点v的所有相邻顶点所需的时间和v的度数成正比
d) 每条边会出现两次
space: O(V+E)
add edge: O(1)
check adjacent: deg(v) <- vertex v
iteration: deg(v)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Z4nziuk-1605523062297)(Graph/Photo%20Nov%2013,%202020%20at%20105929%20PM.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yShOuTgS-1605523062298)(Graph/[email protected])]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFy3SB4e-1605523062299)(Graph/[email protected])]
O(V+E)
dfs遍历整个图的顺序和最短路径无关,而bfs搜索的是最短路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfnh5z5r-1605523062302)(Graph/20190329164255150.png)]
共三个
可利用 深度优先 来找出图中所有的连通分量
*深度优先搜索的预处理使用的时间和空间与V+E成正比且可以在常数时间内处理关于图的连通性查询。
有向图:由一组顶点和一组有方向的边组成的,每条有方向的边都连接着有序的一对顶点
indegree(入度):point to
outdegree(出度):point away
simple:没有重复的E / V
simple digraph的定律:E <= V(V-1)
strongly connected: every V is reachable from every other V
判断strongly connectivity的时间复杂度:O(V+E)
在有向图中,深度优先搜索标记由一个集合的顶点可达的所有顶点所需的时间与被标记的所有顶点的出度之和成正比
用途:解决优先级限制下的调度问题
有向无环图(DAG):不含有向环的有向图
顶点的强连通:如果两个顶点v和w是互相可达的,那么它们是强连通的
图的强连通:如果一幅有向图中的任意两个顶点都是强连通的,则称这幅有向图也是强连通的
三个for loop
space: O(V^2)
runtime: O(V^3)
必须是DAG -> directed graph that has no cycle
见笔记
O(V+E)
适用于 加权有向图
重点解决“找到从一个顶点到达另一个顶点的权重最小的 有向路径 ”
(只写了要注意的)
放松边v -> w意味着检查从s到w的最短路径是否是先从s -> v -> w的,如果是,那么更新数据结构的内容
采用了类似Prim的类似方法来计算最短路径树
Dijkstra可以解决边 权重非负 的加权 有向图 的 单起点 最短路径问题。
也可以在加权无向图中找到最短路径
graph需要时connected的
使用Dijkstra计算根结点为给定起点的最短路径树所需的空间与V成正比,时间与ElogV成正比 -> O(ElogV)
用处:
当且仅当加权有向图中至少 存在一条从s到v的有向路径 且所有从s到v的有向路径上的任意顶点都 不存在于任何负权重环中 时,s到v的最短路径才是存在的
Bellman-Ford算法所需的时间和EV成正比,空间和V成正比
一幅加权图的最小生成树(MST)是它的一棵权值(树中所有边的权值之和)最小的生成树
最小生成树仅存在于加权无向图
每幅连通图都只有一棵唯一的最小生成树(所有边权重不同)
无cycle=a tree+weight minimize
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgJkoBgj-1605523062304)(Graph/Photo%20Nov%2013,%202020%20at%20102515%20PM.jpg)]
只有一个顶点,会向它添加V-1条边,每次总是将下一条连接树中的顶点与不在树中的顶点且权值最小的边加入树中
最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili 4:00
把所有边和weight按大小 排序 ,但保证不能有cycle
最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili 2:09
所需的空间和E成正比,所需的时间和 ElogE 成正比
分块然后选最短的路径连接
O(ElogV)
对于每一种切分,权重最小的横切边必然属于最小生成树。
Remarks:Prim和Kruskal不能处理有向图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYd98l3e-1605523062305)(Graph/Photo%20Nov%2013,%202020%20at%20102448%20PM.jpg)]
图的邻接矩阵的实现
无向图1——图的邻接表数组表示以及DFS、BFS搜索算法实现_大魔王-CSDN博客
【数据结构】图的连通分量 HaYa-CSDN博客 数据结构 连通分量
连通图和连通分量 weixin_30569153的博客-CSDN博客 连通分量
❿ 图的五种存储结构
图的邻接矩阵(Adjacency Matrix): 图的邻接矩阵用两个数组来表示图。一个一维数组存储图中顶点信息,另一个二维数组(一般称之为邻接矩阵)来存储图中的边或者弧的信息。从邻接矩阵中我们自然知道一个顶点的度(对于无向图)或者有向图中一个顶点的入度出度信息。
假设图G有n个顶点,则邻接矩阵是一个n*n的方阵。
1.对于如果图上的每条边不带权值来说,那么我们就用真(一般为1)和假(一般为0)来表示一个顶点到另一个顶点存不存在边。下面是一个图的邻接矩阵的定义:
邻接矩阵法实现带权值的无向图的创建如下:
按照如图输入各边(不重复)
测试程序如下:
结果可得该矩阵,证明创建树成功。 假设n个顶点e条边的创建,createGraph算法的时间复杂度为O(n+n*n+e)。如果需要创建一个有向图,那么和上面一样一个一个录入边下标和权值。
邻接矩阵这种存储结构的优缺点: 缺点是对于边数相对顶点较少的稀疏图来说会存在极大的空间浪费。假设有n个顶点,优点是对于有向完全图和无向完全图来说邻接矩阵是一种不错的存储结构,浪费的话也只浪费了n个顶点的容量。
在树的存储结构一节中我们提到对于孩子表示法的第三种:用一段连续的存储单元(数组)存储树中的所有结点,利用一个单链表来存储数组中每个结点的孩子的信息。对于图的存储结构来说,我们也可以利用这种方法实现图的存储
邻接表(Adjacency List): 这种数组与链表相结合的存储方法叫做邻接表。1.为什么不也用单链表存储图的结点信息呢?原因就是数组这种顺序存储结构读取结点信息速率快。对于顶点数组中,每个数据元素还需要存储一个指向第一个邻接顶点的指针,这样才可以查找边的信息2.图中每个顶点Vi(i > 0)的所有邻接点构成一个线性表 (在无向图中这个线性表称为Vi的边表,有向图中称为顶点作为弧尾的出边表) ,由于邻接点的不确定性,所以用链表存储,有多少个邻接点就malloc一个空间存储邻接点,这样更不会造成空间的浪费(与邻接矩阵相比来说)。3.对于邻接表中的某个顶点来说,用户关心的是这个顶点的邻接点,完全可以遍历用单链表设计成的边表或者出边表得到,所以没必要设计成双链表。
邻接表的存储结构:
假设现在有一无向图G,如下图:
从邻接表结构中,知道一个顶点的度或者判断两个顶点之间是否存在边或者求一个顶点的所有邻接顶点是很容易的。
假设现在有一有向图G,如下图:
无向图的邻接表创建示例如下:
假设在上图(无向图)中的V0V1V2V3顶点值为ABCD,则依据下面测试程序可得结果:
邻接表的优缺点: 优点是:邻接表存储图,既能够知道一个顶点的度和顶点的邻接结点的信息,并且更不会造成空间的浪费。缺点是邻接表存储有向图时,如果关心的是顶点的出度问题自然用邻接表结构,但是想了解入度需要遍历图才知道(需要考虑逆邻接表)。
十字链表(Orthogonal List) :有向图的一种存储方法,它把邻接表和逆邻接表结合起来,因此在十字链表结构中可以知道一个顶点的入度和出度情况。
重新定义顶点表的结点如下图:
现在有一有向图如下图:
则它的存储结构示意图为:
其定义如下:
十字链表是用来存储有向图的,这样可以看出一个顶点的出入度信息。对于无向图来说完全没必要用十字链表来存储。
在无向图中,因为我们关注的是顶点的信息,在考虑节约空间的情况下我们利用邻接表来存储无向图。但是如果我们关注的是边的信息,例如需要删除某条边对于邻接表来说是挺繁琐的。它需要操作两个单链表删除两个结点。因此我们仿照十字链表的方式对边表结点结构重新定义如下图:
它的邻接多重表结构为:
多重邻接表的优点:对于边的操作相比于邻接表来说更加方便。比如说我们现在需要删除(V0,V2)这条边,只需将69步骤中的指针改为nullptr即可。
边集数组(edgeset array): 边集数组是由两个数组组成,一个存储顶点信息,另一个存储边的信息,这个边数组中的每个数据元素由起点下标,终点下标,和权组成(如果边上含有权值的话)。
边数组结构如下图:
边集数组实现图的存储的优缺点:优点是对于边的操作方便快捷,操作的只是数组元素。比如说删除某条边,只需要删除一个数组元素。缺点是:对于图的顶点信息,我们只有遍历整个边数组才知道,这个费时。因此对于关注边的操作来说,边集数组更加方便。