我正在尝试使用prim算法创建最小生成树,我对实际堆有一个主要问题。我将图形邻接列表构造为顶点矢量,每个顶点都有一个边矢量。边缘包含重量,连接顶点和键。我不确定我的堆应该是一堆顶点还是边缘。如果我使它成为一堆顶点,那么无法确定权重是否来自相同的父顶点和目标顶点,这使我认为我应该为每个顶点边列表创建一个堆。所以我最后的问题是我应该创建一堆边缘还是一堆顶点?如果它是一个边缘列表,我应该使用边缘上的权重作为密钥,还是应该有一个名为key的单独数据成员,我可以实际用于优先级队列?谢谢!
答案 0 :(得分:0)
您的堆可以是成对<vertex, weight>
,并且将包含顶点,这些顶点是远离部分最小生成树中已有的任何顶点的单个边。 (编辑:在某些情况下,它可能包含一个已经在部分MST中的顶点,你应该在它们弹出时忽略这些元素。)
它可能是一堆像<src, dst, weight>
这样的边缘,实际上是相同的,你只需忽略src
,而dst
与第一个版本中的vertex
相同
PS。关于那个key
的东西,我认为不需要任何键,你需要比较权重。
答案 1 :(得分:0)
你应该做一个边缘的minHeap,因为你要根据它们的权重排序边缘但是边缘应该包含两个顶点:在每一端表示一个顶点。否则,正如您所建议的那样:无法确定权重是来自相同的父顶点和目标顶点。因此,您应该重新构造边类并对其进行minHeap。
同样考虑Wiki的算法。
使用选定的单个顶点初始化树 从图中任意选择。
通过一条边生长树:边缘 将树连接到尚未在树中的顶点,找到 最小权重边缘,并将其传递给树。
重复步骤2(直到所有顶点都在树中)。
我不完全理解边缘类中的关键字段。我认为它就像一个边缘的Id。因此,您应该创建它们的堆,但是由于您要为堆提供用户定义的数据结构,您还应该为边类提供比较函数,即定义bool operator<(const Edge&)
方法。
答案 2 :(得分:0)
堆必须使用key作为最小加权边来维护顶点。由于顶点仍未被访问,因此任何边缘都将被忽略,因此未访问的顶点的所有未访问边缘的最小值将是要添加到跨越的下一个边缘,因此您将删除与其对应的顶点。这里唯一的问题是将更新的权重保持到堆中顶点的最小边缘,因为生成树在每次迭代中都会更改,并且会向其添加新边。这样做的方法是保持堆中每个未访问顶点的位置,当一个新顶点被添加到生成树时,使用它们指向的顶点的直接位置使用存储位置来更新它的未访问边。然后,如果当前成本低于添加的新边缘权重,则更新顶点最小成本。然后使用堆的标准过程将其冒泡到堆中以维护最小堆。
DataStructure: -
<Vertex,Weight> : Vertex id & weight of minimum edge to it as record of heap
position[Vertex] : The position of vertex record in heap.
注意:内置函数不会帮助你,因此你需要构建自己的堆来使这个工作有效。在开始时将每个顶点的键值初始化为某个无限值
另一种方法:将指向未访问顶点的所有边存储在最小堆中。但这需要比其他方法更高的空间复杂度,但具有类似的摊销时间复杂度。当你提取边缘时检查它指向的顶点是否被访问,如果再次访问提取并丢弃边缘。