【发布时间】:2017-09-12 01:36:19
【问题描述】:
我想了解这些容器在时间复杂度方面的主要区别。 我已经尝试了 3 种 Dijkstra 算法的实现,如下所述:
1- 用一个简单的数组作为队列
2- 使用 STL priority_queue
3- 设置了 STL
我测试过的图很大,它包含超过 150000 个顶点,有方向,所有边的权重都是正的。
我得到的结果如下:
1 - 使用数组的算法非常慢 --> 这是预期的
2 - 使用 STL priority_queue,算法运行速度比数组快得多 --> 这也是预期的
3 - 使用 STL 设置算法运行得非常快,我说的是比 priority_queue 快 100 倍 --> 我没想到会看到如此巨大的性能......
知道 std::priority_queue 和 std::set 是存储元素的数据容器,并且两者具有基本相同的插入复杂度 O(log n),我不明白它们之间存在这么大的性能差异。你对此有什么解释吗?
感谢您的帮助,
已编辑: 这是我的实现的摘要:
与 std::set:
unsigned int Graphe::dijkstra(size_t p_source, size_t p_destination) const {
....
set<pair<int, size_t>> set_vertices;
vector<unsigned int> distance(listAdj.size(),
numeric_limits<unsigned int>::max());
vector < size_t
> predecessor(listAdj.size(),
numeric_limits < size_t > ::max());
distance[p_source] = 0;
set_vertices.insert( { 0, p_source });
while (!set_vertices.empty()) {
unsigned int u = set_vertices.begin()->second;
if (u == p_destination) {
break;
}
set_vertices.erase( { distance[u],
u });
for (auto itr = listAdj[u].begin();
itr != listAdj[u].end(); ++itr) {
int v = itr->destination;
int weigth = itr->weigth;
if (distance[v]
> distance[u] + weigth) {
if (distance[v]
!= numeric_limits<unsigned int>::max()) {
set_vertices.erase(
set_vertices.find(
make_pair(distance[v],
v)));
}
distance[v] = distance[u] + weigth;
set_vertices.insert( { distance[v],
v });
predecessor[v] = u;
}
}
}
....
return distance[p_destination];}
并带有priority_queue:
unsigned int Graphe::dijkstra(size_t p_source, size_t p_destination) const {
...
typedef pair<size_t, int> newpair;
priority_queue<newpair, vector<newpair>, greater<newpair> > PQ;
vector<unsigned int> distance(listAdj.size(),
numeric_limits<unsigned int>::max());
vector < size_t
> predecessor(listAdj.size(),
numeric_limits < size_t > ::max());
distance[p_source] = 0;
PQ.push(make_pair(p_source, 0));
while (!PQ.empty()) {
unsigned int u = PQ.top().first;
if (u == p_destination) {
break;
}
PQ.pop();
for (auto itr = listAdj[u].begin();
itr != listAdj[u].end(); ++itr) {
int v = itr->destination;
int weigth = itr->weigth;
if (distance[v]
> distance[u] + weigth) {
distance[v] = distance[u] + weigth;
PQ.push(
make_pair(v, distance[v]));
predecessor[v] = u;
}
}
}
...
return distance[p_destination];}
【问题讨论】:
-
你的实现是否正确?
-
是的,我相信它是正确的,我在三个实现中得到了相同的输出(相同的寻路)。除了在第三个实现中运行时间超快。
-
向我们展示你的实现
-
priority_queue和set之间的巨大差异可能是由更新顶点距离步长引起的。您可以使用set简单地更新距离,但您不能使用priority_queue来更新距离,例如,使用不同的距离多次添加相同的顶点。 -
是的,有道理,这也是我的假设,因为 priority_queue 的巨大损失发生在队列中第一个元素的 pop 步骤中,它的复杂度为O(log(size_queue))
标签: c++ algorithm performance graph stl