You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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;
}

咱们来掰碎了看:

  • visitedstd::vector<Node*>,所以std::find返回的迭代器指向的元素类型是Node*(错误信息里的aka "Node *"就是在说这个)
  • 但你要赋值给*ittempstd::pair<Node*, int>类型,一个是指针,一个是键值对,这俩完全不是一回事,编译器当然会报错说找不到合适的转换函数。

你这里混淆了两个概念:visited应该是用来标记已经处理过的节点(即已经确定了最短路径的节点),而finalWeight是用来记录每个节点的最短路径权重,这俩不能混在一起操作。

二、关于_Scary_val的说明

这个名字看起来挺唬人,但其实你完全不用关心它——它是C++标准库中std::vector的内部实现细节(比如GCC的STL里用这个结构体来管理vector的内存、迭代器状态等),属于库的内部命名,和你的代码逻辑没有任何关系。错误信息里真正有用的是后面的aka "Node *",它明确告诉你迭代器指向的元素类型是Node*

三、Dijkstra实现的逻辑修正

除了刚才的类型错误,你的代码还有几个需要调整的地方,我给你梳理下并给出修正方案:

1. 调整数据结构:用映射记录节点的最短距离

把原来的finalWeightvisited合并成一个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

火山引擎 最新活动