【C语言】打印二叉树树形(制表符实现,清晰+高拓展)(2022-10-22 更新—偏移量说明)

二叉树-7.1 二叉树序列打印 在前序遍历中,我们每遍历到一个结点,当即把它打印出来,然后把它的左孩子压入栈中,遇到空结点时,把退栈得到栈顶元素x,然后x的右子树按上面做法继续压入栈中。观察递归做法中的前序遍历,可以发现:我们每遍历一个结点,当即打印出该结点,然后以左孩子,右孩子的顺序接着往下递归。一种通用的迭代解法。按照这个顺序,1入栈,2入栈,2出栈并打印,3入栈,3出栈并打印,轮到1时,因为它还有右子树,所以要把3再次入栈,这样就会重复打印3了,所以要使用一个栈打印结点值,除了记录当前正在遍历的结点,还要记录之前已经访问过的结点。 阅读详情


2022-10-22 补充

好久没来 优快云 了,今晚一看发现一些小伙伴反应说看文中的 偏移量 看的很晕(当时自己写比较主观哈哈),秉着要对文章负责的态度,我在这里统一给大家详细解释一下
如果是第一次来的话,可以先去看正文
没想到这么久了还有人看我的文章,挺感动的,先谢谢大家的支持了~

废话不多说,先看画的这张图(相信大家看到图心里应该就有底了)
这张图里边已经基本上把算法的核心全部画出来了,确认根结点的位置是重点(画树枝是次要的)
说明:为了画线比较好看,我把对 x 坐标的减 1 操作放到了第一个偏移量的位置,这样能使得线段对的上每个结点
在这里插入图片描述

首先要解释的就是 偏移参数 以及 三个偏移量 的作用:

  1. tap:这个是父节点传递给子结点的相对偏移量
    如算法中所示,它是直接针对 tap1 的,用于计算父树的偏移量
  2. tap1:也就是图中红色的划线,该偏移我叫做 父树偏移量
    是为了计算当前结点的父节点再整个空间的偏移量,加上这个偏移量,父节点的位置就相当于初始化状态的父节点,它的子结点(当前结点)可以直接基于父节点来计算自己的偏移量
  3. tap2:也就是图中绿色的划线,该偏移我叫做 子树偏移量
    这是在子树为右子树的情况下需要的,前边的 tap1 我们已经确定了以父节点为根的树在空间中的位置,而子结点如果是右子树的话,那么还需要将左子树的位置空出来,tap2 就是干这件事的
  4. tap3:也就是图中橙色的画线,该偏移我叫做 半偏移量
    这是左右子树都需要的,左子节点用 tap1 就可以确定相对位置,而右子节点用 tap1 和 tap2 的和,也就确定了和左子树一样的相对位置(分别使用者两个偏移量,左右子树的状态就相同了,tap3 的规则对他们来说是一样的)
    准确地说,tap3 是树枝的长度,也就是为了下面的树能有空间继续放的下去而需要的偏移量

到这里,大家对几个偏移量的作用应该基本上都清楚了,至于每个偏移量的计算方法,这里我简单说明一下(手动在纸上模拟一遍更好理解哦),这里我顺序倒着解释可能会更好

  1. tap3:首先是 tap3,它的作用就是为下边的树空出位置,计算方法是 2treeDepth-depth-1
    什么意思呢?以上图为例,该树深度为 4,则宽度为 24=16,所以一个子树的宽度应该是 8,也就是24-1
    所以上式的 -1 操作表明了,子树的宽度是父树的一般。再而,每往下一层,子树的宽度都会减半,所以得减去当前深度 depth,所以最终的指数部分就是 treeDepth-depth-1
  2. tap2:然后是 tap2,它的作用是把右子树向右挪出一个左子树的位置
    所以我们需要的,自然就是左子树的宽度啦,由于是在同一层,所以不需要减半也就不用 -1,所以指数部分是 treeDepth-depth,而前边的 right 就好理解了,因为右子树才需要否则置为 0 表示不需要
  3. tap1:再而是 tap1,它的作用是确定父树在整个空间的偏移量
    而该父树的父树可能是左子树也可能是右子树,爷爷也可能是左子树和右子树,这么多情况要怎么确定呢?
    答案就是 tap 偏移量了,由它来记录前边的爸爸爷爷们究竟有多少是右子树,得到一个累计值,然后 tap1 就可以根据这个累计值算出整体在空间的偏移量了!由于是在同一层,所以也不需要 -1
  4. tap:这个在 tap1 已经介绍过了,就是相对偏移量,用来保存该节点的爸爸爷爷到底做了多少次右子树,是一个累计值

