PHP中实现拓扑算法

PHP实现拓扑排序topological sort算法(附完整源码) 阅读详情

概念

拓扑算法是一个有向无线算法
是一个处理复杂关系的算法

应用场景

A = B+C
B = C+D
C = A+T
这里的值因为计算顺序不同,会导致计算结果不同,而拓扑排序就能解决这个问题,找出先计算那一位

环的概念

拓扑排序中的一个bug
如果
A =B+C
B = C+D
C = A+D
这里A的值会影响C,C会影响A,所以一旦出现这种情况即预示着出现了环,该逻辑有问题

代码示例

//假设数据结构是这样的
public function text(){
        $accounts = [
            ['name' => 'A', 'value' => "C + B"],
            ['name' => 'B', 'value' => "C + D"],
            ['name' => 'C', 'value' => 100],
            ['name' => 'D', 'value' => 100],
            ['name' => 'E', 'value' => "A + B + C"],
        ];

        $initialValues = [
            'C' => 100,
            'D'=> 100,
        ];

$analysister_config_data = $this->calculateAccountBalances($accounts,$initialValues);
return['data'=>$analysister_config_data ];
}




 /**
     * @param $accounts
     * @param $initial_values
     * @return array
     * 用于计算所有所有账户最终余额
     */
    function calculateAccountBalances($accounts, $initialValues) {
        $graph = $this->buildDependencyGraph($accounts);
        $sortedNodes = $this->topologicalSort($graph);

        $balances = $initialValues;
        foreach ($sortedNodes as $node) {
            if (isset($balances[$node])) {
                continue;
            }
            // 获取当前节点的表达式
            $expression = $accounts[array_search($node, array_column($accounts, 'name'))]['value'];
            // 替换表达式中的变量为已知值
            foreach ($balances as $key => $value) {
                $expression = str_replace($key, $value, $expression);
            }
            // 计算表达式的值
            $balances[$node] = eval("return $expression;");
        }

        return $balances;
    }




/**
     * @param $value:当前账户的值,
     * @param $accountValues:一个引用数组,存储已经计算的值避免重复计算
     * @param $accounts:所有账户
     * @return int*
     */
    function parseValue($value, &$accountValues, $accounts, $initialValues) {
        $parts = explode(' ', $value);
        $result = 0;
        $operator = '+';

        foreach ($parts as $part) {
            if ($part === '+' || $part === '-') {
                $operator = $part;
                continue;
            }

            if (ctype_alnum($part)) { // 只处理有效的账户名称
                if (isset($accountValues[$part])) {
                    $value = $accountValues[$part];
                } elseif (isset($initialValues[$part])) {
                    $value = $initialValues[$part];
                    $accountValues[$part] = $value; // 确保将初始值存储到 accountValues 中
                } else {
                    if (isset($accounts[$part])) {
                        $value = $this->parseValue($accounts[$part]['value'], $accountValues, $accounts, $initialValues);
                    } else {
                        echo ("账户没找到 " . $part);
                    }
                }
            } else {
                // 如果 part 是数字,直接使用
                $value = (int)$part;
            }

            if ($operator === '+') {
                $result += $value;
            } else {
                $result -= $value;
            }
        }

        return $result;
    }


 /**
     * @param $accounts
     * @return array
     * 将需要计算的数据生成为依赖关系图
     */
    function buildDependencyGraph($accounts) {
        $graph = [];
        foreach ($accounts as $account) {
            $name = $account['name'];
            if (!isset($graph[$name])) {
                $graph[$name] = [];
            }
            $parts = explode(' ', $account['value']);
            foreach ($parts as $part) {
                if (is_numeric($part)){
                    continue;
                }
                if (ctype_alnum($part) && !in_array($part, ['+', '-'])) {
                    $graph[$name][] = $part;
                    if (!isset($graph[$part])) {
                        $graph[$part] = [];
                    }
                }
            }
        }
        return $graph;
    }

    /**
     * @param $graph 依赖图,是一个二维数组,表示依赖关系
     * @return array
     * 用于对数据排序,按照依赖关系排序
     */
    function topologicalSort($graph) {
        $inDegree = []; // 节点的入度
        $zeroDegree = []; // 入度为0的节点
        $sorted = []; // 拓扑排序结果

        // 初始化所有节点的入度为0
        foreach ($graph as $node => $dependencies) {
            $inDegree[$node] = 0;
        }

        // 计算每个节点的入度
        foreach ($graph as $node => $dependencies) {
            foreach ($dependencies as $dependency) {
                if (ctype_alnum($dependency)) { // 确保只处理有效的账户名称
                    if (!isset($inDegree[$dependency])) {
                        $inDegree[$dependency] = 0; // 确保所有节点都在 inDegree 数组中
                    }
                    $inDegree[$node]++; // 这里应该增加当前节点的入度
                }
            }
        }

        // 找出入度为0的节点
        foreach ($inDegree as $node => $degree) {
            if ($degree == 0) {
                $zeroDegree[] = $node;
            }
        }

        // 进行拓扑排序
        while (!empty($zeroDegree)) {
            $node = array_shift($zeroDegree);
            $sorted[] = $node;


            // 处理当前节点的依赖关系
            foreach ($graph as $currentNode => $dependencies) {
                if (in_array($node, $dependencies)) {
                    $inDegree[$currentNode]--;
                    if ($inDegree[$currentNode] == 0) {
                        $zeroDegree[] = $currentNode;
                    }
                }
            }
        }

        // 检测是否存在环
        if (count($sorted) != count($graph)) {
            echo '存在环,无法进行拓扑排序';
        }
        return $sorted;
    }

