狄克斯特拉(Dijkstra) 算法 php实现

news2024/12/30 3:37:30

《算法图解》中提到的狄克斯特拉算法,用php实现。

一 原理及解释

根据示例图求出起点到终点的最小耗费路径。

因为涉及每条路径的权重,所以这种算法仅适合有向路径。

所谓有向路径,指仅从起点指向终点的路径。

相对的无向路径,指起点和终点互相指向的路径,一般这样的路径不带箭头。

该算法设定每条路径没有权重为负的路径,且没有不可指向终点的路径,所以所有节点都有效。

起点“O”,终点“C”,实例图如下

根据图示,路径0到A耗费1总耗费1记作A<-O:1:1,以此类推B<-O:2:1,选取耗费最小的路径A<-O:1:1,此时O节点遍历完成。

从节点A再次开始C->A:4,总耗费需要加上之前路径的耗费所以C->A:4:5,A节点遍历完成。

剩余B节点未处理,选取B节点开始C->B:1:3,B节点遍历完成。因为总消耗3小于总消耗5,所以选择C->B路径。

因为C节点是终点,不用便利。所以其余节点遍历完成,则C节点处理完成。

最终选择路径O->B->C,总消耗3。

二 处理流程

1、初始化

节点总耗费父节点遍历完成
OFALSEFALSEFALSE
AFALSEFALSEFALSE
BFALSEFALSEFALSE
CFALSEFALSEFALSE

2、选取起点节点O

节点总耗费父节点遍历完成
OFALSEFALSETRUE
A1OFALSE
B2OFALSE
CFALSEFALSEFALSE

下一步,选取耗费最少且未遍历完成的节点,但是要注意耗费的值不能是FALSE。可将耗费中FALSE视为最大。

某些语言中有无穷大的常量关键字,可以直接用大小对比排除未设置耗费数量的节点。

3、选取节点A

节点总耗费父节点遍历完成
OFALSEFALSETRUE
A1OTRUE
B2OFALSE
C4AFALSE

B->A:3:4,原有节点总耗费为2,小于4。所以不采用B->A,即B->A的数据不更新到表中。

下一步,选取耗费最少且未遍历完成的节点

4、选取节点B

节点总耗费父节点遍历完成
OFALSEFALSETRUE
A1OTRUE
B2OTRUE
C3BTRUE

B->C:1:3,原有节点总耗费为4,大于3。所以采用C->B,即C->B的数据更新到表中。

此时除去终点的节点都处理完,代表终点处理完成,即节点C处理完成。

5、处理流程总结

1、初始化表

2、选取起点节点

3、开始首次处理,即是用节点数据更新表数据

4、设置节点处理完成

5、选取耗费最少且未遍历完成的节点

6、重复4、5步操作。当节点为终点节点时推出循环

7、生成结果

三 php实现

//狄克斯特拉(Dijkstra) 算法 实现
class Test
{
    /**
     * $tableitem =['node'=>'','cost'=>'','prev'=>'']
     */
    private $table = []; //计算开销数据
    private $result = []; //结算表
    private $data = [];
    private $start;
    private $end;
    public function __construct($data, $start, $end)
    {
        $this->data = $data;
        $this->start = $start;
        $this->end = $end;
    }