至于你们要问,为什么我会知道需要这些偏移量。我只能说,这是一点点调试出来的(无奈)
一开始就是只有 tap3,确定需要为子树空出多少就好了嘛
然后就发现,怎么区分左右子树?!所以就出现了 tap2
最后才发现最致命的一点,一层层的递归下,每棵小树(父节点+子结点)他们分别在空间的哪个位置?所以出现了辅助性的 tap 和用于确定相对位置的 tap1

好了,整一个完整的说明就到这里了
从看到评论和私信,到拿起一年前的代码重新理解(哭),再到捋好思路将说明补充好,已经过去一个半小时了
虽然这对我来说有点花时间(一年过去了,心态也不太一样了)
但我自己清楚在看别人博文看不懂,自己苦苦理解几个小时没出来个结果是多么痛苦(我看别人博文时,对于说的含含糊糊的也有要骂街的冲动2333),所以我也决心一定要把思路讲清楚,让自己成为自己讨厌的人,是很不应该的啊

就到这里啦,今年起来就没写过博客,今天也顺带把手感提上来了,后边看情况再更新吧
看到以前的文章还能对大家有帮助,挺开心的,能帮到你们就好。溜了溜了~(有什么问题可以再评论或者私信我哦)


0. 前言

上 优快云 找了很多份树形代码,一个共通的感觉就是拓展性不够强
比如说树大了节点之间被撑开无法兼容性不好
没有使用树枝连接的画显示稍显混乱,使用斜线当树枝又不好拓展
还有一部分就是代码太冗长看不懂

基于此,我打算用回制表符,力求清晰显示出树形
肝了几个小时的代码,过程中一点一点调出来树形
代码部分也在不断优化,思路在不断的调试中也不断改变
最后总结出一种以绝对偏移量画树形的方法,下边将一一对代码进行解释

1. 效果展示

首先树画出来的效果如下,可以很好兼容各种树形,显示也很清晰
在这里插入图片描述
在这里插入图片描述
拓展性扛扛的完全不用担心
在这里插入图片描述

2. 核心代码及解读

① 核心代码

代码也是简洁 + 清晰