PHP实现图的拓扑排序算法​(附完整源码) 阅读详情

相关推荐

PHP实现topological sort拓扑排序算法(附完整源码)

PHP实现topological sort拓扑排序算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 312

拓扑排序算法之php实现

      在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,成为AOV网(Activity On Vertex Network)。所谓拓扑排序,就是对一个有向图构造拓扑序列的过程。       对AOV网进行拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或...

不忘初心,方得始终 720

PHP实现使用kahn实现topological sort拓扑排序算法(附完整源码)

PHP实现使用kahn实现topological sort拓扑排序算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 334

拓扑排序算法(TopologySort)

    拓扑排序算法 适用范围:要求有向图,且有入度为0的节点,且没有环    1.将图中的所有节点全部记录到HashMap,入度为零的节点添加到zeroInQueue    2.建立一个集合用来存放结果    3.从zeroInQueue中弹出一个,遍历她的子节点    4.将其子节点入度减一    5.如果这个子节点的入度为零了,就将其放入到zeroInQueue中图的表示和生成见:点击打开链...

BarryLee的博客 3013

PHP实现Kahn算法( 附完整源码)

PHP实现Kahn算法( 附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 197

PHP实现拓扑排序(附完整源码)

PHP实现拓扑排序(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 234

php 拓扑排序

拓扑排序li z <?php function topological_sort($nodeids, $edges) { $L = $S = $nodes = array(); foreach($nodeids as $id) { $nodes[$id] = array('in'=>array(), 'out'=>array()); ...

weixin_41282397的博客 425

PHP实现Kahn算法(附完整源码)

PHP实现Kahn算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 224

php 拓扑排序,拓扑排序(DFS实现)

1 #include 2 #include 3 #include 4 #include 56 #define MaxVertexNodeNumSize 10007 #define MaxVertexNodeNameSize 10089 structVertexBodyNode10 {11 charVertexName[MaxVertexNodeNameSize];12 intArc...

weixin_30304773的博客 247

手把手教你用Qt和DSP28335实现串口Bootloader,附赠源码和避坑指南

本文详细介绍了如何使用Qt和DSP28335实现串口Bootloader,包括开发环境搭建、通信协议设计、Qt上位机开发、DSP端Bootloader核心实现以及应用程序工程的特殊配置。通过实战案例和源码分享,帮助开发者快速掌握嵌入式固件升级技术,提升工业设备远程升级的效率和可靠性。

weixin_29176179的博客 133

ThinkBook 16p 2024 BIOS降压定频实战:从解锁CFG Lock到AC Loadline调优

高性能笔记本在满载时频繁撞上温度墙,通常源于固件层默认电压冗余过大,而系统级降压工具又受限于CFG Lock锁定。要根治问题,需要从BIOS固件层面理解电压管理机制——AC/DC Loadline参数控制着CPU在不同负载下的电压请求,通过修改这些负载线值可以安全降低电压,解锁CFG Lock后还能让XTU、ThrottleStop等软件调参工具恢复可用。这种BIOS级调优在工程实践中广泛用于改善散热、稳定频率、压降风扇噪音,尤其适用于联想ThinkBook 16p 2024与拯救者Y9000P等采用HX平

weixin_32496547的博客 385

PHP实现拓扑排序topological sort算法(含完整源代码)

拓扑排序(Topological Sort)是一种对有向无环图(DAG, Directed Acyclic Graph)进行排序的算法。在有向图中,每条边都有一个方向,拓扑排序可以将图中的所有节点排成线性序列,使得对于任意的有向边 (u, v),起点 u 在终点 v 之前。以上代码通过构建一个有向图,并使用深度优先搜索(DFS)进行拓扑排序。拓扑排序的时间复杂度为 O(V + E),其中 V 表示图中节点的个数,E 表示图中边的个数。

希望我的博客,能帮上你解决学习中工作中所遇到的问题 5347

Python+OpenCV实现游戏自动刷怪脚本(附完整代码)

本文详细介绍了如何使用Python和OpenCV开发游戏自动刷怪脚本,涵盖环境搭建、图像识别、行为决策引擎及反检测优化等关键技术。通过完整的代码示例,帮助开发者实现从简单脚本到智能自动化系统的升级,提升游戏效率。

weixin_29032489的博客 517

图的拓扑排序

介绍 假设我们有一组任务要完成,并且有些任务要在其它任务完成之后才能开始,所以我们必须非常小心这些任务的执行顺序。 如果这些任务的执行顺序足够简单的话,我们可以用链表来存储它们,这是一个很好的方案,让我们可以准确知道任务的执行顺序。问题是有时候不同任务之间的关系是非常复杂的,有些任务依赖于两个甚至更多的任务,或者反过来很多任务依赖自己。 因此我们不能通过链表或者树的数据结构来对这

yanzhaohandan的专栏 570

英飞凌TC3xx实战:PWM中点触发ADC采集+DMA自动搬运完整配置流程(基于ILLD库)

本文详细介绍了在英飞凌TC3xx系列微控制器上使用ILLD库实现PWM中点触发ADC采集并通过DMA自动搬运数据的完整配置流程。该方案适用于电机控制、电源管理等需要高精度定时采集的场景,通过GTM生成PWM信号、ADC采集和DMA传输实现全硬件自动化流程,显著提升系统效率。

weixin_42536058的博客 527

Win11+VSCode+TeXLive:学术党必备的LaTeX环境配置避坑指南(2024最新版)

本文详细介绍了如何在Windows 11系统下,通过VSCode编辑器与TeXLive发行版配置高效的LaTeX学术写作环境。针对国内用户常见的镜像下载慢、插件配置复杂等问题,提供了优化方案和避坑指南,帮助科研人员和学生快速搭建流畅的学术写作工作流。

plum99的博客 616

什么是拓扑排序?

它能将图中的节点排列成一个线性序列,使得对每一条有向边 (u, v),节点 u 在排序中都出现在节点 v 之前。简单来说,就是把一个复杂的事情分解成若干个小事情,并弄清楚这些小事情之间的依赖关系,然后按顺序一步步完成。它利用了一个重要的事实:在非环有向图中,必定存在一个或多个“入度为0”的节点(即没有其他节点指向它的节点)。我们可以从这些节点开始,逐步删除它们和它们的出边,然后找到新的“入度为0”的节点,重复这个过程,直到所有节点都被删除。这样,我们删除节点的顺序就是一种拓扑排序。

长风破浪会有时的博客 566

AI赋能软件测试:从冒烟测试到全流程智能化的效率革命

软件测试是确保软件质量的关键环节,其核心原理是通过预设用例验证系统功能是否符合预期。传统测试方法依赖人工编写和维护脚本,面临维护成本高、适应性差等挑战。随着人工智能技术的发展,特别是自然语言处理和计算机视觉的成熟,AI为测试领域带来了新的技术价值。通过让AI理解应用界面和业务逻辑,可以实现测试用例的智能生成、自主执行和结果分析,显著提升测试效率和覆盖率。在实际应用场景中,AI驱动的冒烟测试能够动态适应UI变化,自动分析失败日志,将测试人员从重复劳动中解放出来,专注于更复杂的质量策略设计。本文基于AI在冒烟测

weixin_28841265的博客 304

java图的拓扑排序,本周算法:图的拓扑排序,本周算法拓扑排序

本周算法:图的拓扑排序,本周算法拓扑排序介绍假设我们有一组任务要完成,并且有些任务要在其它任务完成之后才能开始,所以我们必须非常小心这些任务的执行顺序。如果这些任务的执行顺序足够简单的话,我们可以用链表来存储它们,这是一个很好的方案,让我们可以准确知道任务的执行顺序。问题是有时候不同任务之间的关系是非常复杂的,有些任务依赖于两个甚至更多的任务,或者反过来很多任务依赖自己。因此我们不能通过链表或者树...

weixin_30220465的博客 200

从 Open SQL JOIN 走向 ABAP CDS Association:把查询写成可复用的数据模型

摘要: 本文通过飞行模型示例,对比了ABAP中三种表关联实现方式:Open SQL JOIN、CDS显式JOIN和CDS Association。重点解析了Association的本质是将表关系声明为数据模型语言,使用时通过路径表达式按需展开为JOIN。文章指出路径表达式在不同位置会默认展开为不同JOIN类型(如SELECT列表默认为LEFT OUTER),并演示了如何用[inner]强制指定INNER JOIN。最后结合S/4HANA实际案例,说明Association通过中心化关系定义和路径复用,能有效

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 377

【30天从零玩转AI应用开发】第16篇:智能体Agent入门——ReAct框架原理+首个会思考、会动手的AI实战

摘要: 本文介绍了AI智能体(Agent)的核心概念及其与普通大模型(LLM)的区别。通过ReAct(Reason+Act)框架,智能体实现了自主思考、调用工具和分步执行的能力。文章详细讲解了LangChain Agent的四大组件,并推荐新手使用ZERO_SHOT_REACT_DESCRIPTION类型。最后提供了一个完整的智能体实战代码示例,该智能体具备数学计算和天气查询功能,能够自主选择工具完成任务,展示了AI从”被动回答“到”主动行动“的关键进化。

在上海谋生的软件喵记录喵生 626
上一篇: thinkphp5使用模型删除与复杂查询EXP
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值