    private function insert_tables($data)
    {
        foreach ($data as $key => $value) {
            $this->insert_table($key);
            if (is_array($value)) {
                $this->insert_tables($value);
            }
        }
    }
    /**
     * 向table加数据
     *
     * @param  [type] $node
     * @return void
     * @author wj
     * @date 2023-10-18
     */
    private function insert_table($node)
    {
        if (!isset($this->table[$node])) {
            $this->table[$node] = [
                'node' => $node,
                'cost' => false,
                'prev' => false,
                'isChecked' => false,
            ];
        }
    }
    /**
     * 改table数据
     *
     * @param  [type] $node
     * @param  [type] $cost
     * @param  [type] $prev
     * @return void
     * @author wj
     * @date 2023-10-18
     */
    private function update_table($node, $cost, $prev)
    {
        $info = $this->table[$node];
        if ($cost < $info['cost'] || false == $info['cost']) {
            $this->table[$node]['cost'] = $cost;
            $this->table[$node]['prev'] = $prev;
        }
    }
    /**
     * 处理节点
     *
     * @param  boolean $node
     * @return void
     * @author wj
     * @date 2023-10-18
     */
    private function deal_node($node = false)
    {
        if (empty($node)) {
            $node = $this->get_need_deal_node();
        }
        if (empty($node) || !isset($this->data[$node])) {
            return false;
        }

        $usedata = $this->data[$node];
        $prev = $node;
        $table_cost = $this->table[$prev]['cost'];
        foreach ($usedata as $key => $cost) {
            $totalcost = $cost + (int) $table_cost;
            $this->update_table($key, $totalcost, $prev);
        }
        $this->table[$node]['isChecked'] = true;
        return true;
    }
    /**
     * 取得最小未处理节点
     *
     * @param  [type] $node
     * @return void
     * @author wj
     * @date 2023-10-18
     */
    private function get_need_deal_node()
    {
        $table = $this->table;
        $min_node = false;
        $cost = false;
        foreach ($table as $key => $value) {
            if ($value['isChecked'] || false === $value['cost']) {
                continue;
            }
            if ($value['cost'] < $cost || false === $cost) {
                $cost = $value['cost']; //最小开销
                $min_node = $key;
            }
        }
        return $min_node;
    }

    /**
     * 设定data 无没用分支 没有负权
     *
     * @param  [type] $data
     * @param  [type] $start
     * @param  [type] $end
     * @return void
     * @author wj
     * @date 2023-10-18
     */
    public function dotest()
    {
        //初始化table;
        $this->insert_tables($this->data);
        $node = $this->start;
        //处理节点
        while ($node) {
            $result = $this->deal_node($node);
            $node = $this->get_need_deal_node();
            if ($node == $this->end) {
                $this->table[$this->end]['isChecked'] = true;
                break;
            }
        }
    }

