Dijkstra最短路径搜索算法简介

一、简介        

        迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止。以参考链接博文的网络节点图为例。

二、基本思想

  1. 首先设定一个排序容器pq,用来存储节点,可以方便我们寻找出距离起点最近的点(优先队列);设定一个距离记录容器dis,用来更新每个节点到起点的最小距离;设定一个路径记录容器pre用来更新距起点的最短路径;
  2. 首先指定一个起点,假设为D,放入排序容器pq中;
  3. 只要pq不为空就开始循环;
  4. 然后遍历所有D节点的邻居节点(即CE),并计算每个邻居节点距离起点D的距离(最近节点的距离+邻居节点的距离和当前该邻居节点距起点的距离,两者取小值),更新为距离起点更小的值,放入距离容器dis中;
  5. 同时距离若更小,则在路径记录容器pre更新邻居节点和当前节点的路径关系(距离更小才更新);
  6. 同时距离若更小,则将更新距离后的邻居节点放入排序容器pq中(距离更小才更新);
  7. 然后再从排序容器pq中选出距离起点最近的点,重复步骤3-7
  8. 知道寻找出目标节点或pq为空。

三、模拟流程

四、C++代码示例

#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <climits>

struct Node {
    std::string name;
    std::unordered_map<std::string, int> neighbors;
    Node(std::string nm): name(nm) {};
    Node(std::string nm, std::unordered_map<std::string, int> nbhd): name(nm), neighbors(nbhd) {};
};

// 初始化节点
std::vector<Node*> initialize_nodes() {
    std::vector<Node*> vec;
    vec.push_back(new Node("A", {{"B", 12}, {"F", 16}, {"G", 14}}));
    vec.push_back(new Node("B", {{"A", 12}, {"F", 7}, {"C", 10}}));
    vec.push_back(new Node("C", {{"B", 10}, {"F", 6}, {"E", 5}, {"D", 3}}));
    vec.push_back(new Node("D", {{"C", 3}, {"E", 4}}));
    vec.push_back(new Node("E", {{"G", 8}, {"F", 2}, {"C", 5}, {"D", 4}}));
    vec.push_back(new Node("F", {{"G", 9}, {"A", 16}, {"B", 7}, {"C", 6}, {"E", 2}}));
    vec.push_back(new Node("G", {{"A", 14}, {"F", 9}, {"E", 8}}));
    return vec;
};

// 清理内存防止泄露
void cleaup_nodes(std::vector<Node*> nodes){
    if (nodes.empty())
        return;
    for (auto node : nodes) {
        delete node;
    }
};

// 寻找节点是否存在
Node* find_node(const std::vector<Node*>& nodes, const std::string& name) {
    for (auto node : nodes) {
        if (node->name == name) {
            return node;
        }
    }
    return nullptr;
};

void dijkstra(const std::vector<Node*>& nodes, const std::string& start, const std::string& target) {
    std::unordered_map<std::string, int> distances; // 距离起点的距离
    std::unordered_map<std::string, std::string> previous; 
    auto cmp = [&](const std::pair<int, std::string>& a, const std::pair<int, std::string>& b) {
        return a.first > b.first;
    };
    std::priority_queue<std::pair<int, std::string>, std::vector<std::pair<int, std::string>>, decltype(cmp)> pq(cmp);// 优先队列
    // 默认每个点距离起点无穷远
    for (const auto& node : nodes) {
        distances[node->name] = INT_MAX;
    }
    // 起点距离为0
    distances[start] = 0;
    pq.push({0, start});

    while (!pq.empty()) {
        // 选取最短的路径节点
        auto [current_distance, current_name] = pq.top();
        pq.pop();
        // 找到则直接退出循环
        if (current_name == target) 
            break;
        Node* current_node = find_node(nodes, current_name);
        if (!current_node) 
            continue;
        for (const auto& [neighbor_name, weight] : current_node->neighbors) {
            int new_distance = current_distance + weight; // 更新其邻居点到起点的距离
            if (new_distance < distances[neighbor_name]) { // 如果这条路比之前的更短
                distances[neighbor_name] = new_distance; // 更新邻居节点到起点的距离
                previous[neighbor_name] = current_name; // 更新父节点
                pq.push({new_distance, neighbor_name}); // 把更近的路径塞入队列中自动排序
            }
        }
    }
    std::vector<std::string> path;
    for (std::string at = target; at != ""; at = previous[at]) {
        path.push_back(at);
        if (at == start) 
            break;
    }
    std::reverse(path.begin(), path.end());
    // 打印输出结果
    if (path.front() == start) {
        std::cout << "从" << start << "到" << target << "的最短路径: ";
        for (const auto& name : path) {
            if (name == start){
                std::cout << name;
            }else{
                std::cout << "-->" << name ;
            }
        }
        std::cout << "\n总距离: " << distances[target] << std::endl;
    } else {
        std::cout << "无路径从" << start << "到" << target << std::endl;
    }
}

int main() {
    std::vector<Node*> nodes = initialize_nodes();
    dijkstra(nodes, "D", "A");
    cleaup_nodes(nodes);
    return 0;
}

参考链接:

(1)Dijkstra算法详解-CSDN博客

  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值