0

我一直在开发一个小程序,该程序使用 OpenMP 计算给定图中每个顶点的最短路径,以在多个线程之间拆分计算,而不是一次执行一个顶点。虽然我当前的实现有效,但我想这样做,以便我可以从格式为“vertex1 vertex2 weight”的文件中读取图形数据,这样图形就不会被硬编码到程序中。

来源在这里: http: //pastebin.com/bkR7QysB

编译如下:

g++ -fopenmp GraphTest.cpp WeightedGraph.cpp -o dijkstra

使用以下数据作为输入:

foo derp 50
narf balls 30
foo balls 20
balls derp 60
derp narf 40
derp cox 30
foo narf 50
narf pie 99
cox pie 15
cox narf 10

我的输出是:

Enter filename: lol.out
Printing all edges currently in graph: 
(foo, derp) : cost 50
(narf, balls) : cost 30
(foo, balls) : cost 20
(balls, derp) : cost 60
(derp, narf) : cost 40
(derp, cox) : cost 30
(foo, narf) : cost 50
(narf, pie) : cost 99
(cox, pie) : cost 15
(cox, narf) : cost 10

[thread:0] Showing single-source shortest path run for source vertex balls. Format is (start, end) : cost.
(balls, balls : cost 0)
(balls, derp : cost 60)

[thread:0] Showing single-source shortest path run for source vertex cox. Format is (start, end) : cost.
(cox, cox : cost 0)
(cox, narf : cost 10)

[thread:1] Showing single-source shortest path run for source vertex derp. Format is (start, end) : cost.
(derp, derp : cost 0)
(derp, cox : cost 30)

[thread:1] Showing single-source shortest path run for source vertex foo. Format is (start, end) : cost.
(foo, foo : cost 0)
(foo, narf : cost 50)

[thread:2] Showing single-source shortest path run for source vertex narf. Format is (start, end) : cost.
(narf, narf : cost 0)
(narf, cox : cost 10)

[thread:2] Showing single-source shortest path run for source vertex pie. Format is (start, end) : cost.
(pie, pie : cost 0)
(pie, cox : cost 15)

这显然是不正确的——它应该打印从一个顶点到图中每个其他顶点的最短路径,但在这里它只打印到自身的最短路径(始终为 0)以及到其直接相邻的一个的路径邻居。它根本没有遍历图表。然而,最奇怪的部分是取消注释 GraphTest.cpp 末尾附近的那个大块并注释掉文件处理代码,以便将图形数据硬编码到程序中,一切正常:

Printing all edges currently in graph: 
(foo, derp) : cost 50
(narf, balls) : cost 30
(foo, balls) : cost 20
(balls, derp) : cost 60
(derp, narf) : cost 40
(derp, cox) : cost 30
(foo, narf) : cost 50
(narf, pie) : cost 99
(cox, pie) : cost 15
(cox, narf) : cost 10

[thread:0] Showing single-source shortest path run for source vertex balls. Format is (start, end) : cost.
(balls, balls : cost 0)
(balls, foo : cost 20)
(balls, narf : cost 30)
(balls, cox : cost 40)
(balls, pie : cost 55)
(balls, derp : cost 60)

[thread:0] Showing single-source shortest path run for source vertex cox. Format is (start, end) : cost.
(cox, cox : cost 0)
(cox, narf : cost 10)
(cox, pie : cost 15)
(cox, derp : cost 30)
(cox, balls : cost 40)
(cox, foo : cost 60)

[thread:1] Showing single-source shortest path run for source vertex derp. Format is (start, end) : cost.
(derp, derp : cost 0)
(derp, cox : cost 30)
(derp, narf : cost 40)
(derp, pie : cost 45)
(derp, foo : cost 50)
(derp, balls : cost 60)

[thread:1] Showing single-source shortest path run for source vertex foo. Format is (start, end) : cost.
(foo, foo : cost 0)
(foo, balls : cost 20)
(foo, derp : cost 50)
(foo, narf : cost 50)
(foo, cox : cost 60)
(foo, pie : cost 75)

[thread:2] Showing single-source shortest path run for source vertex narf. Format is (start, end) : cost.
(narf, narf : cost 0)
(narf, cox : cost 10)
(narf, pie : cost 25)
(narf, balls : cost 30)
(narf, derp : cost 40)
(narf, foo : cost 50)

[thread:2] Showing single-source shortest path run for source vertex pie. Format is (start, end) : cost.
(pie, pie : cost 0)
(pie, cox : cost 15)
(pie, narf : cost 25)
(pie, derp : cost 45)
(pie, balls : cost 55)
(pie, foo : cost 75)

老实说,我不知道这里发生了什么。我唯一能想到的是某处的东西太早超出范围并导致我的图形对象行为异常,但如果这是真的那么两个输出应该是错误的......希望比我更聪明的人可以运行这并帮助我找出问题所在。

4

1 回答 1

0

我将提到我在阅读您的代码时看到的一些问题:

  1. 请注意,您的边缘图由一对索引,因此您在此处实现的必须是有向图。因为您按 (vi, vj) ​​进行索引,所以边 (v0, v1) 和 (v1, v0) 是不同的,并且将具有不同的值(甚至可能不存在!)。您可能应该考虑一种管理边缘的方法,以便查找它们不依赖于顺序。

  2. 我不明白您为什么在严重依赖标准模板库的代码中使用 char*s。弦乐是你的朋友!

现在,我认为问题在于您正在重新插入顶点。在您的代码中,您无需进行任何检查以确保您添加的顶点不存在于图中。相反,您只需分配一个新顶点并将其放入您的顶点映射中。如果已经有一个具有该名称的顶点,它会在地图中被覆盖,并且您将失去对该数据的唯一引用。因此,您有内存泄漏,因为被替换的顶点永远不会被删除。

因此,如果您的输入文件是:

narf 球 50 foo narf 10

您的代码将在两行上创建并添加一个 narf 顶点。这是迄今为止我看到的唯一区别,但它很重要,并且会产生非常昂贵的错误以及内存泄漏。

作为旁注,我不一定看到拥有边缘对象的价值。您可以轻松地将边缘的所有信息存储在每个顶点 _neighbors 列表中。将该列表设为地图,将相邻顶点的名称设为键并将成本设为值:

_neighborMap[ v0.name() ] = 成本;

拥有边缘类型似乎只是增加了许多不必要的引用和复杂性。只是一个想法...

当我进一步查看您的代码时,我发现您实际上从未删除任何 Vertex 或 Edge 对象。如果您不想使用动态内存分配,只需让您的 Graph 使用 Vertex 实例而不是指针。这些是非常小的对象,因此您只需执行以下操作即可通过复制在额外指令方面花费很多:

_internalVertexMap[ "v0" ] = Vertex( "v0" );
于 2011-05-11T01:02:43.060 回答