目录
[1. 数据结构初始化](#1. 数据结构初始化)
[2. 主循环过程](#2. 主循环过程)
一、算法概述
Dijkstra算法是荷兰计算机科学家艾兹赫尔·戴克斯特拉 于1956年提出的,用于解决带非负权值的有向或无向图中的单源最短路径问题 。它的核心思想是贪心策略:每次从未确定最短路径的节点中,选择距离起点最近的节点,然后更新其相邻节点的距离。
二、算法步骤详解
1. 数据结构初始化
创建三个数据结构:
dist[]:记录从起点到每个节点的当前最短距离,起点设为0,其他设为无穷大(∞)
visited[]:标记节点是否已确定最短路径
prev[]:记录最短路径上的前驱节点,用于重建路径
2. 主循环过程
重复以下步骤直到所有节点都被访问:
从未访问节点 中选择dist值最小 的节点
u将
u标记为已访问对
u的每个邻居节点v(且v未访问):
计算新的距离:
new_dist = dist[u] + weight(u, v)如果
new_dist < dist[v]:
更新
dist[v] = new_dist更新
prev[v] = u
三、具体示例
考虑以下带权图(起点为A):
A
/ \
4 2
/ \
B---1---C
\ /
5 8
\ /
D
执行过程:
| 步骤 | 当前节点 | 已访问节点 | 距离数组dist (A,B,C,D) | 说明 |
|---|---|---|---|---|
| 初始化 | - | {} | [0, ∞, ∞, ∞] | 起点A距离为0 |
| 1 | A | {A} | [0, 4, 2, ∞] | 更新B(4), C(2) |
| 2 | C | {A,C} | [0, 3, 2, 10] | 通过C到B更短: 2+1=3 |
| 3 | B | {A,B,C} | [0, 3, 2, 8] | 通过B到D: 3+5=8 |
| 4 | D | {A,B,C,D} | [0, 3, 2, 8] | 完成 |
最终最短路径:
-
A→C: 2
-
A→B: 3 (路径: A→C→B)
-
A→D: 8 (路径: A→C→B→D)
四、算法实现(MATLAB)
%% ==================== 主程序:Dijkstra算法演示 ====================
clear; clc; close all;
fprintf('========== Dijkstra算法路径规划演示 ==========\n');
%% 1. 创建网格地图
fprintf('1. 创建20x20网格地图...\n');
map_size = 20;
grid_map = zeros(map_size, map_size);
% 添加障碍物(墙)
grid_map(8, 3:18) = 1; % 水平墙
grid_map(5:15, 10) = 1; % 垂直墙
% 添加随机障碍物
rng(42); % 固定随机种子
num_obstacles = 30;
for i = 1:num_obstacles
r = randi([1, map_size]);
c = randi([1, map_size]);
grid_map(r, c) = 1;
end
% 设置起点和终点
start_pos = [2, 2];
goal_pos = [18, 18];
grid_map(start_pos(1), start_pos(2)) = 0; % 确保起点空闲
grid_map(goal_pos(1), goal_pos(2)) = 0; % 确保终点空闲
fprintf(' 起点: (%d, %d)\n', start_pos(1), start_pos(2));
fprintf(' 终点: (%d, %d)\n', goal_pos(1), goal_pos(2));
%% 2. 运行Dijkstra算法
fprintf('\n2. 运行Dijkstra算法...\n');
tic;
[path, distance_map] = dijkstra_grid_planner(grid_map, start_pos, goal_pos);
plan_time = toc; % 记录规划时间
fprintf(' 规划完成!耗时: %.4f秒\n', plan_time);
%% 3. 可视化结果
fprintf('\n3. 可视化结果...\n');
% 将plan_time作为额外参数传递给可视化函数
visualize_results(grid_map, start_pos, goal_pos, path, distance_map, plan_time);
%% ==================== 核心算法函数 ====================
function [path, distance_map] = dijkstra_grid_planner(grid_map, start_pos, goal_pos)
% Dijkstra网格路径规划器
% 输入:grid_map - 网格地图(0=空闲,1=障碍物)
% start_pos - 起点坐标 [行, 列]
% goal_pos - 终点坐标 [行, 列]
% 输出:path - 路径坐标序列
% distance_map - 距离地图
[rows, cols] = size(grid_map);
% 将坐标转换为节点编号
start_node = pos2node(start_pos, cols);
goal_node = pos2node(goal_pos, cols);
% 初始化数据结构
distances = inf(rows*cols, 1); % 距离数组
visited = false(rows*cols, 1); % 访问标记
prev = zeros(rows*cols, 1); % 前驱节点
distances(start_node) = 0; % 起点距离为0
% 定义4个移动方向(上、下、左、右)
dirs = [-1, 0; 1, 0; 0, -1; 0, 1];
% 主循环
for i = 1:rows*cols
% 找到未访问节点中距离最小的节点
min_dist = inf;
current_node = -1;
for node = 1:length(distances)
if ~visited(node) && distances(node) < min_dist
min_dist = distances(node);
current_node = node;
end
end
% 如果没有可达节点或到达目标,结束
if current_node == -1 || current_node == goal_node
break;
end
visited(current_node) = true;
% 获取当前节点的坐标
[r, c] = node2pos(current_node, cols);
% 检查4个邻居方向
for d = 1:4
nr = r + dirs(d, 1);
nc = c + dirs(d, 2);
% 检查边界和障碍物
if nr >= 1 && nr <= rows && nc >= 1 && nc <= cols
if grid_map(nr, nc) == 0
neighbor_node = pos2node([nr, nc], cols);
if ~visited(neighbor_node)
new_dist = distances(current_node) + 1; % 每步代价为1
if new_dist < distances(neighbor_node)
distances(neighbor_node) = new_dist;
prev(neighbor_node) = current_node;
end
end
end
end
end
end
% 重建路径
if distances(goal_node) < inf
path_nodes = reconstruct_path(prev, start_node, goal_node);
% 将节点路径转换为坐标
path = zeros(length(path_nodes), 2);
for i = 1:length(path_nodes)
[r, c] = node2pos(path_nodes(i), cols);
path(i, :) = [r, c];
end
else
path = [];
fprintf(' 警告:找不到可行路径!\n');
end
% 生成距离地图(将Inf替换为NaN以便可视化)
distance_map = reshape(distances, [rows, cols]);
distance_map(distance_map == inf) = NaN;
end
%% ==================== 工具函数 ====================
function node = pos2node(pos, cols)
% 坐标转换为节点编号
node = (pos(1)-1) * cols + pos(2);
end
function [r, c] = node2pos(node, cols)
% 节点编号转换为坐标
r = floor((node-1) / cols) + 1;
c = mod(node-1, cols) + 1;
end
function path_nodes = reconstruct_path(prev, start_node, goal_node)
% 重建路径节点序列
path_nodes = [];
current = goal_node;
while current ~= 0
path_nodes = [current, path_nodes];
current = prev(current);
end
% 验证路径有效性
if isempty(path_nodes) || path_nodes(1) ~= start_node
path_nodes = [];
end
end
%% ==================== 可视化函数 ====================
function visualize_results(grid_map, start_pos, goal_pos, path, distance_map, plan_time)
% 创建可视化窗口
figure('Position', [100, 100, 1200, 400]);
% 子图1:原始地图和路径
subplot(1, 3, 1);
imagesc(grid_map);
colormap(gca, [1 1 1; 0.4 0.4 0.4]); % 白色=空闲,深灰色=障碍物
hold on;
% 标记起点和终点
plot(start_pos(2), start_pos(1), 'gs', 'MarkerSize', 12, 'MarkerFaceColor', 'g', 'LineWidth', 2);
plot(goal_pos(2), goal_pos(1), 'rs', 'MarkerSize', 12, 'MarkerFaceColor', 'r', 'LineWidth', 2);
% 绘制路径
if ~isempty(path)
plot(path(:,2), path(:,1), 'b-', 'LineWidth', 2);
plot(path(:,2), path(:,1), 'bo', 'MarkerSize', 6, 'MarkerFaceColor', 'b');
fprintf(' 路径步数: %d\n', size(path, 1));
end
axis equal tight;
grid on;
set(gca, 'YDir', 'reverse');
xlabel('X (列)', 'FontSize', 10);
ylabel('Y (行)', 'FontSize', 10);
title('Dijkstra路径规划结果', 'FontSize', 12, 'FontWeight', 'bold');
legend({'起点', '终点', '路径'}, 'Location', 'best');
% 子图2:距离地图
subplot(1, 3, 2);
% 处理NaN值用于可视化
dist_plot = distance_map;
dist_plot(isnan(dist_plot)) = max(dist_plot(~isnan(dist_plot))) + 1;
imagesc(dist_plot);
colormap(gca, 'hot');
colorbar;
hold on;
% 标记起点和终点
plot(start_pos(2), start_pos(1), 'gs', 'MarkerSize', 12, 'MarkerFaceColor', 'g', 'LineWidth', 2);
plot(goal_pos(2), goal_pos(1), 'rs', 'MarkerSize', 12, 'MarkerFaceColor', 'r', 'LineWidth', 2);
if ~isempty(path)
plot(path(:,2), path(:,1), 'c-', 'LineWidth', 2);
end
axis equal tight;
set(gca, 'YDir', 'reverse');
xlabel('X (列)', 'FontSize', 10);
ylabel('Y (行)', 'FontSize', 10);
title('距离地图(起点到各点的最短距离)', 'FontSize', 12, 'FontWeight', 'bold');
% 子图3:简化示例演示Dijkstra算法原理
subplot(1, 3, 3);
% 创建一个简单的5x5示例
demo_map = zeros(5, 5);
demo_map(3, 2:4) = 1; % 一行障碍物
demo_start = [1, 1];
demo_goal = [5, 5];
% 运行简化版的Dijkstra
[demo_path, demo_dist] = simple_dijkstra_demo(demo_map, demo_start, demo_goal);
% 绘制距离场和路径
imagesc(demo_dist);
colormap(gca, 'cool');
colorbar;
hold on;
% 绘制障碍物
[obs_r, obs_c] = find(demo_map == 1);
plot(obs_c, obs_r, 'ks', 'MarkerSize', 40, 'MarkerFaceColor', 'k', 'LineWidth', 2);
% 绘制路径
if ~isempty(demo_path)
plot(demo_path(:,2), demo_path(:,1), 'y-', 'LineWidth', 3);
end
% 绘制起点和终点
plot(demo_start(2), demo_start(1), 'gs', 'MarkerSize', 25, 'MarkerFaceColor', 'g', 'LineWidth', 2);
plot(demo_goal(2), demo_goal(1), 'rs', 'MarkerSize', 25, 'MarkerFaceColor', 'r', 'LineWidth', 2);
% 标注距离值
[rows, cols] = size(demo_map);
for r = 1:rows
for c = 1:cols
if demo_map(r, c) == 0
dist_val = demo_dist(r, c);
if ~isnan(dist_val)
text(c, r, sprintf('%.0f', dist_val), ...
'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'middle', ...
'FontSize', 10, 'FontWeight', 'bold', ...
'Color', 'white');
else
text(c, r, '∞', ...
'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'middle', ...
'FontSize', 10, 'FontWeight', 'bold', ...
'Color', 'white');
end
end
end
end
axis equal tight;
set(gca, 'YDir', 'reverse');
xlabel('X', 'FontSize', 10);
ylabel('Y', 'FontSize', 10);
title('Dijkstra算法演示', 'FontSize', 12, 'FontWeight', 'bold');
fprintf(' 可视化完成!\n');
fprintf('\n========== 程序执行完成 ==========\n\n');
% 显示结果总结
fprintf('结果总结:\n');
fprintf(' 地图大小: %dx%d\n', size(grid_map, 1), size(grid_map, 2));
fprintf(' 障碍物比例: %.1f%%\n', 100*sum(grid_map(:))/numel(grid_map));
fprintf(' 规划时间: %.4f秒\n', plan_time);
if ~isempty(path)
manhattan_dist = abs(start_pos(1)-goal_pos(1)) + abs(start_pos(2)-goal_pos(2));
fprintf(' 最短路径步数: %d\n', size(path, 1));
fprintf(' 曼哈顿距离: %d\n', manhattan_dist);
end
end
%% ==================== 简化演示函数 ====================
function [demo_path, demo_dist] = simple_dijkstra_demo(demo_map, demo_start, demo_goal)
% 简化版的Dijkstra用于演示
[rows, cols] = size(demo_map);
% 初始化
distances = inf(rows, cols);
visited = false(rows, cols);
prev = cell(rows, cols);
distances(demo_start(1), demo_start(2)) = 0;
dirs = [-1, 0; 1, 0; 0, -1; 0, 1];
% 运行Dijkstra
for iter = 1:rows*cols
% 找到最小距离的未访问节点
min_val = inf;
min_pos = [-1, -1];
for r = 1:rows
for c = 1:cols
if ~visited(r, c) && distances(r, c) < min_val && demo_map(r, c) == 0
min_val = distances(r, c);
min_pos = [r, c];
end
end
end
if min_pos(1) == -1
break;
end
r = min_pos(1);
c = min_pos(2);
visited(r, c) = true;
% 检查是否到达目标
if r == demo_goal(1) && c == demo_goal(2)
break;
end
% 更新邻居
for d = 1:4
nr = r + dirs(d, 1);
nc = c + dirs(d, 2);
if nr >= 1 && nr <= rows && nc >= 1 && nc <= cols
if demo_map(nr, nc) == 0 && ~visited(nr, nc)
new_dist = distances(r, c) + 1;
if new_dist < distances(nr, nc)
distances(nr, nc) = new_dist;
prev{nr, nc} = [r, c];
end
end
end
end
end
% 重建路径
demo_path = [];
if distances(demo_goal(1), demo_goal(2)) < inf
current = demo_goal;
while ~isempty(current)
demo_path = [current; demo_path];
current = prev{current(1), current(2)};
end
end
% 处理距离矩阵显示
demo_dist = distances;
demo_dist(isinf(demo_dist)) = NaN;
end
1、命令行信息:
========== Dijkstra算法路径规划演示 ==========
1. 创建20x20网格地图...
起点: (2, 2)
终点: (18, 18)
2. 运行Dijkstra算法...
规划完成!耗时: 0.0072秒
3. 可视化结果...
路径步数: 35
可视化完成!
========== 程序执行完成 ==========
结果总结:
地图大小: 20x20
障碍物比例: 13.5%
规划时间: 0.0072秒
最短路径步数: 35
曼哈顿距离: 32
2、图形窗口
-
左图:地图+路径
-
中图:距离场热力图
-
右图:5x5算法原理演示
