剑指offer学习笔记——面试题27:二叉搜索树与双向链表

本文介绍如何将二叉搜索树转换为排序的双向链表,提供三种不同的实现方法,包括借助额外空间的方案、中序遍历同时转换链表的方法及非递归的中序遍历实现。

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};

解题思路:

简单的来讲,可以考虑成相当于是先找到二叉树的中序排列,然后将这个排列的顺序从前往后串为一个双向链表即可!

方案一:

跟着这种思路,可以得到第一种解决方案,借助额外空间O(n)。

    vector<TreeNode*> mvTree;
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)
            return NULL;
        InorderTrans(pRootOfTree);
        if(mvTree.size()==1)
            return pRootOfTree;
        for(int i=0;i<mvTree.size();i++)   //遍历中序遍历,然后串成链表
        {
            if(!i)
            {
                mvTree[0]->left = NULL;
                mvTree[0]->right = mvTree[1];
                continue;
            }
            mvTree[i]->left = mvTree[i-1];
            if(i!=mvTree.size()-1)
                mvTree[i]->right = mvTree[i+1];
            else
                mvTree[i]->right = NULL;
        }
        return mvTree[0];
    }
    void InorderTrans(TreeNode* pRoot)
    {
        if(pRoot==NULL)
            return;
        InorderTrans(pRoot->left);
        mvTree.push_back(pRoot);    //得到中序遍历
        InorderTrans(pRoot->right);
    }

方案二:

就是按照上面中序的思路,不用先得到中序遍历。而是在中序遍历的同时完成链表改造!!!那么这里的重点就是如何记录链表中最后一个元素的问题了!!!请看下面代码。注意二重指针的使用

   TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)
            return NULL;
        TreeNode* LastNodeinList = NULL;    //设置一个指针,记录链表中最后一个元素
        Trans(pRootOfTree,&LastNodeinList);
        while(LastNodeinList!=NULL&&LastNodeinList->left!=NULL)   //从后往前,找到链表的头
            LastNodeinList = LastNodeinList->left;
        return LastNodeinList;
    }
    //递归版本
    void Trans(TreeNode* pRoot,TreeNode **pLast)   //注意,一定要使用二维指针。因为我需要改变一维指针的值,只能使用二维指针。
    {                                              //如果有引用就方便多了,但是指针没有引用
        if(pRoot==NULL)
            return;
        Trans(pRoot->left,pLast);
        pRoot->left = *pLast;        //当前节点的前序指向链表的最后元素   //中序遍历同时需要信息的操作,将当前节点左指针指向链表末尾,链表末尾右指针指向当前指针   
        if(*pLast!=NULL)             //链表最后元素的后续指向当前节点
            (*pLast)->right = pRoot;
        *pLast = pRoot;              //当前节点变为链表最后的元素
        Trans(pRoot->right,pLast);
    }

方案三:

可以看做是方案二的拓展,即不使用递归的方式进行二叉树中序遍历,请看下面代码。

    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)
            return NULL;
        TreeNode* LastNodeinList = NULL;
        TreeNode* pNode = pRootOfTree;
        stack<TreeNode*> s;             //使用栈来模拟递归的调用
        while(pNode!=NULL||!s.empty())
        {
            while(pNode!=NULL)
            {
                s.push(pNode);
                pNode = pNode->left;
            }
            if(!s.empty())
            {
                pNode = s.top();                //中序遍历在出栈的时候进行操作
                s.pop();
                pNode->left = LastNodeinList;
                if(LastNodeinList)
                    LastNodeinList->right = pNode;
                LastNodeinList = pNode;
                pNode = pNode->right;
            }
        }
        while(LastNodeinList!=NULL&&LastNodeinList->left!=NULL)
            LastNodeinList = LastNodeinList->left;
        return  LastNodeinList;
    }
源码链接: https://pan.quark.cn/s/7b9e1590db2e 在本计划中,我们聚焦于一个基于数字逻辑的药片装瓶系统的构建,这构成了北京邮电大学(北邮)在小学期内向学生提供的一次课程设计课题。该系统致力于模拟实际药品包装的操作流程,借助电子操控和自动化技术达成药片的高效且精准的装瓶目标。以下是对该系统设计所涉及的关键知识领域的详尽阐述: 1. **数字逻辑**:数字逻辑是电子工程领域的核心学科,主要探究如何运用二进制数字进行信息的表征处理。在此项目中,数字逻辑用于构建和实现系统的控制机制,诸如计数器、编码器、解码器、触发器等,旨在保障药片装瓶过程的精确调控。 2. **硬件电路构建**:系统可能整合微控制器、传感器、执行机构等硬件单元。例如,微控制器作为系统的心脏,负责接收输入信号,处理数据,并指挥执行机构执行药片装填。传感器负责监测药片的数量和瓶装进度,而执行机构如电机则负责实际完成装瓶动作。 3. **计数器**:在药片装瓶的操作过程中,计数器用于追踪已装入瓶子的药片总数,确保达到预设的剂量标准。这可能需要设计同步计数器或异步计数器,以实现精确计数并触发装瓶操作。 4. **编码解码**:编码器将特定的信息(例如药片种类或剂量)转化为二进制编码,便于硬件设备进行处理;解码器则将这些编码解读为可执行的操作,如切换装瓶路径或启动封盖流程。 5. **触发器**:在系统中,触发器可用于在特定条件达成时启动或中止某个操作,例如当瓶子达到满载时关闭装填机制。 6. **传感器技术**:可能包含重量传感器、光电传感器或机械触碰开关,用于识别瓶子的存在、位置以及药片的数量。这些传感器的精确度直接关联到整个系统的性能水平。 7. **控制算法**...
内容概要:本文针对孤岛微电网在遭受拒绝服务(DoS)攻击下的安全稳定运行问题,提出了一种基于混合系统理论的弹性二次控制策略,创新性地将动态事件触发机制DoS攻击防御进行协同设计。该方法在保障微电网电压、频率恢复及有功功率精确均分的同时,有效应对通信链路被恶意阻塞的安全威胁,实现了控制性能通信资源利用效率的双重优化。通过Simulink仿真平台Matlab代码实现,验证了所提策略在复杂网络攻击场景下的鲁棒性有效性,深入分析了系统稳定性条件及攻击容忍边界,为电力信息物理系统(CPS)在面临网络安全挑战时的可靠控制提供了理论依据和技术路径。; 适合人群:具备电力系统自动化、分布式控制或网络安全等相关专业背景,熟悉Matlab/Simulink仿真环境,从事微电网控制、信息物理系统安全或弹性控制研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 提升高比例分布式能源接入背景下孤岛微电网在通信受限网络攻击耦合场景下的运行可靠性弹性恢复能力;② 实现低通信开销下的分布式协同控制,优化资源利用并增强系统抗干扰性能;③ 为电力系统中安全-控制联合设计提供可复现的仿真模型技术方案,推动安全防护从被动响应向主动容忍转变。; 阅读建议:读者应结合文中提供的Matlab代码Simulink模型开展仿真实验,重点理解动态事件触发机制的设计原理及其混合系统稳定性分析的融合方法,建议延伸学习DoS攻击建模、弹性控制理论及相关安全性证明技术,以全面掌握该协同设计框架的核心思想实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值