使用邻接列表C++实现 Dijkstra

Implementing Dijkstra with adjacency list C++

本文关键字:C++ 实现 Dijkstra 列表      更新时间:2023-10-16

我正在尝试为具有用户定义对象的邻接列表编写Dijkstra算法。

这个项目是我工作的一部分,所以我必须保持一般。

我正在使用邻接列表和 STL 优先级队列

这是我比较不同节点的方式

class priorityQueueCompareNodes
{
public:
bool operator() ( const Node& leftSideNode, 
const Node& rightSideNode  )
{
return leftSideNode.cost > rightSideNode.cost;
}
};

这就是我弹出并插入优先级队列的方式。

//get the node with the lowest cost from the priority queue
Node closestNode = priorityQueue.top();
//pop this node from the queue
priorityQueue.pop();

当我放宽边缘并将成本更改为不同的节点时,我会更改邻接列表,而不是优先级队列。

我的问题是我如何更改优先级队列中的值,以便每次放松边缘权重和更改距离/父母时都有更新的优先级队列。

谢谢大家。

使用任何类型的指针来访问std::priority_queue的内部工作原理以更新其中的元素都是有问题的。例如,在最低优先级队列中,数据结构保证节点的值小于其子节点的值。如果选择更新优先级队列中的值,则必须手动执行冒泡操作,以保持该保证的完整性。手动执行冒泡向上/向下操作有点击败使用像std::priority_queue这样的集合的重要性。

使用std::set提供了一种可行的替代方案。要检索最小值和最大值,只需使用集合的beginrbegin指针即可。除了集合之外,您应该为节点保留最小距离M的数组/向量(即随机访问集合(。每当松弛产生到节点v的较短路径时,你可以删除旧的集合条目v,更新M[v],并将v的条目插入到具有新M[v]值的集合中。更新M[v]在恒定时间内完成,设置操作需要O(log|V|)时间。因此,即使它具有比优先级队列更大的常量因子,使用集合也具有相同的渐近复杂性。

下面是说明用法的伪代码。由于您的代码不完整,我求助于使用标准数据类型。图的顶点是 0 索引的,对于v i,邻接列表adjList保持传出边的向量在adjList[i]中。对于每条边,将分别保留目标顶点的索引和该边的权重。

void dijkstra(vector< vector< pair<int, long long> > >& adjList, int source) {
set< pair<long long, int> > priorityQueue;
vector< long long > minCosts(adjList.size(), INFINITY);
minCosts[source] = 0LL;
priorityQueue.insert( make_pair(minCosts[source], source) );
while(!priorityQueue.empty()) {
set< pair<long long, int> >::iterator it = priorityQueue.begin();
int u = it->second;
long long costU = it->first;
for(int i=0; i < adjList[u].size(); ++i) {
int v = adjList[u][i].first;
long long w = adjList[u][i].second;
if (costU + w < minCosts[v]) {
if(minCosts[v] < INFINITY) {
priorityQueue.erase( make_pair(minCosts[v], v) );
}
minCosts[v] = costU + w;
priorityQueue.insert( make_pair(minCosts[v], v) );
}
}
}
// minCosts[] now keeps the minimal distance of all nodes from source
}

显然,在您的代码库中检索边缘成本和相关邻接列表条目可能有所不同,但由于您没有提供这些详细信息,因此我尝试提供一个更通用的代码示例,可以最低限度地强调这一点。基本上,集合可能只保留一对成本和节点索引,然后你就设置好了。

或者,您可以为vehicleNode类型定义一个比较运算符,并将其保留在集合中,而不是一对成本和节点。但这只是一个特定于实施的决定,而不是您问题的要点。