对某些Graph操作的最简单算法的建议

时间:2010-04-15 16:44:01

标签: c algorithm graph dijkstra

这个项目的截止日期很快就会结束,我没有太多时间来处理剩下的事情。因此,我没有寻找最好的(可能更复杂/耗时)算法,而是在寻找最简单的算法来在Graph结构上实现一些操作。

我需要做的操作如下:

  • 列出距离为X
  • 的图表网络中的所有用户
  • 在给定距离X和关系类型的情况下列出图表网络中的所有用户
  • 计算给定关系类型的图表网络上2个用户之间的最短路径
  • 计算图表网络上2个用户之间的最大距离
  • 计算图表网络上距离最远的连接用户

关于我的Graph实现的一些注意事项:

  • 边缘节点有2个属性,一个属于char类型,另一个属于int。它们分别代表关系和体重的类型。
  • 图表是使用链接列表实现的,包括顶点和边。我的意思是,每个顶点指向下一个顶点,每个顶点也指向不同链表的头部,即该特定顶点的边。

我对自己需要做的事情了解到:

  • 我不知道这是否是最简单的,如上所述,但对于2个用户之间的最短路径,我相信Dijkstra算法是人们似乎经常推荐的,所以我想我会继续这样做。
    • 我一直在搜索和搜索,我发现很难实现这个算法,有没有人知道任何教程或易于理解的东西,所以我可以自己实现这个算法?如果可能的话,使用C源代码示例,它会有很大帮助。我看到许多带有数学符号的例子,但这让我更加困惑。
    • 如果我将图形“转换”为邻接矩阵来表示链接权重和关系类型,您认为这会有所帮助吗?是否更容易执行该算法而不是链接列表?我可以轻松地实现一个函数来在需要时进行转换。我这样说是因为我觉得在阅读了几页关于这个主题之后会更容易,但我可能是错的。
  • 我对其他4项操作没有任何想法,建议?

3 个答案:

答案 0 :(得分:8)

  

列出距离为X

的图表网络中的所有用户

距离X距离是什么?从起始节点或它们之间的距离X?你能给我举个例子吗?这可能是也可能不像BF搜索或运行Dijkstra那么简单。

假设您从某个节点开始并希望列出距起始节点X的所有节点,只需从起始节点运行BFS即可。当您要在队列中插入新节点时,检查从起始节点到要插入新节点的节点的距离是否是从要插入新节点的节点的边缘权重到新节点是< = X。如果它严格降低,则插入新节点,如果它相等,则只打印新节点(如果也可以将0作为边缘权重,则只插入它)。

  

在给定距离X和关系类型

的情况下列出图表网络中的所有用户

见上文。只考虑与BFS的关系类型:如果父类型与您尝试插入队列的节点的类型不同,请不要插入它。

  

在给定关系类型

的情况下,计算图网络上2个用户之间的最短路径

算法取决于许多因素:

  • 您需要多久计算一次?
  • 你有多少个节点?

既然你想要轻松,最简单的是Roy-Floyd和Dijkstra。

  • 使用Roy-Floyd是节点数的立方,因此效率低下。只有在你能负担得起运行一次然后在O(1)中回答每个查询时才使用它。如果你能够在内存中保留一个邻接矩阵,请使用它。
  • 如果要保持简单,Dijkstra的节点数是二次的,但每次要计算两个节点之间的距离时,都必须运行它。如果您想使用Dijkstra,请使用邻接列表。

以下是C实现:Roy-FloydDijkstra_1Dijkstra_2。您可以使用"<algorithm name> c implementation"在Google上找到很多内容。

编辑:对于18000个节点,Roy-Floyd是不可能的,邻接矩阵也是如此。构建和占用太多内存需要花费太多时间。您最好的选择是为每个查询使用Dijkstra算法,但最好使用堆实现Dijkstra - 在我提供的链接中,使用堆来查找最小值。如果你在每个查询上运行经典的Dijkstra,那也可能需要很长时间。

另一种选择是在每个查询上使用Bellman-Ford算法,这将为每个查询提供O(Nodes*Edges)运行时。但是,如果你没有像维基百科告诉你的那样实​​现它,这是一个很大的高估。而是使用类似于BFS中使用的队列。每当节点更新其与源的距离时,将该节点插回队列。这在实践中将非常快,并且也适用于负权重。我建议你使用这个或Dijkstra堆,因为经典的Dijkstra可能需要很长时间才能生成18 000个节点。

  

计算图表网络上2个用户之间的最大距离

最简单的方法是使用回溯:尝试所有可能性并保持找到的最长路径。 This is NP-complete,因此不存在多项式解。

如果您有18 000个节点,这真的很糟糕,我不知道任何算法(简单或其他)对于如此多的节点都能合理快速地工作。考虑使用贪心算法逼近它。或者您的图表可能具有某些属性,您可以利用这些属性。例如,它是DAG(有向无环图)吗?

  

计算图表网络上距离最远的连接用户

意思是您想要找到图表的直径。最简单的方法是找到每两个节点之间的距离(所有对最短路径 - 在每两个节点之间运行Roy-Floyd或Dijkstra,并选择具有最大距离的两个节点)。

同样,使用您的节点数和边数很难快速完成。我担心你在最后两个问题上运气不好,除非你的图表具有可被利用的特殊属性。

  

如果我将图形“转换”为邻接矩阵来表示链接权重和关系类型,您认为这会有所帮助吗?是否更容易执行该算法而不是链接列表?我可以轻松地实现一个函数来在需要时进行转换。我这样说是因为我觉得在阅读了几页关于这个主题之后会更容易,但我可能是错的。

不,除非你的应用针对超级计算机,否则邻接矩阵和Roy-Floyd是一个非常糟糕的主意。

答案 1 :(得分:5)

此假设O(E log V)是一个可接受的运行时间,如果你在网上做的事情,这可能不是,它会需要一些更高动力的机器。

  • 列出距离为X
  • 的图表网络中的所有用户

Djikstra's algorithm对此有好处,一次性使用。您可以保存结果以供将来使用,通过线性扫描所有顶点(或者更好的是,排序和二进制搜索)。

  • 在给定距离X和关系类型的情况下列出图表网络中的所有用户

可能与上面几乎相同 - 如果它的关系不正确,只需使用一些重量无穷大的函数。

  • 计算给定关系类型的图表网络上2个用户之间的最短路径

与上面相同,基本上,如果您匹配这两个用户,请尽早确定。 (或者,您可以“在中间相遇”,如果您在最短路径上找到某人,则提前终止)

  • 计算图表网络上2个用户之间的最大距离

Longest pathNP-complete problem

  • 计算图表网络上距离最远的连接用户

这是图表的直径,您可以在Math World上阅读。

对于邻接列表与邻接矩阵问题,它取决于图表的密集程度。此外,如果您想缓存结果,那么矩阵可能就是您的选择。

答案 2 :(得分:1)

计算两个节点之间最短路径的最简单算法是Floyd-Warshall。它只是循环的三重嵌套;就是这样。

它会在O(N^3)中计算所有对的最短路径,因此它可能会执行超出必要的工作,并且如果N很大,则需要一段时间。