最短路径-Dijkstra算法

简介: 最短路径-Dijkstra算法

Dijkstra算法,又称"迪杰斯特拉算法",是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

算法解析

1: 设置2个顶点集合S,T

S 存储已经找到的最短路径点的距离

T 存储未处理过的顶点

2: 先把起点A存储到T.准备处理

3: 获取到T的起点A,首先起点A到起点A的距离是0,直接存储到S:A=>{length:0,route:A},

4: 然后通过起点,获取起点周围的几个点和距离,例如B距离1,C距离5,D距离3,存储到T

5: 起点到周围的点都是当前的最短路径,直接存储到S:B=>{length:1,route:AB},C=>{length:5,route:AC},以此类推

6: 继续获取周围B,C,D 周围的点和距离,例如B周围点为 E,C 距离为1,1,存储到T

7: 获取到T的E,C,E直接存储,由于C在5的时候已经存储,length为5,而A=>B length为1,B=>C length为 1,1+1< 5,则直接覆盖更新掉之前的C距离,改为:C=>{length:2,route:ABC} (假想情况,为了方便理解更新最短路径),如果长度大于之前的,则不处理该点

8: 继续获取到E,C周围的点.存储到T

9: 如果已经获取到了终点(可以不需要终点,则之前遍历全部点),则不再获取终点周围的点

重复7,8步骤,直到T不存在数据

在这个过程中,可以保证起点到所有点都是最短路径

算法图解过程

例如 10x10 宫格图中:

image.png

以绿色方格为起点,红色为终点,黑色为障碍物.

1: 首先绿色方格距离为0,直接存储,并获取到周围3个点(不考虑斜边和障碍物),存储到T

2: 遍历T的3个点,距离都为1,直接存储

3: 遍历3个点周围的点,存储到T

4: 取出T点的其他待处理点,判断路径长度,如果小于之前存储的,则覆盖更新路径

.

.

.

其他过程略

下图是遍历步骤,颜色渐变代表了遍历的次数不同

image.png

可看出,到红点的路径有多条:

image.png

图中的黄线都代表着到红点可能的遍历情况

代码

php代码实现:

地图抽象类,可自行实现宫格地图,或其他地图.

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/3/15 0015
 * Time: 9:07
 */
namespace Dijkstra;
abstract class MapHandleAbstract
{
    protected $map = \[\];//地图
    protected $start;//起点
    protected $end;//终点
    //abstract public function drawMap();//绘制地图
    abstract public function getAdjacent($coordinates);//获取相邻点
    abstract public function getLength($start,$end);//获取2点的距离
    abstract public function getStart();
    abstract public function setStart($start);
    abstract public function getEnd();
    abstract public function setEnd($end);
}

宫格地图实现类;

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/3/15 0015
 * Time: 9:14
 */
