gpt4 book ai didi

c++ - std::priority_queue 对比 std::set 的 Dijkstra 最短路径算法性能

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:05:21 25 4
gpt4 key购买 nike

我想了解这些容器在时间复杂度方面的主要区别。我已经尝试了 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];}

最佳答案

跳过

你在优先级队列上加倍工作真的很糟糕。

你是双重插入到队列中,因为你不能修改或删除。这是正常且必要的,因为您不能。

但是当这些旧值从队列中出来时,您需要“跳过 while 循环的迭代”。

类似于:

if (PQ.top().second != distance[PQ.top().first]) continue;  // It's stale! SKIP!!

关于c++ - std::priority_queue 对比 std::set 的 Dijkstra 最短路径算法性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43434465/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com