当前位置: 首页 > java >正文

二叉树—中序遍历—非递归

 

初始状态

假设当前从根节点 b 开始,此时栈为空 。

第一步:处理根节点 b 的左子树

  • 调用 goAlongLeftBranch 函数,从节点 b 开始,因为 b 有左子树(节点 a ),将 b 入栈,此时栈:[b] ;继续沿着左分支,a 没有左子树了,将 a 入栈 ,此时栈:[a, b] 。
  • 回到主循环,栈非空,执行 x = S.pop() ,a 出栈并访问 a ;然后 x 指向 a 的右子树,a 右子树为空,回到主循环继续判断栈状态。

第二步:处理根节点 b

  • 此时栈顶是 b ,执行 x = S.pop() ,b 出栈并访问 b ;然后 x 指向 b 的右子树(节点 f )。

第三步:处理 b 右子树(以 f 为根的子树 )

  • 调用 goAlongLeftBranch 函数,从节点 f 开始,因为 f 有左子树(节点 d ),将 f 入栈,此时栈:[f] ;继续沿着左分支,d 有左子树(节点 c ),将 d 入栈 ,此时栈:[d, f] ;c 没有左子树了,将 c 入栈 ,此时栈:[c, d, f] 。
  • 回到主循环,栈非空,执行 x = S.pop() ,c 出栈并访问 c ;然后 x 指向 c 的右子树,c 右子树为空,回到主循环继续判断栈状态。

第四步:继续处理 f 左子树剩余部分

  • 此时栈顶是 d ,执行 x = S.pop() ,d 出栈并访问 d ;然后 x 指向 d 的右子树(节点 e )。
  • 将 e 入栈,此时栈:[e, f] ,执行 x = S.pop() ,e 出栈并访问 e ;e 右子树为空,回到主循环继续判断栈状态。

第五步:处理根节点 f

  • 此时栈顶是 f ,执行 x = S.pop() ,f 出栈并访问 f ;然后 x 指向 f 的右子树(节点 g )。
  • 将 g 入栈,此时栈:[g] ,执行 x = S.pop() ,g 出栈并访问 g ;g 右子树为空,此时栈为空,满足 S.empty() 条件,break 跳出循环,中序遍历结束。

 

 

时间复杂度的证明:

 

简要分析:

关键操作包括:入栈( goAlongLeftBranch 函数)和出栈节点访问(主循环)

入栈 

goAlongLeftBranch 函数:沿着二叉树的左分支不断将节点入栈。最坏情况下,二叉树退化为一条单链(eg:所有节点只有左孩子 ),此时对于一个具有 n 个节点的二叉树,调用 goAlongLeftBranch 函数时  需将 n 个节点依次入栈,每次入栈操作可视为 O(1) ,所以单次 goAlongLeftBranch 调用  在最坏情况下的时间复杂度为 Ω(n) 。

出栈及节点访问

主循环中,每次迭代会执行一次出栈并访问出栈节点。每个节点只会入栈一次且出栈一次(每个节点在沿着左分支时入栈,出栈访问后不会再次入栈 )。出栈和访问节点都是O(1) 。由于二叉树共有 n 个节点,所以出栈及节点访问操作的总时间复杂度为 O(n) 。

分摊

虽然单次 goAlongLeftBranch 调用可能花费 Ω(n) 时间(如二叉树为单链时 ),但从整个遍历过程来看,每个节点入栈和出栈操作总共最多各一次。

例如,当沿着左分支集中进行多次入栈(耗时较长 )时,后续这些入栈节点会依次出栈并被访问。把前面集中入栈的较长时间开销分摊到后续这些节点出栈及访问的过程中。从整体 n 个节点的处理来看,平均每个节点的操作时间是常数级别的。所以整个中序遍历算法的时间复杂度为 O(n) 。

 

具体分析:

template <typename T>
static void goAlongLeftBranch( BinNodePosi(T) x, Stack <BinNodePosi(T)> &S ) {while ( x ) { S.push( x ); x = x->lc; } // 反复地入栈,沿左分支深入
}

作用:沿当前节点 x 的左分支不断将节点入栈。每次循环执行 S.push(x)(入栈,时间复杂度为 O(1))和 x=x−>lc(指针移动,时间复杂度为 O(1))。

对于每个节点,它只会从左分支方向被访问一次并入栈。整个二叉树共有 n 个节点,因此所有节点入栈的总次数为 n,总时间复杂度为 O(n)。

 

template <typename T, typename V> 
void travIn_I1( BinNodePosi(T) x, V& visit ) { Stack <BinNodePosi(T) > S; // 辅助栈while ( true ) { // 反复地goAlongLeftBranch( x, S ); // 从当前节点出发,逐批入栈if ( S.empty() ) break; // 直至所有节点处理完毕x = S.pop(); // x的左子树或为空,或已遍历(等效于空),故可以visit( x->data ); // 立即访问之x = x->rc; // 再转向其右子树(可能为空,留意处理手法)}
}

 