    public function getresult()
    {
        $end = $this->end;
        $result = [];
        $node = $end;
        while ($node) {
            $nodeinfo = $this->table[$node];
            $result[$nodeinfo['node']] = $nodeinfo;
            $node = $nodeinfo['prev'];
        }
        $result = array_reverse($result);
        $path = implode("->", array_keys($result));
        $lastnode = end($result);
        $cost = $lastnode['cost'];
        $data = [
            'result' => $result,
            'path' => $path,
            'cost' => $cost,
        ];
        return $data;
    }
}
$data = [
    "O" => [
        "A" => 0,
        "B" => 1,
    ],
    "A" => [
        "C" => 1,
        "B" => 2,
    ],
    "B" => [
        "D" => 2,
    ],
    "C" => [
        "D" => 3,
    ],
];
$t = new Test($data, "O", "D");
$t->dotest();
$data = $t->getresult();
var_dump($data);
#执行结果
array(3) {
  'result' =>
  array(3) {
    'O' =>
    array(4) {
      'node' =>
      string(1) "O"
      'cost' =>
      bool(false)
      'prev' =>
      bool(false)
      'isChecked' =>
      bool(true)
    }
    'B' =>
    array(4) {
      'node' =>
      string(1) "B"
      'cost' =>
      int(1)
      'prev' =>
      string(1) "O"
      'isChecked' =>
      bool(true)
    }
    'D' =>
    array(4) {
      'node' =>
      string(1) "D"
      'cost' =>
      int(3)
      'prev' =>
      string(1) "B"
      'isChecked' =>
      bool(true)
    }
  }
  'path' =>
  string(7) "O->B->D"
  'cost' =>
  int(3)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1109744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zookeeper(目前只有安装)

安装 流程 学kafka的时候安装 Apache ZooKeeper 安装地址&#xff1a;https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7-bin.tar.gz 解压 tar -zxvf kafka_2.12-3.0.0.tgz -C /export/server/ 改配置 cd config cp zoo_sample.cfg z…

Harbor 安装部署

Harbor基本介绍 1、Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;Harbor 是一个企业级的 Docker 私有仓库项目。 2、Harbor以 Docker 公司开源的 Registry 为基础&#xff0c;提供了图形管理 UI 、基于角色的访问控制(Role Based AccessControl) 、AD/L…

cppcheck新手指引

文章目录 一、简介功能原理特征 二、安装WindowsLinux 三、使用1、Manual2、Windows gui3、Windows Cli、Linux4、vscode5、严重等级6、常用示例7、Suppressions8、html报告 四、用户是否可以编写检查规则&#xff1f;五、Cppcheck Premium 一、简介 cppcheck 是一个开源的静态…

vue中echart-gl 3D地图纹理实例

1. 安装 npm install echarts npm install echarts-gl2. vue组件 html部分 <template><section class"chartapp"><div class"map-chart" ref"mapChart"></div></section> </template>JS引入 import * as…

MIPS64乘法器模拟实验

目录 忽略溢出的乘法器 溢出提示的乘法器 忽略溢出的乘法器 首先&#xff0c;我们得了解乘法器如何由加法器设计得到&#xff0c;此处&#xff0c;我们以32位乘法为例。 总共分为4步&#xff1a; 1. 测试乘数最低位是否为1&#xff0c;是则给乘积加上被乘数&#xff0…

Linux-Jconsole连接远程服务器

Jconsole连接远程服务器 一、修改jmxremote.password.template文件二、启动jar项目三、jconsole远程连接1、打开的你jconsole2、远程连接 一、修改jmxremote.password.template文件 进去你的/idk/jre/lib/management目录下可以看到jmxremote.password.template文件 修改jmxr…

“智能+”时代,深维智信如何借助阿里云打造AI内容生成系统

云布道师 前言&#xff1a; 随着数字经济的发展&#xff0c;线上数字化远程销售模式越来越成为一种主流&#xff0c;销售流程也演变为线上视频会议、线下拜访等多种方式的结合。根据 Gartner 报告&#xff0c;到 2025 年 60% 的 B2B 销售组织将从基于经验和直觉的销售转变为数…

lazada店铺商品评论数据采集,lazada商品评论数据接口,lazadaAPI接口

lazada店铺商品评论数据可以通过以下步骤进行采集&#xff1a; 注册Lazada开发者账号。首先在Lazada开放平台网站上注册并创建开发者账号&#xff0c;并创建一个应用&#xff0c;获取到所需的App Key和App Secret等信息。设置API密钥和访问令牌。使用获取到的App Key和App Sec…

(python)系统路径和文件操作 —— os和pathlib

文章目录 前言1、遍历目录下的文件 前言 pathlib 和 os 是 Python 中用于处理文件路径和文件系统操作的两个模块。os 模块提供了底层的操作系统相关功能&#xff1b;pathlib 提供了面向对象的路径操作接口。pathlib 模块实际上是在 os 模块的基础上进行了封装和扩展&#xff0…

2023年中国车载导航仪产量、销量及市场规模分析[图]

车载导航仪是一种用于汽车上的电子设备&#xff0c;用于帮助驾驶员找到目的地并规划路线&#xff0c;它通常使用地图软件和GPS定位技术来确定车辆的位置&#xff0c;并提供语音和图形指示&#xff0c;以指导驾驶员前往目的地。 车载导航仪行业分类 资料来源&#xff1a;共研产…

又一个新指标可以写,氧化平衡评分,源自膳食以及生活方式

郑老师统计课程&#xff0c;欢迎点击报名&#xff1a;Nhanes公共数据库挖掘 课程 最近学习文献&#xff0c;发现新指标的使用在越来越NHANES数据库类的文章上占比越来越高。以往的研究证明饮食与生活方式与睡眠质量存在关联&#xff0c;本期我们要学习的文章推出了一个新指标&a…

使用免费SSL证书的好处

在互联网上保护用户隐私和数据安全是至关重要的。SSL证书是一种常见的安全解决方案&#xff0c;用于加密通信并验证网站的真实性。SSL&#xff08;安全套接层&#xff09;证书是一种数字证书&#xff0c;用于建立加密连接&#xff0c;保护数据的机密性和完整性。虽然商业SSL证书…

2023年【氧化工艺】考试报名及氧化工艺考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 氧化工艺考试报名是安全生产模拟考试一点通总题库中生成的一套氧化工艺考试总结&#xff0c;安全生产模拟考试一点通上氧化工艺作业手机同步练习。2023年【氧化工艺】考试报名及氧化工艺考试总结 1、【单选题】 由和O…

解决ConfigurationBuilder未包含“SetBasePath”的定义

在类库文件中使用ConfigurationBuilder读取json文件时提示ConfigurationBuilder未包含“SetBasePath”的定义。 解决方案&#xff1a; 包控制管理器安装这三个包&#xff0c;缺一不可 Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.FileExtensions…

FXL6408UMX一款完全可配置的8位12C控制GPIO扩展器

FXL6408UMX是一款8位I 2 C受控的GPIO扩展器。当配置为输入模式时&#xff0c;FXL6408监控用于数据转换的输入端口&#xff0c;并通过指定/ INT引脚的所有输入可配置上拉或下拉电阻&#xff0c;在漏极开路或非驱动应用场景预偏置输入。当配置为输出模式时&#xff0c; GPIO引脚根…

四元数数学性质、运算规则、线性插值(公式版)

四元数 Q ⟨ x , y , z , w ⟩ Q \langle x, y, z, w \rangle Q⟨x,y,z,w⟩ Q x i y j z k w Q xi yj zk w Qxiyjzkw 1.运算与性质 1)数乘 Q s ⋅ ⟨ x , y , z , w ⟩ ⟨ s ⋅ z , s ⋅ y , s ⋅ z , s ⋅ w ⟩ Q s \cdot \langle x, y, z, w \rangle \langle…

