最短路径-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分别为起点,终点

下面的输出为路线图

目录
相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
90 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
4月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
4月前
|
自然语言处理 算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
62 0
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
|
4月前
|
算法 定位技术
路径规划算法 - 求解最短路径 - A*(A-Star)算法
路径规划算法 - 求解最短路径 - A*(A-Star)算法
125 0
|
4月前
|
算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
84 0
|
7天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
13天前
|
机器学习/深度学习 算法 Serverless
基于WOA-SVM的乳腺癌数据分类识别算法matlab仿真,对比BP神经网络和SVM
本项目利用鲸鱼优化算法(WOA)优化支持向量机(SVM)参数,针对乳腺癌早期诊断问题,通过MATLAB 2022a实现。核心代码包括参数初始化、目标函数计算、位置更新等步骤,并附有详细中文注释及操作视频。实验结果显示,WOA-SVM在提高分类精度和泛化能力方面表现出色,为乳腺癌的早期诊断提供了有效的技术支持。
|
9天前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
|
6天前
|
算法
基于WOA鲸鱼优化的购售电收益与风险评估算法matlab仿真
本研究提出了一种基于鲸鱼优化算法(WOA)的购售电收益与风险评估算法。通过将售电公司购售电收益风险计算公式作为WOA的目标函数,经过迭代优化计算出最优购电策略。实验结果表明,在迭代次数超过10次后,风险价值收益优化值达到1715.1万元的最大值。WOA还确定了中长期市场、现货市场及可再生能源等不同市场的最优购电量,验证了算法的有效性。核心程序使用MATLAB2022a实现,通过多次迭代优化,实现了售电公司收益最大化和风险最小化的目标。