狄克斯特拉算法 - 学习整理
个人整理,原创发布,转载请标注博客来源。https://editor.csdn.net/md/?articleId=102799813
很多时候,总会忽略了一些你认为不需要的知识体系,但最终你发现,你又要花大量的时间去弥补这个空缺。
算法简介
狄克斯特拉算法,用于计算出在非负权重的情况下,图中起点到终点的最短路径......
解决问题
- 从A出发是否存在到达B的路径;
- 从A出发到达B点的最短路径(时间最少或者路径最少);
算法思路
- 找出“最便宜”的节点,即可在最短时间内到达的节点;
- 更新此节点到“邻居”节点的开销,其含义下文案例说明。
- 重复上述过程,直到对图中的所有节点都这样做了;
- 计算最短路径;
案例分析
案例一
图示(MarkDown画的图)
首先列出起点到各相连节点的耗费时间
父节点 节点 耗时 起点 A 6分钟 起点 B 2分钟 … 终点 ∞ 无穷大 获取耗时最短的节点,由上表可以看出是起点->B节点花费时间最少,计算节点B前往各个邻居节点的所需时间,并更新原本需要花费更多的时间的节点:
父节点 节点 耗时 B A 5分钟 (更新耗时) 起点 B 2分钟 B 终点 7 (更新耗时) 此时,B节点添加进已处理的列表中,不再进行处理,现在只剩余A节点到各邻居节点的所需要的耗时,并更新原本需要花费更多的时间的节点。
父节点 节点 耗时 B A 5分钟 起点 B 2分钟 A 终点 6 (更新耗时) 有表格可以看出,最终路径是起点-> B -> A -> 终点,耗时6分钟。
算法编码
/** Dijkstra.cpp** Created on: Oct 21, 2019* Author: kjh*/#include <map>
#include <set>
#include <string>
#include <vector>
#include <iostream>
#include <limits>using std::map;
using std::string;
using std::set;class Dijkstra {public:typedef std::map<std::string, int> KeyValueNode;typedef std::map<std::string, KeyValueNode> GraphMap;void init();void process(const std::string& startKey, const std::string& target);private:std::string getMinCost(KeyValueNode& keyVals);void process_node(const std::string& key, KeyValueNode& keyVals);void print(const std::string& target);private:// for graph.GraphMap _map;// for visited nodestd::set<string> _visited_set;// for parents relationstd::map<string, string> _node_parents;// 存放到各节点需要的最小时间KeyValueNode _cost_path;
};/******************************** start --> A (6)* --> B (2)* B --> A (3)* --> fin(5)* A --> fin (1)******************************/
void Dijkstra::init() {_map.clear();_visited_set.clear();_cost_path.clear();_node_parents.clear();// init graphKeyValueNode start = {{"A", 6}, {"B", 2}};KeyValueNode b = {{"A", 3}, {"FIN", 5}};KeyValueNode a = {{"FIN", 1}};_map = {{"START", start}, {"B", b}, {"A", a}};
}std::string Dijkstra::getMinCost(KeyValueNode& keyVals) {int min_cost = std::numeric_limits<int>::max();string min_key;for (auto& it : keyVals) {if (it.second < min_cost && _visited_set.count(it.first) != 1) {min_cost = it.second;min_key = it.first;}}return min_key;
}void Dijkstra::process(const std::string& startKey, const std::string& target) {// find start key.auto iter = _map.find(startKey);if (iter == _map.end()) {return ;}// 处理起点的邻居节点,讲邻居节点的耗时加入cost_path.for (auto & node :iter->second) {int cost = node.second;_cost_path.insert(node);_node_parents.insert(std::make_pair(node.first, startKey));}// 查找cost最小的节点std::string mini_key = getMinCost(_cost_path);while(!mini_key.empty()) {std::cout << "process node: " << mini_key << std::endl;auto it = _map.find(mini_key);if (it == _map.end()) {break;}// 处理cost最小节点邻居节点,并更新cost_pathprocess_node(mini_key, it->second);_visited_set.insert(mini_key);mini_key = getMinCost(_cost_path);}// 输出结果print(target);
}void Dijkstra::process_node(const std::string& key, KeyValueNode& keyVals) {auto it = _cost_path.find(key);if (it == _cost_path.end()) {return;}int has_cost = it->second;for (auto& node : keyVals) {int cost = node.second;cost = has_cost + cost;auto cit = _cost_path.find(node.first);if (cit == _cost_path.end()) {_cost_path.insert(std::make_pair(node.first, cost));_node_parents.insert(std::make_pair(node.first, key));} else {int old_cost = cit->second;if (cost < old_cost) {_cost_path.erase(cit);_cost_path.insert(std::make_pair(node.first, cost));_node_parents.erase(node.first);_node_parents.insert(std::make_pair(node.first, key));}}}
}void Dijkstra::print(const std::string& target) {auto citer = _node_parents.find(target);if (citer != _node_parents.end()) {std::vector<std::string> path;std::string parents = citer->second;path.push_back(target);while(!parents.empty()) {path.push_back(parents);auto piter = _node_parents.find(parents);if (piter != _node_parents.end()) {parents = piter->second;} else {parents = "";}}int size = path.size();std::cout << "Path : ";for (int i = size -1 ; i >= 0; i--) {std::cout << path[i];if (i > 0) {std::cout << " --> ";}}auto cost_iter = _cost_path.find(target);if (cost_iter != _cost_path.end()) {std::cout << " cost: " << cost_iter->second;}std::cout << std::endl;} else {std::cout << "Does not exists to " << target << " path" << std::endl;}
}int main() {Dijkstra test;test.init();test.process("A", "H");return 0;
}// g++ Dijkstra.cpp -std=c++11
案例二
案例一中选择了最简单的图,案例二将图复杂一步,来说明算法的思想
- 如果使用广度优先算法,可以得出A到H的最短路径为:A–>B–>E–>H
- 图中给每个节点赋予权重值,就可以使用狄克斯特拉算法来求解A到H的权重和值最小的路径。
按照案例一中的步骤,进行分析:
- 取A(起点)到各节点的耗时
父节点 | 节点 | 耗时 |
---|
A | B | 5
A | C | 1
A | H | +∝
- 找出A节点到达各邻居节点中权重最小的节点,此时C节点的权重最小,将C节点邻居节点D、F加入节点图表中
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 |
A | C | 1 | C已处理
A | H | +∝ |
C | D | 6 |
C | F | 7 |
- 在加入C节点的邻居节点后,从最新的列表中找出A到各节点最小权重点,此时B最小;处理B节点的各邻居节点
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 | B已处理
A | C | 1 | C已处理
A | H | +∝ |
C | D | 6 |
C | F | 7 |
B | E | 15 |
- A的相邻节点已经处理完成,此时找最小权重路径,C-D,计算处理相邻节点的耗时,并标记D已处理
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 | B已处理
A | C | 1 | C已处理
A | H | +∝ |
C | D | 6 | D已处理
C | F | 7 |
D | E | 9 |
- 同理处理F
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 | B已处理
A | C | 1 | C已处理
E | H | +∝ |
C | D | 6 | D已处理
C | F | 7 | F已处理
D | E | 9 |
F | G | 9 |
- 同理处理E
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 | B已处理
A | C | 1 | C已处理
E | H | 12 |
C | D | 6 | D已处理
C | F | 7 | F已处理
D | E | 9 | E已处理
F | G | 9 |
- 同理更新G
父节点 | 节点 | 耗时 | 标志 |
---|
A | B | 5 | B已处理
A | C | 1 | C已处理
E | H | 12 |
C | D | 6 | D已处理
C | F | 7 | F已处理
D | E | 9 | E已处理
F | G | 9 | G已处理
经过上述的过程推敲,可以看出,最后一步处理G,其用时没有比之前更小了,固不更新列表值。
有次的出最小权重:12, 路径:A–>C–>D–>E–>H
程序验证:
// 替换案例一中初始化函数,生成新的图void Dijkstra::init() {_map.clear();_visited_set.clear();_cost_path.clear();_node_parents.clear();// init graphKeyValueNode a = {{"B", 5}, {"C", 1}};KeyValueNode b = {{"E", 10}};KeyValueNode c = {{"D", 5}, {"F", 6}};KeyValueNode d = {{"E", 3}};KeyValueNode e = {{"H", 3}};KeyValueNode f = {{"G", 2}};KeyValueNode g = {{"H", 10}};_map = {{"A", a}, {"B", b}, {"C", c}, {"D", d}, {"E", e}, {"F", f}, {"G", g}};
}
- 从案例的图示做为输入编写了算法,即在固定的图规格中寻找消耗最小的路径。
- 转化到工程项目中,可能给出的图会很复杂,需要根据实际的工程问题来解答(狄克斯特拉算法的核心不会变化,我们就需要从具体的问题抽象划分图解)。
- 比如将复杂的问题分解成我们需要的两点间的图。在应用狄克斯特拉算法来解决。
- 上述只是一个解题的思路,具体问题还需要具体对待。
狄克斯特拉算法 - 学习整理相关推荐
- 《算法图解》学习笔记(七):狄克斯特拉算法(附代码)
欢迎关注WX公众号:[程序员管小亮] python学习之路 - 从入门到精通到大师 文章目录 欢迎关注WX公众号:[程序员管小亮] [python学习之路 - 从入门到精通到大师](https://b ...
- 【学习 记录】狄克斯特拉算法 - Java
最近学习<算法图解>一书时,看到狄克斯特拉算法之前没有使用过,在学习后用常用语言Java将算法实现出来以加深印象. 作用 狄克斯特拉算法用于找出最快的路径,而常用的广度优先搜索算法可用于找 ...
- 图解算法学习笔记(七):狄克斯特拉算法
目录 1)使用狄克斯特拉算法 2)术语 3)实现 4)小结 本章内容; 介绍加权图,提高或降低某些边的权重: 介绍狄克斯特拉算法,找出加权图中前往X的最短路径: 介绍图中的环,它导致狄克斯特拉算法不管 ...
- 算法学习之狄克斯特拉算法
加权图 在了解狄克斯特拉算法之前,先介绍一下加权图. 如图,假设你要从起点出发到达终点,如果只考虑换乘少,即最短路径.那么可以使用广度优先搜索算法,该算法我之前简单的写过,链接点这里.但是,现在你要找 ...
- 小白的算法初识课堂(part7)--狄克斯特拉算法
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 狄克斯特拉算法 具体步骤实现 术语 跳蚤市场 具体步骤实现 负权边 python实现 狄克斯特拉算法 在上一个 ...
- 初学狄克斯特拉算法~(待提高)
读书笔记 狄克斯特拉算用来寻找加权图的"最短路径"(不一定是段数最少,我们需要一定的量度,比如说最少花费,最短时间等,bfs只是解决了段数的最短路径问题) 鉴于无向图就是一个环,而 ...
- 算法图解part7:狄克斯特拉算法
算法图解part7:狄克斯特拉(Dijkstra)算法 1.狄克斯特拉算法(Dijkstra's algorithm) 2.术语 3.负权边 4.实现狄克斯特拉算法 4.1 最短路径思路 4.2 py ...
- 狄克斯特拉算法(入门)
狄克斯特拉算法可以找出加权图中前往X的最短路径. 注意: - 其只适用于有向无环图 - 适用于正权边,负权边的将出错(贝尔曼-福德算法适用于负权边) 步骤: 找出当前最"便宜"的节 ...
- 算法(四):图解狄克斯特拉算法
算法简介 狄克斯特拉算法(Dijkstra )用于计算出不存在非负权重的情况下,起点到各个节点的最短距离 可用于解决2类问题: 从A出发是否存在到达B的路径: 从A出发到达B的最短路径(时间最少.或者 ...
最新文章
- 敏捷研发落地之持续集成
- C#之windows桌面软件第九课:汉字串口助手
- linux的strace命令(详解)
- endnotex8与9的区别_下载安装EndnoteX8或EndnoteX9,建立数据库并以自己的名字命名。...
- 计算机程序停止工作怎么办,如何将“某某程序已正常停止工作,请关闭程序”这个提示自动关闭...
- 24V电压TVS二极管选型
- 利用C语言编程输出小写英文字母表的大写形式(以5为间隔)
- 未能解决并且期待解决的第二个诡异事件----HashMap相关方法
- SAP——ABAP报表的一般格式
- 方舟非专用服务器稳定吗,方舟非专用服务器
- OSChina 周二乱弹 —— 春节假期已经完全结束
- 网页设计(三)——JavaScript
- Alpine执行bash
- 图论(图、树基本知识)
- Proteus + μVision Keil单片机仿真教程(一)点亮一个LED
- 电子白板软件使用详解
- Verdi -- 保存调试的所有设置和界面
- webflux - 统一响应 ModifyResponseBodyGatewayFilterFactory
- office共享——多人编辑
- 沈阳航空航天大学计算机考研真题文件模板