/*
* 递归打印打印出树形
* T		正在打印的树
* depth	目前在打印树的第几层
* right	该子树是否为右子树
* tap	目前子树需要的相对偏移数量
*/
Status Traverse_R(BiTree T, int depth, int right, int tap) {
   
   
	if (T == NULL) return OK;

	// 获取一次树的初始高度,用于计算相对偏移数量
	static int treeDepth = BiTreeDepth(T);
	// 记录当前光标位置,用于在递归中记录当前递归时树的位置
	int x, y;
	// 拆分树,将树的左右子树拆分开来
	BiTree L, R;
	BreakBiTree(T, L, R);

	// 计算父树的偏移量
	int tap1 =
控制台图形化打印二叉树(c/c++) 用c/c++实现的控制台图形化打印二叉树 阅读详情

相关推荐

树状显示二叉树(标准C语言实现)

二叉搜索树的黑框树状显示(标准C语言实现) 最近在用C语言实现平衡二叉搜索树,用了半天时间实现了树的基本功能后,发现我的二叉树打印方法还是停留在简单的逐行打印,此时的效果图如下: 一行的每两个数值分别对应上一行一个数值的左右孩子,用星号表示空。无疑这中表示方法十分鸡肋,利用人工点数的方式确定节点的左右孩子,实在不方便调试和扩展功能,如果节点多了可能还会造成开发者白内障,危害极大。 出于开发效率和...

weixin_40568729的博客 1万+

C语言打印二叉树

打印二叉树,高度为4内的,可完美打印二叉树

树状打印二叉树 C语言课程设计

[问题描述]   按树状形式打印二叉树结构,即二叉树的根在屏幕的最上边,二叉树的左子树在屏幕的左下方,二叉树的右子树在屏幕的右下边。 [测试数据]   由学生依据软件工程的测试技术自己确定。注意测试边界数据,如空二叉树。 [实现提示]   (1)利用RDL遍历方法;   (2)利用结点的深度控制横向位置。

嵌入式接口通识知识之PCIe接口

PCIe x1接口是最常见的一种,插槽的长度是最短的,仅有25mm。PCIe x4接口有四个数据通道,提供比x1接口更高的带宽,插槽的长度为39mm,分为前后两组,一组22根针脚用于供电,剩下的42根针脚是数据针脚。插槽全长89mm,有164根针脚,分为前后两组,较短的插槽有22根针脚,主要用于供电,较长的插槽142根,主要用于数据传输,具有16通道所带来的高带宽。PCIe x8接口有八个数据通道,插槽全长56mm,有98跟针脚,分为前后两组,较短的22根针脚用于供电,剩下的76根针脚是数据针脚。

2301_76587520的博客 1305

大疆OcuSync vs 传统2.4GHz:深度拆解无人机图传射频模块的硬件差异

本文深度对比了大疆OcuSync与传统2.4GHz无人机图传射频模块的硬件差异,涵盖芯片组、天线系统、PCB设计、散热方案及生产测试等核心环节。重点解析OcuSync的全定制SoC芯片、智能MIMO天线阵列及精密PCB布局如何实现革命性性能提升,为无人机图传技术发展提供专业参考。

u5v6w7的博客 806

二阶系统的带宽(频域分析)

下面以典型I型系统为例,计算系统的开环截止频率和闭环截止频率。设I型系统为: 1:系统的开环截止频率为 2:系统的闭环截止频率 其实我们在工程整定时,把ζ = 0.707,也把系统的带宽近视看成自然震荡角频率即 (wb≈wc≈wnw_{b}\approx w_{c}\approx w_{n}wb​≈wc​≈wn​)对于二阶系统。 ...

wanrenqi的博客 2万+

ATAC-seq差异分析实战:从原始数据到GO富集(R/Bioconductor全流程)

本文提供了ATAC-seq差异分析的完整R/Bioconductor实战流程,涵盖从原始数据准备、一致峰集构建、计数矩阵生成,到使用DESeq2进行差异可及性分析,以及差异峰的基因组注释与GO富集分析。文章详细讲解了关键步骤、参数设置和常见问题,旨在帮助研究者获得可靠且可解释的生物学结果。

weixin_29246195的博客 228

1.30 Cubemx_STM32H743 SD_Card纳入文件管理系统

Cubemx_STM32H743 SD_Card纳入文件管理系统1、简介2、CubeMX配置 1、简介 和前面文章原理其实一样的。 1.29 Cubemx_STM32F429\H743 nandflash、spifalsh纳入文件管理系统 现在一并将SD卡、NandFlash、SPIFlash一并作为文件管理。 下面直接介绍SDcard,其他参考前面文章。 2、CubeMX配置 ...

oDuanYanGuHong的博客 1079

UG/NX二次开发Siemens官方NXOPEN实例解析—1.3 BlockStyler/ExtrudewithPreview

随着工业智能化的不断发展,UG二次开发的需求越来越多,也吸引了大批的二开从业人员,本人作为一名资深IT从业者(10年+)也毅然加入二次开发大军。然而,和流行IT行业(互联网、金融、医疗等)相比,工业智能化的门槛显得更高一点,专业的工业软件,相对封闭的开发理念和更小的开发圈子,让刚进入二开的从业者有点举步维艰。边学边整理,希望通过这系列文章的整理能给二开的生态增添一叶绿。

MarcoPro的博客 1633

<PLC><汇川>汇川PLC基于EtherCat协议使用转矩模式控制SV630N伺服驱动电机

本系列是关于PLC相关的博文,包括PLC编程、PLC与上位机通讯、PLC与下位驱动、仪器仪表等通讯、PLC指令解析等相关内容。PLC品牌包括但不限于西门子、三菱等国外品牌,汇川、信捷等国内品牌。除了PLC为主要内容外,PLC相关元器件如触摸屏(HMI)、交换机等工控产品,如果有值得记录的内容,也会添加进来。

用沸腾的热血,支付我们的人生吧! 4158

哨兵1号回波数据(L0级)FDBAQ压缩算法详解

本文介绍哨兵1号用的FDBAQ算法,它实现非整数可变bit压缩,大部分数据仅需 3bit输出,少数高反射率数据需4bit输出,使得平均输出比特率刚超过3bit,比熵约束分块自适应量化 (ECBAQ)压缩算法所需的3.7bit更低。也就是说FDBAQ压缩完,除了要记录分块尺寸和各块的均值码(对应哨兵1号数据包里的THIDX)外,还需要记录霍夫曼码字的长度(对应哨兵1号数据包里的BRC)。唯一不同的就是量化后的编码规则使用了霍夫曼编码,相当于在传统的BAQ压缩流程的后面又加了一个步骤。

2303

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: 【Kafka之轨迹】Kafka 入门使用
下一篇: 【C语言】B 树全代码实现与超超详细思路解读(五天的呕心沥血,绝对原创每个细节,详解查找、插入与删除)
寒冰小澈IceClean
博客等级 码龄6年 344粉丝 79原创
评论 34
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒冰小澈IceClean

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值