出栈x = S.pop() 为出栈,时间复杂度为 O(1)。每个节点入栈后仅出栈一次,总出栈次数为 n,总时间复杂度为 O(n)。

访问节点visit( x->data ) 用于访问节点数据,每个节点仅被访问一次,时间复杂度为 O(1),n 个节点总时间复杂度为 O(n)。

转向右子树x = x->rc 是指针移动,时间复杂度为 O(1)。每个节点处理完后转向右子树(即使右子树为空也会执行一次该操作),总操作次数为 n,总时间复杂度为 O(n)。

虽然 goAlongLeftBranch 函数单次调用可能沿长左链做多次入栈(如树退化为左单链时),但从全局看,每个节点的入栈、出栈、访问及转向右子树操作均为 O(1) 且仅执行一次。

总时间复杂度为各部分时间复杂度之和:O(n)+O(n)+O(n)+O(n)=O(n)。

此二叉树中序遍历代码的时间复杂度为 O(n),每个节点都被且仅被处理一次,所有操作的总耗时与节点数 n 呈线性关系。

 

 

1.入栈

goAlongLeftBranch 函数中 while (x) { S.push(x); x = x->lc; } 会沿左分支将节点入栈。每个节点仅入栈一次,总入栈次数为 n(n 为节点总数),入栈总时间为 O(n)。

2. 外层循环

  • 出栈x = S.pop() 每个节点仅出栈一次,总出栈次数为 n,时间为 O(n)。
  • 访问节点visit(x->data) 每个节点仅访问一次,时间为 O(n)。
  • 转向右子树x = x->rc 每个节点处理后转向右子树(即使为空也执行一次),总操作次数为 n,时间为 O(n)。

虽然有循环嵌套,但每个节点的入栈、出栈、访问、转向右子树操作均为 O(1) 且仅执行一次。所有操作的总时间复杂度为各部分之和:

O(n)(入栈)+O(n)(出栈)+O(n)(访问)+O(n)(转向右子树)=O(n)


外层循环,每次出栈一个节点,处理它的右子树。每个节点出栈一次,访问一次。虽然外层是 while (true),但每次循环都处理一个节点,并且每个节点的入栈和出栈都是一次。

时间复杂度看的是每个操作的总次数。入栈总次数是 n,出栈总次数是 n,每个节点处理一次。所以总的时间复杂度是 O (n)

一句话:循环嵌套看似为n^2,但在while(true)中每个节点只被处理一次,没有重复处理,所以是 O (n)

DSACPP

 

http://www.xdnf.cn/news/4164.html

相关文章:

  • 两数之和(暴力+哈希查找)
  • Linux[Makefile]
  • ffmpeg录音测试
  • 爬虫程序中如何添加异常处理?
  • Vi/Vim 编辑器详细指南
  • Facebook如何运用AI实现元宇宙的无限可能?
  • DC-DC降压型开关电源(Buck Converter)设计中,开关频率(f sw​ )、滤波电感(L)和滤波电容(C out​ )的关系和取舍
  • uniapp 全局混入:监听路由变化,路由变化即执行
  • 嵌入式openharmony标准鸿蒙系统驱动开发基本原理与流程
  • openssl 生成自签名证书实现接口支持https
  • 【coze】手册小助手(提示词、知识库、交互、发布)
  • C++中指针使用详解(4)指针的高级应用汇总
  • 人工智能对人类的影响
  • 【Hive入门】Hive安全管理与权限控制:审计日志全解析,构建完善的操作追踪体系
  • kubeadm部署k8s
  • openwrt 使用quilt 打补丁(patch)
  • 基于图像处理的道路监控与路面障碍检测系统设计与实现 (源码+定制+开发) 图像处理 计算机视觉 道路监控系统 视频帧分析 道路安全监控 城市道路管理
  • 计算机视觉与深度学习 | 基于数字图像处理的裂缝检测与识别系统(matlab代码)
  • 【Python系列】Python 中的 HTTP 请求处理
  • OpenAI的“四面楚歌”:从营利到非营利,一场关于AGI控制权的革命
  • 信息时代的政治重构:网络空间与主权的未来
  • 搭建spark yarn 模式的集群
  • mybatis 的多表查询
  • Nacos源码—4.Nacos集群高可用分析四
  • 【Linux网络】应用层协议HTTP
  • Ubuntu18.04搭建samda服务器
  • ORACLE EBS 12.1 启用https 简单策略
  • 谷歌在即将举行的I/O大会之前,意外泄露了其全新设计语言“Material 3 Expressive”的细节
  • 如何通过外网访问内网?对比5个简单的局域网让互联网连接方案
  • 单应性估计