namespace Dijkstra;
class GridMap extends MapHandleAbstract
{
    protected $map = \[\];
    protected $start;
    protected $end;
    protected $x;
    protected $y;
    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
        $this->initMap();
    }
    public function initMap()
    {
        $map = \[\];
        for ($i = 0; $i < $this->x; $i++) {
            for ($j = 0; $j < $this->y; $j++) {
                $map\[$i\]\[$j\] = 0;
            }
        }
        $this->map = $map;
    }
    public function drawMap()
    {
        echo "    0    1    2    3    4    5    6    7    8    9 \\n";
        for ($i = 0; $i < $this->y; $i++) {
            echo "$i ";
            for ($j = 0; $j < $this->x; $j++) {
                echo " \[{$this->map\[$j\]\[$i\]}\] ";
            }
            echo "\\n\\n";
        }
        // TODO: Implement drawMap() method.
    }
    public function getLength($start, $end)
    {
        return abs($start\[0\]-$end\[0\])+abs($start\[1\]-$end\[1\]);
        // TODO: Implement getLength() method.
    }
    /**
     * 获取相邻点
     * getAdjacent
     * @author Tioncico
     * Time: 15:15
     */
    public function getAdjacent($coordinate)
    {
        $data = \[\];
        $map = $this->map;
        //4个相邻点
        if (isset($map\[$coordinate\[0\] - 1\]\[$coordinate\[1\]\]) && $map\[$coordinate\[0\] - 1\]\[$coordinate\[1\]\] !== 'x') {
            $data\[\] = \[$coordinate\[0\] - 1, $coordinate\[1\]\];
        }
        if (isset($map\[$coordinate\[0\] + 1\]\[$coordinate\[1\]\]) && $map\[$coordinate\[0\] + 1\]\[$coordinate\[1\]\] !== 'x') {
            $data\[\] = \[$coordinate\[0\] + 1, $coordinate\[1\]\];
        }
        if (isset($map\[$coordinate\[0\]\]\[$coordinate\[1\] - 1\]) && $map\[$coordinate\[0\]\]\[$coordinate\[1\] - 1\] !== 'x') {
            $data\[\] = \[$coordinate\[0\], $coordinate\[1\] - 1\];
        }
        if (isset($map\[$coordinate\[0\]\]\[$coordinate\[1\] + 1\]) && $map\[$coordinate\[0\]\]\[$coordinate\[1\] + 1\] !== 'x') {
            $data\[\] = \[$coordinate\[0\], $coordinate\[1\] + 1\];
        }
        //斜边暂时不计
        return $data;
    }
    /**
     * @return mixed
     */
    public function getStart()
    {
        return $this->start;
    }
    /**
     * @param mixed $start
     */
    public function setStart($start): void
    {
        $this->map\[$start\[0\]\]\[$start\[1\]\] = 'S';
        $this->start = $start;
    }
    /**
     * @return mixed
     */
    public function getEnd()
    {
        return $this->end;
    }
    /**
     * @param mixed $end
     */
    public function setEnd($end): void
    {
        $this->map\[$end\[0\]\]\[$end\[1\]\] = 'E';
        $this->end = $end;
    }
    public function setHinder($coordinates)
    {
        foreach ($coordinates as $value) {
            $this->map\[$value\[0\]\]\[$this->map\[1\]\] = 'x';
        }
    }
    public function addHinder($coordinate)
    {
        $this->map\[$coordinate\[0\]\]\[$coordinate\[1\]\] = 'x';
    }
}

算法实现类

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/3/1 0001
 * Time: 10:04
 */
namespace Dijkstra;
class Dijkstra
{
    protected $mapHandle = null;
    protected $save = \[\];
    protected $list = \[\];
    public function __construct(MapHandleAbstract $mapHandleClass)
    {
        $this->mapHandle = $mapHandleClass;
    }
    /**
     * 执行
     * exec
     * @param $start
     * @param $end
     * @return array
     * @author Tioncico
     * Time: 9:31
     */
    public function exec($start, $end)
    {
        $this->mapHandle->setStart($start);
        $this->mapHandle->setEnd($end);
        $this->addList($start, 0, \[\]);
        $this->dijkstra($end);
        return $this->save;
    }
    /**
     * 算法
     * dijkstra
     * @param null $end
     * @return array
     * @author Tioncico
     * Time: 9:38
     */
    public function dijkstra($end = null)
    {
        $save = $this->save;
        while ($value = array_shift($this->list)) {
            $endKey = "{$value\[0\]}_{$value\[1\]}";
            //判断是否之前有该点记录,没有则说明该点是未知路线
            //有则判断路线是否最短
            $totalLength = $value\['totalLength'\];
            $length = $value\['length'\];
            $route = $value\['route'\];
            if (!isset($save\[$endKey\])) {
                $save\[$endKey\]\['totalLength'\] = $totalLength + $length;
                $route\[\] = \[$value\[0\],$value\[1\]\];
                $save\[$endKey\]\['route'\] = $route;
                if ($value == $end) {
                    return $save;
                }
                $this->addList($value, $totalLength + $length, $route);
            } else {
                if ($save\[$endKey\]\['totalLength'\] > $totalLength + $length) {
                    $save\[$endKey\]\['totalLength'\] = $totalLength + $length;
                    $route\[\] = \[$value\[0\],$value\[1\]\];
                    $save\[$endKey\]\['route'\] = $route;
                    if ($value == $end) {
                        return $save;
                    }
                    $this->addList($value, $totalLength + $length, $route);
                }
            }
        }
        $this->save = $save;
        return $save;
    }
    public function addList($coordinate, $totalLength, $route)
    {
        //获取起始点的周围点
        $data = $this->mapHandle->getAdjacent($coordinate);
        $list = \[\];
        foreach ($data as $key=>$va) {
            $list\[$key\]\['totalLength'\] = $totalLength;
            $list\[$key\]\['route'\] = $route;
            $list\[$key\]\['length'\] = $this->mapHandle->getLength($coordinate,$va);
            $list\[$key\]\[0\] = $va\[0\];
            $list\[$key\]\[1\] = $va\[1\];
        }
        $this->list = array_merge($this->list, $list);
        return $this->list;
    }
}

