C++实现Dijkstra算法:优先队列迭代器相关类型转换错误问题
C++实现Dijkstra算法:优先队列迭代器相关类型转换错误问题
嘿,我来帮你拆解下你遇到的问题,先从最扎眼的编译错误说起,再一步步理顺Dijkstra的实现逻辑~
一、编译错误的直接原因:类型不匹配
你看到的这个错误信息,核心问题出在Dijkstra函数里的这段代码:
auto it = (std::find(visited.begin(), visited.end(), node->to)); if (*it != node->to) finalWeight.emplace_back(temp); else { *it = temp; }
咱们来掰碎了看:
visited是std::vector<Node*>,所以std::find返回的迭代器指向的元素类型是Node*(错误信息里的aka "Node *"就是在说这个)- 但你要赋值给
*it的temp是std::pair<Node*, int>类型,一个是指针,一个是键值对,这俩完全不是一回事,编译器当然会报错说找不到合适的转换函数。
你这里混淆了两个概念:visited应该是用来标记已经处理过的节点(即已经确定了最短路径的节点),而finalWeight是用来记录每个节点的最短路径权重,这俩不能混在一起操作。
二、关于_Scary_val的说明
这个名字看起来挺唬人,但其实你完全不用关心它——它是C++标准库中std::vector的内部实现细节(比如GCC的STL里用这个结构体来管理vector的内存、迭代器状态等),属于库的内部命名,和你的代码逻辑没有任何关系。错误信息里真正有用的是后面的aka "Node *",它明确告诉你迭代器指向的元素类型是Node*。
三、Dijkstra实现的逻辑修正
除了刚才的类型错误,你的代码还有几个需要调整的地方,我给你梳理下并给出修正方案:
1. 调整数据结构:用映射记录节点的最短距离
把原来的finalWeight和visited合并成一个unordered_map<Node*, int>来存储每个节点的最短路径距离,再用另一个映射记录前驱节点(方便后续回溯路径):
std::unordered_map<Node*, int> dist; std::unordered_map<Node*, Node*> prev; // 初始化所有节点的距离为无穷大(用一个很大的数代替) const int INF = INT_MAX; for (auto& node : graph1.GraphNodes) { dist[node] = INF; } dist[start] = 0; // 起点距离为0
2. 用优先队列代替vector模拟队列,提升效率
你原来用notVisited这个vector手动维护顺序,每次插入都要找位置,效率很低。Dijkstra算法标准实现是用小顶堆(优先队列)来快速取出当前距离最小的节点:
// 定义小顶堆:优先队列默认是大顶堆,所以要自定义比较器 using QueueElement = std::pair<int, Node*>; std::priority_queue<QueueElement, std::vector<QueueElement>, std::greater<QueueElement>> pq; pq.emplace(0, start);
3. 修复双向边的创建逻辑
你的Edge构造函数里注释掉了双向边的创建,导致无向图的边只加了一半,把注释去掉:
Edge::Edge(Node* from, Node* to, int weight, bool directional) { this->to = to; this->from = from; this->weight = weight; from->connections.push_back(this); if (!directional) { // 注意这里要new一个新的Edge,并且directional传true,避免循环创建 new Edge(to, from, weight, true); } }
4. 修正拼写错误
Node类里的conncections多写了一个c,改成connections,不然调用的时候会有编译错误。
修正后的完整Dijkstra函数
#include <climits> #include <unordered_map> #include <queue> #include <algorithm> void dijkstra(Node* start, Node* end) { const int INF = INT_MAX; std::unordered_map<Node*, int> dist; std::unordered_map<Node*, Node*> prev; std::unordered_set<Node*> visited; // 初始化距离 for (auto& node : graph1.GraphNodes) { dist[node] = INF; } dist[start] = 0; // 小顶堆优先队列 using QueueElement = std::pair<int, Node*>; std::priority_queue<QueueElement, std::vector<QueueElement>, std::greater<QueueElement>> pq; pq.emplace(0, start); while (!pq.empty()) { auto [current_dist, u] = pq.top(); pq.pop(); // 如果已经处理过这个节点,跳过 if (visited.count(u)) continue; visited.insert(u); // 到达终点可以提前退出 if (u == end) break; // 遍历当前节点的所有邻边 for (auto& edge : u->connections) { Node* v = edge->to; int weight = edge->weight; // 松弛操作 if (dist[u] != INF && dist[v] > dist[u] + weight) { dist[v] = dist[u] + weight; prev[v] = u; pq.emplace(dist[v], v); } } } // 输出最短距离 if (dist[end] == INF) { std::cout << "没有从" << start->name << "到" << end->name << "的路径!" << std::endl; return; } std::cout << "从" << start->name << "到" << end->name << "的最短路径长度是:" << dist[end] << std::endl; // 回溯路径并输出 std::vector<Node*> path; for (Node* v = end; v != nullptr; v = prev[v]) { path.push_back(v); } std::reverse(path.begin(), path.end()); std::cout << "路径:"; for (size_t i = 0; i < path.size(); ++i) { if (i > 0) std::cout << " -> "; std::cout << path[i]->name; } std::cout << std::endl; }
内容来源于stack exchange




