【问题标题】:Priority queue and Prim's Algorithm优先队列和 Prim 算法
【发布时间】:2014-01-09 14:01:03
【问题描述】:

我已经阅读了 C++ 参考手册,但仍然不清楚如何在 STL 中使用 priorityqueue 数据结构。

所以,基本上我一直在尝试使用堆来实现我自己的。

我这样做是为了实现 Prim 的算法。

Vector <int, int> pq;

这是我的优先队列。第一个字段是节点,第二个字段是现有树的权重。

我计划在每次将新节点添加到树中时通过更新其相邻节点的权重来修改 pq 中的权重值。

  • 如何访问该向量的各个元素?我还需要能够随意删除元素。

这是实现优先级队列的好方法吗?如果我想在容器中添加另一个字段,即

Vector<int, int, int> MST
  • 如何访问第三个元素?我想以这种方式存储生成的 MST,以便前两个字段表示形成边缘的顶点,第三个字段表示权重。

如果有人能告诉我如何使用 push_back 将元素分配给该向量,那也会有所帮助。

  • 另外,传统的 C++ STL 优先级队列会对此有所帮助吗,因为每次向 MST 添加新元素时我都需要更新优先级值?修改值时会根据优先级自行更正吗?

  • 另一个问题,这些向量,当我将它们传递给函数并尝试进行更改时,它是按值传递还是按引用传递 - 或者,这些更改是否反映在函数外部?

【问题讨论】:

  • 你是指古老过时的ARM与“C++参考手册”吗?
  • 如果你的意思是std::vectorVector,STL 向量可能只有一个元素类型的模板参数(实际上它也有分配器模板参数)。您可以使用 std::vector&lt;std::pair&lt;int,int&gt;&gt; 来代替您的目的。 cplusplus.com/reference/vector/vector
  • @PlasmaHH :我实际上是指 cplusplus.com 站点作为参考。我认为这是合法的:)
  • @vard:是的。我的意思是 std::vector。好吧,我需要同时添加边缘和重量,并且能够单独访问要打印的元素。
  • @Floose 实际上你想要索引优先级队列,对吗?

标签: c++ algorithm stl


【解决方案1】:

在 Prim 的算法中,不需要随机访问元素。您只需要跳过已连接的队列中的元素并向前传递。

所以算法如下:

  1. 选择一个节点N
  2. N 的所有边添加到 PQ 中
  3. 从 PQ 中弹出最低成本优势
    • 如果它连接已经在树中的节点,跳过它
    • 否则将此边添加到树中,调用新节点 N 并返回第 2 点。

添加节点后,只需检查树的大小是否已经为size of graph - 1。如果是,则结束。

请注意,PQ 上的唯一操作是 add_elementpop_minimum - 因此 std::priority_queue 将起作用。

【讨论】:

  • 你能解释一下你的意思以及我应该怎么做。我认为优先队列是最简单的实现
  • 我没写清楚。我的意思是不需要随机访问。我会更新答案
  • 啊,好吧。我不是在问随机访问。只是如何在 Vector 中存储和检索元素
  • 那我好像误会了,抱歉。我会再检查一遍。
  • 我在代码中实现这部分时遇到了一点麻烦-“从 PQ 中弹出一个最小成本边缘-如果它连接了已经在树中的节点,请跳过它”如何检查这个?如果您可以在答案中包含 STL 优先级队列的工作原理,那也会有所帮助 - 我根本无法理解语法。
【解决方案2】:

首先,std::vector&lt;int,int&gt; 无效 - 第二个类型参数是(可选)分配器,而 int 不是分配器。如果您使用不同的底层容器,请说出它是什么。我假设你现在想使用std::vector

其次,std::priority_queue 不支持你想要的操作(访问和删除任意元素),所以你不能使用它。

您可以直接使用底层向量,以及堆算法(std::make_heap 等)对其进行排序:

  • 随机访问将起作用(尽管当您的向量处于堆顺序时,您还不清楚您期望索引是什么)
  • 删除任意元素需要将其从向量中删除并重新运行 make_heap,或者您可以实现自己的 siftDown

哦,你可以制作一些值类型来存储在你的向量中,比如

std::vector<std::pair<int,int>>

对于你的第一个例子,或者更清楚:

struct {
  int node;
  int weight;
} Node;
// ...
std::vector<Node>

【讨论】:

  • 如何访问 vector 的单个元素?我也不明白分配器的作用以及为什么这会使实现有效。
  • @Floose 您可以使用std::vector at() 方法或随机访问运算符,也可以使用迭代器和原始指针访问向量元素。
  • 不,我是否使用相同的vector[i].node和vector[i].weight?这是正确的吗?
  • @Floose 是的,它是正确的,但使用 at() 运算符可能会更好,因为它会检查向量边界本身,而 operator[] 不会。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-27
  • 2013-12-23
  • 1970-01-01
  • 2013-08-08
相关资源
最近更新 更多