调用方法:

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/3/1 0001
 * Time: 10:04
 */
include "./vendor/autoload.php";//自动加载
$map = new \\Dijkstra\\GridMap(10,10);
$map->addHinder(\[5,5\]);
$map->addHinder(\[5,4\]);
$map->addHinder(\[5,3\]);
$map->addHinder(\[4,3\]);
$map->addHinder(\[3,3\]);
$map->addHinder(\[5,6\]);
$map->addHinder(\[5,7\]);
$map->addHinder(\[4,7\]);
$map->addHinder(\[3,7\]);
$map->addHinder(\[2,7\]);
//var_dump($map);
$test = new \\Dijkstra\\Dijkstra($map);
$save = $test->exec(\[4,5\],\[6,5\]);
$map->drawMap();
//var_dump($save);
foreach ($save\['6_5'\]\['route'\] as $value) {
    echo "{$value\[0\]}_{$value\[1\]}\\n";
}

最后附上一张输出图:

image.png

x代表障碍物,S,E分别为起点,终点

下面的输出为路线图

目录
相关文章
|
4月前
|
存储 运维 监控
基于 C# 语言的 Dijkstra 算法在局域网内监控软件件中的优化与实现研究
本文针对局域网监控系统中传统Dijkstra算法的性能瓶颈,提出了一种基于优先队列和邻接表优化的改进方案。通过重构数据结构与计算流程,将时间复杂度从O(V²)降至O((V+E)logV),显著提升大规模网络环境下的计算效率与资源利用率。实验表明,优化后算法在包含1000节点、5000链路的网络中,计算时间缩短37.2%,内存占用减少21.5%。该算法适用于网络拓扑发现、异常流量检测、故障定位及负载均衡优化等场景,为智能化局域网监控提供了有效支持。
100 5
|
1月前
|
机器学习/深度学习 编解码 算法
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
167 4
|
2月前
|
算法 机器人 定位技术
基于机器视觉和Dijkstra算法的平面建筑群地图路线规划matlab仿真
本程序基于机器视觉与Dijkstra算法,实现平面建筑群地图的路径规划。通过MATLAB 2022A读取地图图像,识别障碍物并进行路径搜索,支持鼠标选择起点与终点,最终显示最优路径及长度,适用于智能导航与机器人路径规划场景。
|
12月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
665 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
8月前
|
存储 算法 测试技术
【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)
【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)
|
8月前
|
算法 编译器 C++
【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)
【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)
|
18天前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
130 3
|
23天前
|
存储 编解码 算法
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
|
12天前
|
机器学习/深度学习 算法 数据可视化
基于MVO多元宇宙优化的DBSCAN聚类算法matlab仿真
本程序基于MATLAB实现MVO优化的DBSCAN聚类算法,通过多元宇宙优化自动搜索最优参数Eps与MinPts,提升聚类精度。对比传统DBSCAN,MVO-DBSCAN有效克服参数依赖问题,适应复杂数据分布,增强鲁棒性,适用于非均匀密度数据集的高效聚类分析。
|
12天前
|
开发框架 算法 .NET
基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA
简介:本文介绍基于ADMM的MIMO信号检测算法,结合无穷范数优化与交替方向乘子法,降低计算复杂度并提升检测性能。涵盖MATLAB 2024b实现效果图、核心代码及详细注释,并对比ML、MMSE、ZF、OCD_MMSE与LAMA等算法。重点分析LAMA基于消息传递的低复杂度优势,适用于大规模MIMO系统,为通信系统检测提供理论支持与实践方案。(238字)

热门文章

最新文章

下一篇
oss教程