`

PHP实现二叉树,线索二叉树

阅读更多
<?php
    require 'biTree.php';

    $str = 'ko#be8#tr####acy#####';
   
    $tree = new BiTree($str);
    $tree->createThreadTree();

    echo $tree->threadList() . "\n";从第一个结点开始遍历线索二叉树
    echo $tree->threadListReserv();从最后一个结点开始反向遍历
?>


biTree.php
<?
    /**
     * PHP实现二叉树
     *
     * @author zhaojiangwei
     * @since 2011/10/25 10:32
     */

    //结点类
    class Node{
        private $data = NULL;
        private $left = NULL;
        private $right = NULL;
        private $lTag = 0;
        private $rTag = 0;

        public function Node($data = false){
            $this->data = $data;
        }
       
        //我不喜欢使用魔术方法 
        public function getData(){
            return $this->data;
        }

        public function setData($data){
            $this->data = $data;
        }

        public function getLeft(){
            return $this->left;
        }

        public function setLeft($left){
            $this->left = $left;
        }

        public function getRight(){
            return $this->right;
        }

        public function setRight($right){
            $this->right = $right;
        }

        public function getLTag(){
            return $this->lTag;
        }

        public function setLTag($tag){
            $this->lTag = $tag;
        }

        public function getRTag(){
            return $this->rTag;
        }

        public function setRTag($tag){
            $this->rTag = $tag;
        }
    }

    //线索二叉树类
    class BiTree{
        private $datas = NULL;//要导入的字符串;
        private $root = NULL; //根结点
        private $leafCount = 0;//叶子结点个数
        private $headNode = NULL; //线索二叉树的头结点
        private $preNode = NULL;//遍历线索化二叉树时保存前一个遍历的结点

        public function BiTree($datas){
            is_array($datas) || $datas = str_split($datas);
            $this->datas = $datas; 
            $this->backupData = $this->datas; 
            $this->createTree(TRUE);          
        }

        
        //前序遍历创建树
        //$root 判断是不是要创建根结点
        public function createTree($root = FALSE){
            if(empty($this->datas)) return NULL;
            
            $first = array_shift($this->datas);
            if($first == '#'){
                return NULL;
            }else{
                $node = new Node($first);
                $root && $this->root = $node;                

                $node->setLeft($this->createTree());
                $node->setRight($this->createTree());

                return $node;
            }
        }
    
        //返回二叉树叶子结点的个数
        public function getLeafCount(){
            $this->figureLeafCount($this->root);
            return $this->leafCount; 
        }
    
        private function figureLeafCount($node){
            if($node == NULL)
                return false;

            if($this->checkEmpty($node)){
                $this->leafCount ++;
            }else{
                $this->figureLeafCount($node->getLeft());
                $this->figureLeafCount($node->getRight());
            }
        }
         
        //判断结点是不是叶子结点
        private function checkEmpty($node){
            if($node->getLeft() == NULL && $node->getRight() == NULL){
                return true;
            }

            return false;
        }

        //返回二叉树深度
        public function getDepth(){
            return $this->traversDepth($this->root);
        }
        
        //遍历求二叉树深度
        public function traversDepth($node){
            if($node == NULL){
                return 0;   
            }

            $u = $this->traversDepth($node->getLeft()) + 1;
            $v = $this->traversDepth($node->getRight()) + 1;

            return $u > $v ? $u : $v;
        }
     
        //返回遍历结果,以字符串的形式
        //$order 按遍历形式返回,前中后 
        public function getList($order = 'front'){
            if($this->root == NULL) return NULL;

            $nodeList = array();

            switch ($order){
                case "front":
                    $this->frontList($this->root, $nodeList);
                    break;
                    
                case "middle":
                    $this->middleList($this->root, $nodeList);
                    break;
                
                case "last":
                    $this->lastList($this->root, $nodeList);
                    break;
                     
                default:
                    $this->frontList($this->root, $nodeList);
                    break; 
            }
            
            return implode($nodeList);
        }

        //创建线索二叉树
        public function createThreadTree(){
            $this->headNode = new Node();
            $this->preNode = & $this->headNode;
            $this->headNode->setLTag(0);
            $this->headNode->setLeft($this->root);
            $this->headNode->setRTag(1);
            
            $this->threadTraverse($this->root);

            $this->preNode->setRight($this->headNode);
            $this->preNode->setRTag(1);
            $this->headNode->setRight($this->preNode);
        }
     
        //线索化二叉树
        private function threadTraverse($node){
            if($node != NULL){
                if($node->getLeft() == NULL){
                    $node->setLTag(1);
                    $node->setLeft($this->preNode);
                }else{
                    $this->threadTraverse($node->getLeft());
                }
                
                if($this->preNode != $this->headNode && $this->preNode->getRight() == NULL){
                    $this->preNode->setRTag(1);
                    $this->preNode->setRight($node);
                }
                
                $this->preNode = & $node;//注意传引用
                $this->threadTraverse($node->getRight());
            }
        }

        //从第一个结点遍历中序线索二叉树
        public function threadList(){
            $arr = array();

            for($node = $this->getFirstThreadNode($this->root); $node != $this->headNode; $node = $this->getNextNode($node)){
                $arr[] = $node->getData();
            }

            return implode($arr);
        }

        //从尾结点反向遍历中序线索二叉树
        public function threadListReserv(){
            $arr = array();
            
            for($node = $this->headNode->getRight(); $node != $this->headNode; $node = $this->getPreNode($node)){
                $arr[] = $node->getData(); 
            }

            return implode($arr);
        }

        //返回某个结点的前驱
        public function getPreNode($node){
            if($node->getLTag() == 1){
                return $node->getLeft();
            }else{
                return $this->getLastThreadNode($node->getLeft());
            }
        }

        //返回某个结点的后继
        public function getNextNode($node){
            if($node->getRTag() == 1){
                return $node->getRight();
            }else{
                return $this->getFirstThreadNode($node->getRight());
            }
        }

        //返回中序线索二叉树的第一个结点
        public function getFirstThreadNode($node){
            while($node->getLTag() == 0){
                $node = $node->getLeft();
            }

            return $node;
        }
       
        //返回中序线索二叉树的最后一个结点
        public function getLastThreadNode($node){
            while($node->getRTag() == 0){
                $node = $node->getRight(); 
            }

            return $node;
        }
       

        //前序遍历
        private function frontList($node, & $nodeList){
            if($node !== NULL){
                $nodeList[] = $node->getData();
                $this->frontList($node->getLeft(), $nodeList);
                $this->frontList($node->getRight(), $nodeList);
            }
        }

        //中序遍历
        private function middleList($node, & $nodeList){
            if($node != NULL){
                $this->middleList($node->getLeft(), $nodeList);
                $nodeList[] = $node->getData();
                $this->middleList($node->getRight(), $nodeList);
            }
        }
        
        //后序遍历
        private function lastList($node, & $nodeList){
            if($node != NULL){
                $this->lastList($node->getLeft(), $nodeList);
                $this->lastList($node->getRight(), $nodeList);
                $nodeList[] = $node->getData();
            }
        }

        public function getData(){
            return $this->data;
        }

        public function getRoot(){
            return $this->root;
        }

    }

?>
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    PHP实现的线索二叉树及二叉树遍历方法详解

    另一个是BiTree类,用于实现线索二叉树的相关操作。 BiTree类中主要包含以下方法: 1. 构造函数:接收一个字符串参数,该字符串中的非'#'字符表示节点的值,'#'字符用于标识空节点。将字符串转换为数组后,通过...

    浙江大学2025年DeepSeek的本地化部署与AI通识教育之未来57页.pdf

    浙江大学2025年DeepSeek的本地化部署与AI通识教育之未来57页.pdf

    基于Matlab+YALMIP+CPLEX的社区综合能源系统主从博弈分布式协同优化策略

    内容概要:本文探讨了基于主从博弈理论的社区综合能源系统分布式协同优化运行策略。随着能源市场的变化,传统的集中优化方法已无法满足多主体间的复杂交互需求。文中利用Matlab、YALMIP和CPLEX平台,构建了一主多从的分布式协同优化模型,其中综合能源销售商作为领导者,新能源冷热电联供运营商和负荷聚合商作为跟随者。通过遗传算法和二次规划相结合的方式解决了Stackelberg均衡的唯一性和求解问题,并通过多个算例验证了该策略的有效性。结果显示,该策略显著提高了供能侧的收益和用能侧的消费者剩余。 适合人群:对能源系统优化、博弈论及其应用感兴趣的科研人员和技术开发者。 使用场景及目标:适用于研究和实施社区综合能源系统的分布式协同优化,旨在提高能源系统的经济效益和社会效益。 其他说明:文中提供了详细的模型构建步骤、代码示例和实验结果,有助于理解和复现实验过程。此外,讨论了光伏渗透率对博弈策略的影响,强调了收敛条件设置的重要性,并分享了一些实用的技术技巧。

    nexus-3.77.2-02-java17-win64.zip

    nexus-3.77版本,适用于windows环境下本地仓库环境搭建,支持jdk17以上,支持https访问配置

    matlab-使用可再生能源的能量存储系统

    该MATLAB Simulink模型提供了与太阳能集成的储能系统(ESS)的综合仿真。该模型是为旨在探索、研究或原型可再生能源解决方案的用户设计的。它包括模拟太阳能发电、电池存储和并网或独立系统的能源管理的组件。太阳能电池板的输入电压可以根据用户而改变 特征 太阳能发电:模拟具有不同太阳辐照度的光伏(PV)系统。 两个储能系统的集成:引入两个动态储能系统来储存能量,它们是锂离子电池和超级电容电池。超级电容器电池被引入来处理由可再生能源引起的波动,锂离子电池被用于支持电网 电池储能:为锂离子电池和超级电容电池实施高效的充电和放电机制 能量管理系统(EMS):平衡光伏系统、电池和负载之间的能量流动。 负载动力学:支持可变负载条件,以测试系统的健壮性。 用户友好的设计:模块化和可定制的模型架构,易于适应。 应用程序 可再生能源的电网整合。 离网储能系统的开发。 理解ESS和太阳能概念的教育目的。 可再生能源技术的研究和开发。

    材料科学中COMSOL与Avizo联合仿真的数字岩心流固耦合建模及其应用

    内容概要:本文详细介绍了利用COMSOL Multiphysics和Avizo软件进行数字岩心建模和流固耦合模拟的方法和技术细节。首先阐述了数字岩心的概念及其重要性,接着讲解了如何在COMSOL中构建流固耦合模型,包括定义物理场、设置参数以及生成高质量网格。随后讨论了Avizo在处理CT扫描图像方面的优势,展示了如何通过Python脚本实现图像分割和三维模型生成,并将其与COMSOL结合用于更精准的物理场模拟。最后强调了这种联合仿真技术在地质工程和能源勘探中的广泛应用前景。 适合人群:从事材料科学研究、地质工程、石油天然气勘探等相关领域的研究人员和技术人员。 使用场景及目标:适用于需要深入了解岩石内部流体流动特性和传输性质的研究项目,旨在提升对复杂地质结构的认识并优化资源开采过程。 其他说明:文中提供了大量实用的技术细节和代码片段,帮助读者更好地理解和实施具体的仿真步骤。同时提醒了一些常见的陷阱和解决方案,有助于提高工作效率和准确性。

    基于51单片机protues仿真的水泵效率温差法测量系统(仿真图、源代码、AD原理图)

    基于51单片机protues仿真的水泵效率温差法测量系统(仿真图、源代码、AD原理图) 水泵效率温差法测量系统 主要是用两个E型热电偶测量水泵进出口温差,温差传给单片机(有水泵效率的经验公式)用单片机程序算出效率并显示出来 主要硬件是两个E型热电偶,好像是分别接MAX31855芯片通信到AT89C52,然后通过单片机编程算出效率再显示效率 设置效率的范围 要是超出范围就报警 1、E型热电偶测量水泵进出口温差; 2、MAX31855芯片温度采集; 3、按键设置温度参数; 4、LCD液晶屏显示相关参数和信息; 5、计算显示效率;

    基于TCN时间卷积神经网络的多分类预测:Excel数据驱动的高精度解决方案

    内容概要:本文详细介绍了基于时间卷积神经网络(TCN)的多分类预测方法,旨在提高时间序列数据分类的准确性。首先简述了TCN的基本原理及其相对于传统循环神经网络(如LSTM、GRU)的独特优势,特别是在并行计算和长期依赖处理方面。接着,文章展示了从Excel中读取数据的具体步骤,并进行了必要的数据预处理,如特征缩放和标签编码。随后,构建了一个基于Keras框架的TCN模型,详细解释了每一层的作用以及参数设置的理由。为了确保模型的有效性和泛化能力,文中还讨论了数据集的划分方式、训练技巧(如滑窗划分)、模型评估指标(如混淆矩阵)以及最终的模型部署方法。此外,作者分享了一些实用的经验和技巧,如避免梯度爆炸的方法、调整学习率策略等。 适合人群:对时间序列数据分析感兴趣的初学者和有一定经验的数据科学家,尤其是希望深入了解TCN模型及其应用的人群。 使用场景及目标:本方案适用于各种涉及时间序列分类的任务,如金融市场趋势预测、工业设备故障检测等。目标是在保证高准确度的同时,提供灵活易用的实现方式,使用户能够快速上手并在自己的项目中应用。 其他说明:文中提供的代码片段可以直接运行或稍作修改后应用于不同的数据集。对于想要进一步优化模型性能的研究者来说,文中提到的一些高级技巧(如滑窗划分、自定义损失函数等)也非常有价值。

    ESP32远程OTA升级解决方案:自动回滚与Websocket传输优化

    内容概要:本文介绍了一种针对ESP32设备的改进型OTA(Over-The-Air)固件升级方案。该方案不仅解决了官方OTA示例中存在的问题,如手动模式灵活性差、自动模式易变砖以及错误处理不足,还增加了自动回滚机制、Websocket传输协议、双模切换等功能。文中详细展示了如何通过SPIFFS存储固件MD5值进行校验,确保固件完整性;利用Websocket提高传输效率并实现断点续传;并通过NVS闪存保存启动计数,增强系统的容错能力。此外,作者分享了实际应用案例,如智能家居项目的批量升级和工业设备的稳定性测试。 适合人群:对ESP32有初步了解并希望深入研究OTA升级机制的开发者和技术爱好者。 使用场景及目标:适用于需要频繁更新固件的物联网设备,特别是那些部署于难以物理接触的位置或者对可靠性要求较高的场合。主要目标是提供一种更加稳定、高效的OTA升级方法,减少因升级失败而导致设备无法使用的风险。 其他说明:文中提供了完整的代码片段和配置指导,帮助读者快速理解和应用这一方案。同时强调了在不同网络环境下的适应性和鲁棒性,确保即使在网络不稳定的情况下也能顺利完成升级。

    光子晶体超表面中动量空间动态调节BICs的COMSOL模拟及其应用

    内容概要:本文详细探讨了光子晶体超表面中动量空间动态调节BICs(连续域中的束缚态)的技术和方法。首先介绍了动量空间和BICs的基础概念,解释了BICs作为一种特殊光学模式的独特性质。随后讨论了通过改变几何参数或引入外部激励来动态调节BICs的具体方法,并展示了如何利用COMSOL软件进行模拟。文中提供了具体的COMSOL建模步骤和脚本示例,包括几何模型的创建、材料属性的设置、物理场的选择以及参数化的扫描设置。此外,还分享了一些实际操作中的经验和技巧,如如何处理COMSOL的缓存问题、优化网格划分、监测Q值变化等。最后,强调了这种结合理论与模拟的研究方法在新型光学器件设计和光与物质相互作用新机制探索中的重要性和有效性。 适合人群:从事光子学、光学工程、物理学等相关领域的研究人员和技术人员,尤其是对光子晶体超表面和BICs感兴趣的学者。 使用场景及目标:适用于希望通过理论结合模拟深入理解光子晶体中超表面BICs特性的科研工作者。主要目标是掌握动量空间中动态调节BICs的方法,为设计高性能光学器件提供理论支持和技术手段。 其他说明:文章不仅提供了详细的理论推导和公式解析,还包括了大量的COMSOL建模实例和代码片段,便于读者动手实践。同时,文中提到了许多实际操作中的注意事项和经验教训,有助于提高模拟效率和准确性。

    如何综合性测试一款电源芯片?ASP3605芯片测试报告

    如何综合性测试一款电源芯片?ASP3605芯片测试报告

    SVM-Adaboost多分类预测算法在MATLAB平台上的故障识别与诊断应用

    内容概要:本文介绍了SVM-Adaboost算法及其在MATLAB平台上的实现方法,重点探讨了该算法在多种故障识别场景中的应用。SVM-Adaboost结合了支持向量机的强大分类能力与Adaboost的迭代增强特性,适用于多分类问题。文中详细讲解了轴承故障识别、变压器油气故障识别、输电线路故障区域识别和绝缘子、配网故障识别的具体实现步骤,包括数据读取、预处理、模型训练、预测验证等环节。此外,还提供了具体的MATLAB代码示例,展示了如何通过调整样本权重、选择合适的核函数等方式优化模型性能。 适合人群:具有一定MATLAB编程基础和技术背景的研究人员、工程师,特别是从事机械故障诊断、电力系统维护等相关工作的专业人员。 使用场景及目标:①快速准确地识别机械设备如轴承、变压器等的故障类型;②提高电力系统输电线路故障区域的定位精度;③增强绝缘子、配网故障识别的准确性;④通过优化模型参数,提升故障识别的效率和可靠性。 其他说明:文章强调了SVM-Adaboost算法在处理小样本数据方面的优势,并指出了一些常见的注意事项,如样本类别均衡、核函数选择、Adaboost迭代次数等。同时,提供了实用的代码片段和技巧,帮助读者更好地理解和应用该算法。

    S7-200 Smart PLC用于卷板材生产线及造纸设备的速度与频率同步控制程序解析

    内容概要:本文详细介绍了基于S7-200 Smart PLC的速度与频率同步控制程序,主要用于卷板材生产线和造纸设备。程序通过设置速度同步地址vw10作为基准,利用频率调整系数factor[i]实现1-15回路的频率同步。此外,还支持主从单机微调功能,确保各回路能够精确同步。文中提供了具体的代码示例,解释了如何通过简单逻辑实现多机同步,并强调了微调和异常检测的重要性。对于16-30回路,考虑到设备布局和负载差异,提出了相应的优化建议,如地址映射调整和滤波算法的应用。 适合人群:从事自动化控制系统开发的技术人员,尤其是熟悉PLC编程和变频器应用的专业人士。 使用场景及目标:①帮助技术人员理解和掌握S7-200 Smart PLC在卷板材生产线和造纸设备中的速度与频率同步控制方法;②提供实用的代码示例和技术细节,便于快速部署和调试;③提高生产线的稳定性和效率,降低故障发生率。 其他说明:本文不仅涵盖了基本的同步控制逻辑,还包括了许多实际应用中的经验和技巧,如微调处理、异常检测和滤波算法等,有助于解决实际工程中的常见问题。

    WPF 全局右键上下文菜单样式, 以及命令的绑定MVVM

    windows系统 的右键菜单太丑有没有, 替换自定义的菜单要是应用不到全局,你就可以来看看, 还写了命令绑定, mvvm模式的.示例代码

    -函数复习整理笔记思维导图还是脑图

    学习

    基于梯度下降的改进自适应短时傅里叶变换方法及其在Jupyter Notebook中的应用

    内容概要:本文介绍了基于梯度下降的改进自适应短时傅里叶变换(STFT)方法,并展示了其在Jupyter Notebook中的具体实现。传统的STFT由于固定窗口长度,在处理非平稳信号时存在局限性。改进的方法通过梯度下降策略自适应调整窗口参数,从而提高时频分辨率。文中详细解释了算法的工作原理,包括信号生成、窗函数设计、损失函数选择等方面,并给出了具体的Python代码示例。此外,文章还讨论了该方法在多个领域的广泛应用,如金融时间序列、地震信号、机械振动信号、声发射信号、电压电流信号、语音信号、声信号和生理信号等。 适合人群:从事信号处理、数据分析及相关领域研究的专业人士,尤其是对时频分析感兴趣的科研人员和技术开发者。 使用场景及目标:适用于需要处理非平稳信号的研究和应用场景,旨在提高信号处理的精度和效率。具体目标包括但不限于:改善金融市场的预测能力、提升地震监测系统的准确性、增强机械设备故障诊断的效果、优化语音识别和合成的质量等。 其他说明:该方法不仅限于特定类型的信号,而是可以通过调整参数灵活应用于不同的信号类型。文中提供的代码可以在Jupyter Notebook环境中直接运行,便于实验和验证。

    蓝桥杯python官方省赛模拟题源代码

    蓝桥杯python资源。蓝桥杯python官方省赛模拟题源代码。

    使用遗传算法的示例问题和解决方案

    使用遗传算法的示例问题和解决方案 给定一个目标字符串,目标是从相同长度的随机字符串开始生成目标字符串。在下面的实施中,进行了以下类比 - 字符 A-Z、a-z、0-9 和其他特殊符号被视为基因 由这些字符生成的字符串被视为 chromosome/solution/Individual 适应度分数是特定索引处与目标字符串中的字符不同的字符数。因此,体能值较低的个体被赋予更多的优先权。 // Number of individuals in each generation

    2025.2.8钟阜路走访人员名单.lnk

    2025.2.8钟阜路走访人员名单.lnk

    基于FPGA的OFDM调制解调Verilog实现:IFFT、FFT与Testbench详解

    内容概要:本文详细介绍了如何在FPGA上使用Verilog实现OFDM调制解调系统,特别是IFFT和FFT模块的设计与实现。文章首先解释了OFDM的基本原理,即通过将数据分解为多路低速信号并在各个子载波上调制,利用IFFT生成时域信号。接着深入探讨了IFFT模块的具体实现,包括基2算法的蝶形运算、旋转因子的预存以及定点数处理。对于接收端的FFT模块,则强调了信道相位旋转的处理和循环前缀的去除。此外,文章还讨论了Testbench的设计,如用MATLAB生成测试向量和加入噪声进行鲁棒性测试。最后分享了一些实践经验,如复数乘法的流水线设计、资源优化技巧以及常见错误避免。 适合人群:具备一定FPGA开发经验的工程师和技术爱好者,尤其是对OFDM调制解调感兴趣的读者。 使用场景及目标:适用于希望深入了解FPGA实现OFDM系统的开发者,帮助他们掌握IFFT和FFT模块的关键技术和实现细节,提高系统性能和可靠性。 其他说明:文中提供了详细的代码片段和操作录像,便于读者理解和实践。同时提醒读者注意一些常见的陷阱和优化技巧,确保工程顺利进行。

Global site tag (gtag.js) - Google Analytics