【问题标题】:priority queues and dijkstra优先队列和dijkstra
【发布时间】:2013-06-07 22:58:59
【问题描述】:

向我解释如何构建优先级队列以及为什么必须这样构建,就好像我对优先级队列的经验的限制是知道队列是什么(我一生中从未使用过)。

当我在看这个网站时: http://comsci.liu.edu/~jrodriguez/cs631sp08/c++priorityqueue.html

priority_queue<Time, vector<Time>, CompareTime> pq;

我知道 Time 是为了让你有一个 Times 队列,比较 Time 决定了将时间放入队列的优先级,但为什么 vector&lt;Time&gt; 需要在构造函数中?

关于 Dijkstra: 我将图实现为节点向量,每个节点包含该向量中所有邻居位置的列表),所以它看起来像这样:

class Node {
  protected:
  string name;
  int value;
  list<int> nodes
}

我将如何实现 Dijkstra 的这一部分:

for each vertex v in Graph:                                
    dist[v] := infinity ;                               
    previous[v] := undefined ;     

对于 dist[v] = infinity,我假设我将每个节点的值设置为无穷大,但是什么变量可以让我这样做呢?而对于previous[v],undefined是什么意思?

【问题讨论】:

  • 用于无限结帐limit.h-1 或任何其他未使用的数字/字符串标识符。如果您使用双打 stackoverflow.com/a/8640726/1031417
  • Vector

标签: c++


【解决方案1】:

在 C++ 中,int 最大值可以用作无限

#include <limits>

然后使用

int imax = std::numeric_limits<int>::max();

【讨论】:

  • 如果没有 std::whatever 会怎样?最大()?
  • @JonathanChiou 取决于你的系统,但如果int4 字节,那么它就是(1&lt;&lt;31) - 1,这就是为什么使用limits 更好,因为你不必猜测
  • 哦,max 给了我一个整数的最大数。我需要无穷大,因为我的作业中的一个测试用例要求我通过 max()
  • @JonathanChiou 实际上,在实际场景中,您永远不会拥有大于 int 最大值的边
  • 对于 djikstra 来说,previous[v]
【解决方案2】:

它是一个编程练习(也就是你必须必须实现everithing),还是一个真正的程序?

如果是最后一个,检查标准库优先级队列:http://en.cppreference.com/w/cpp/container/priority_queue

另一方面,如果它真的是一个学习练习,在谷歌上搜索一下你会发现:http://pages.cs.wisc.edu/~vernon/cs367/notes/11.PRIORITY-Q.html

我可以写一篇关于priority_queues 实现(最大/最小堆、推送/弹出操作等)的介绍/解释,但那篇论文(我认为)有很好的示例、解释和图片。

编辑:在看到您对我的问题的回答后“这是一个练习还是一个真正的程序?”。我更喜欢在这里写下完整的答案,并附上例子。

第 1 步:设置

std::priority_queue 有三个模板参数:

  • T:很明显,容器中存放的物品的类型。
  • 底层容器:顾名思义,是实现中使用的底层容器的类型。它的默认值为std::vector&lt;T&gt;
  • Comparer:priority_queue 用来比较项目的函子类。它的默认值为std::less&lt;T&gt;(因此,默认情况下,std::priority_queue 是最大优先级队列)。 如果您想要一个最小优先级队列(如您的情况,Dijkstra 算法),您必须通过一个比较器来做到这一点。通常,您为您的类型实现二进制 operator &gt;,以使 std::greater&lt;T&gt; 函子工作。

STEP2:使用std::priority_queue

因此,如果您已正确完成设置,就可以使用std::priority_queue。它具有三个主要操作:

  • push():在 piority_queue 中插入一个值。
  • pop():移除优先级队列的顶部
  • top():返回对存储在 priority_queue 中的具有最大(或最小,取决于您的比较器)优先级的元素的 const 引用。注意 top() 不是删除,它是 pop() 的工作。

示例:

#include <queue>
#include <iostream>

//User defined type. For this short example, a simple uint wrapper:
struct Foo
{
    unsigned int i;

    Foo(unsigned int _i) : i(_i) {}
};

//Implementation of operator> for class Foo, to make std::greater<Foo> work:
bool operator>(const Foo& f1 , const Foo& f2)
{
    return f1.i > f2.i;
}

int main()
{
    std::priority_queue<Foo,std::vector<Foo>,std::greater<Foo>> foo_min_priority_queue;

    foo_min_priority_queue.push(Foo(2));
    foo_min_priority_queue.push(Foo(1));
    foo_min_priority_queue.push(Foo(0));

    std::cout << foo_min_priority_queue.top().i << std::endl; //Prints 0 
    foo_priority_queue.pop();

    std::cout << foo_min_priority_queue.top().i << std::endl; //Prints 1 
    foo_min_priority_queue.pop();

    std::cout << foo_min_priority_queue.top().i << std::endl; //Prints 2 
    foo_min_priority_queue.pop();

    return 0;
}

参考资料:

【讨论】:

  • 真实程序,我需要知道如何使用STL优先队列
  • @JonathanChiou 我用完整的解释和一个例子编辑了答案。
  • 我认为Dijkstra算法不能使用STL的优先级队列,因为该算法需要队列上的decrease-key抽象操作。 STL 的优先级队列既不提供,也不提供删除任意元素以更新其优先级并再次插入的能力。对于高效的 Dijkstra 算法实现,斐波那契堆将是一个不错的选择。尽管 d-ary 堆很简单,但可以自己实现(使用数组)。
  • @android 不是真的。即使队列中存在,您仍然可以将新元素插入优先级队列。在实践中,我从来没有遇到过性能大幅下降的情况。
  • 我认为比较器不是必须的。默认情况下priority_queue 返回最大元素,因此您只需要存储距离的否定结果
猜你喜欢
  • 2013-12-23
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多