java击球小游戏运行代码

创建一个图形化的小游戏通常需要使用Java图形库&#xff0c;例如Swing或JavaFX。下面是一个使用JavaFX创建的简单的图形化小游戏示例&#xff0c;其中一个小球会在窗口内移动&#xff0c;你需要点击小球以增加得分&#xff1a; import javafx.application.Application; import…

淘宝开放平台 API 获取淘宝天猫店铺订单接口

业务场景&#xff1a;作为全球最大的 B2C 电子商务平台之一&#xff0c;淘宝&#xff08;天猫&#xff09;平台提供了丰富的商品资源&#xff0c;吸引了大量的全球买家和卖家。为了方便开发者接入淘宝平台&#xff0c;淘宝平台提供了丰富的 API 接口&#xff0c;其中商品详情接…

2023年【北京市安全员-A证】试题及解析及北京市安全员-A证证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 北京市安全员-A证试题及解析是安全生产模拟考试一点通总题库中生成的一套北京市安全员-A证证考试&#xff0c;安全生产模拟考试一点通上北京市安全员-A证作业手机同步练习。2023年【北京市安全员-A证】试题及解析及北…

【大数据开发技术】实验06-SequenceFile、元数据操作与MapReduce单词计数

文章目录 SequenceFile、元数据操作与MapReduce单词计数一、实验目标二、实验要求三、实验内容四、实验步骤附&#xff1a;系列文章 SequenceFile、元数据操作与MapReduce单词计数 一、实验目标 熟练掌握hadoop操作指令及HDFS命令行接口掌握HDFS SequenceFile读写操作掌握Map…