使用邻接列表C++实现 Dijkstra
Implementing Dijkstra with adjacency list C++
我正在尝试为具有用户定义对象的邻接列表编写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
提供了一种可行的替代方案。要检索最小值和最大值,只需使用集合的begin
和rbegin
指针即可。除了集合之外,您应该为节点保留最小距离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
类型定义一个比较运算符,并将其保留在集合中,而不是一对成本和节点。但这只是一个特定于实施的决定,而不是您问题的要点。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- std::random_device是如何实现的