我正在寻找一种将图形存储为字符串的方法。字符串将用作地图中的键,以便两个拓扑相同的图形将映射到地图中的相同值。有人知道这样的算法吗? 树的节点标有允许的重复标签。
该程序在java中,并且其实现很简单,但是可以理解任何指向可能算法的指针。
答案 0 :(得分:5)
如果你有一个算法将一般图形映射到字符串,并且当两个图形映射到同一个字符串时,当且仅当它们在拓扑上是等价的时候,那么你有一个GRAPH AUTOMORPHISM的算法。 图形自同构没有已知的多项式时间算法。所以你不能(很容易)一个多项式时间算法来计算你假设的字符串,因为否则你已经构造了一个用于绘制自同构的未知且非常有效的算法。
这并不意味着无法解决你的类图表的问题;它只是意味着对于所有图的类来说,这有点困难。
答案 1 :(得分:3)
您可能会发现以下问题相关......
基本上,可以使用自动理论教科书中众所周知的算法来最小化自动机。 Hopcrofts就是一个例子。正好有一个最小的自动机,相当于任何给定的自动机。然而,该最小自动机可以以不同方式表示。构造一个安全的规范形式基本上是重新编号节点并使用在定义自动机方面很重要的信息排序邻接表,而不是通过特定于表示的信息来排序。
基本原则应扩展到一般图表。是否可以最小化图形取决于它们的语义,但重新编号节点和排序邻接列表的基本思想仍然适用。
此处的其他答案假定您的图表有关 - 例如,节点具有可以排序的唯一标签,这些标签对于图形的语义很重要,可用于标识邻接矩阵或列表中的节点。例如,如果您对未标记图形的变形感兴趣,这将无法工作。对节点进行编号的不同方式(从而对邻接列表进行排序)将导致等效图形的不同规范形式恰好以不同的方式表示。
对于重新编号等,一种方法是借用和自适应自动机最小化算法的原则。基本上...
创建块矢量(节点集)。最初,每个节点类别(即每个不同的节点注释)填充一个块。这里的修改是我们通过注释细节(而不是特定于表示的节点ID)对它们进行排序。
对于按顺序排列的每个边(注释),评估每个块。如果块中的每个节点都可以跟随当前边缘类型到达同一组下一个块,则保持不变。否则,根据需要拆分它以获得实现此目标的最大块。将这些拆分块保持在向量中聚集在一起(保留现有的排序,稍微改进一下),并根据下一个块集的合适顺序对拆分块进行排序。例如,只要块的当前向量使用位向量,并且通过遵循当前边缘类型可以使每个块的设置位可达。要对bitvectors进行排序,请将它们视为大整数。
编辑 - 我忘了提及 - 在第二个项目符号中,一旦拆分一个块,就会重新启动向量中的第一个块和第一个边注释。显然,一个天真的实现会很慢,所以采用原理并用它来适应Hopcrofts最小化算法。
如果最终得到包含多个节点的块,则这些节点是等效的。这是否意味着它们可以合并取决于你的语义,但每个这样的块中节点的相对排序显然无关紧要。
如果处理可以最小化的图形(例如自动机有向图),我怀疑最好先将其最小化,但我仍然没有自己实现这一点。
关键是,当然,确保您的重新编号仅对图表的重要细节 敏感 - 其结构和注释 - 而不仅仅是那里的东西,以便您可以构造一个表示,如节点ID /地址等。
一旦订购了块,就可以轻松获得规范形式。
答案 2 :(得分:1)
gSpan引入了“最小DFS代码”,它对图形进行编码,使得如果两个图形具有相同的代码,则它们必须是同构的。 gSpan具有C ++和Java实现。
答案 3 :(得分:0)
执行此操作的常用方法是使用Adjacency lists
答案 4 :(得分:-1)
在邻接列表旁边,有adjacency matrices。您选择哪一个应该取决于您使用哪个来实现您的Graph类(邻接列表通常是更好的选择,但它们都有优点和缺点)。如果你有一个完全不同的Graph实现,考虑使用其中之一,因为它使很多图算法很容易实现。
如果可能,另一个选项是覆盖Graph类上的hashCode()
和equals()
,并使用实际的图形对象作为键,而不是转换为字符串。
E:覆盖hashCode()
和equals()
是我将采取的路线,如果某些顶点没有唯一标记。正如评论中所指出的,这可能很昂贵,但我认为这将取决于Graph类的实现。
如果equals()
过于昂贵,那么您应该使用邻接列表或矩阵,但不要只使用节点名称。您必须仔细指定识别单个图形和顶点的确切内容(以及使它们相等的内容),然后使邻接列表的字符串表示使用这些属性而不是节点名称。我建议你的图表write this specification等于操作。