程序设计:控制台输出二叉树 二叉树的形象显示

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


       本文指导你编写一个输出到字符控制台的形象的二叉树展示。

目录

一般的Tree显示方式

理想的显示方式

实现方法

计算显示位置

输出数据

计算子树宽度的代码

设置显示位置的代码

输出数据的代码


一般的Tree显示方式

        编写二叉树算法时调试是很头疼的,如何显示成一目了然的树结构呢?以目录树方式显示当然比较简单,类似windows控制台的Tree命令的效果:

        这种输出只需要正确计算节点的缩进级别就可以了,用一个递归函数很容易就实现了。

        但是这种输出方式并不方便查看,不容易直接看到两个子节点。而我们一般讲解二叉树的时候都是横向排版,两个子节点排在父节点下面的同一行。

理想的显示方式

        理想的显示方式如下图所示:

        这就是程序的实际输出效果,左子节点左边有个“[”,右子节点右边有个“]”,这样每一组子节点就一目了然,左子树整个都显示在父节点的左边,右子树整个都显示在父节点右边。

        由于我们的目的不是做完美的界面,所以不会考虑ncurse库这种能随意绘制的方式(如果这样不如直接用图形界面了),我们只考虑printf和cout的能力。

实现方法

        要想实现这种效果,需要分两步来做:

  1. 计算整个左子树的宽度,从而确定节点显示位置
  2. 根据计算好的显示位置自上而下输出数据

计算显示位置

        计算显示位置是个比较复杂的事情,因为每个节点的显示宽度是不确定的,需要预先确定每个节点的宽度,然后根据结构计算正确的位置,如果子节点缺失,没必要占用显示空间。

        既然这么复杂,我们可以把问题拆开,把计算精确位置留给第二步,把每个节点当成一个格子,这一步只计算格子位置。

        计算出的格子位置如何保存呢?这就需要一个表格,这个表格的行列数刚好容纳整个二叉树。仔细观察一下上面的输出示例图形,每一个节点都独立占据一列,左子树的宽度就是左子树的总节点数,因此表格的列数就是总的节点数,行数就是树的深度。

        这样很容易预先申请一个二维数组,然后根据计算出的位置设置里面的值,最后将这个二维数组输出就可以了。

输出数据

        经过上一步,输出数据已经在二维数组里,如何显示就比较容易了。只需要预先计算一下每列的最大显示宽度,然后逐个输出就可以了。

        当然为了实现这个功能,最好有一些包装类,以简化操作。

计算子树宽度的代码

        这只是示意代码:

	//获取节点总数,包括自身T_SHM_SIZE _check_get_count(T_SIZE h){//thelog << h << endi;T_SIZE n = 0;if (_check_is_data_node(h)){++n;//thelog << h << " " << TREE_NODE::at(h).hLeft<<" "<< TREE_NODE::at(h).hRight << endi;n += _check_get_count(TREE_NODE::at(h).hLeft);n += _check_get_count(TREE_NODE::at(h).hRight);}else{//thelog << "NULL" << endi;}return n;}

        解释一下这个代码:

        T_SIZE h 就是节点的指针或者句柄,这里实际上是位置索引。

        _check_is_data_node(h) 判断一个位置是否是有效位置,相当于判断是不是空指针。       

        TREE_NODE::at(h) 获取位置上的节点对象的引用。

        TREE_NODE::at(h).toString2(left) 这个代码获得节点的显示字符串,参数控制是否是左节点,左节点添加“[”,右节点添加“]”。

        基本逻辑就是:

        如果不是有效节点,返回0

        否则返回1+左节点树的总节点数+右节点数的总节点数

        显然这是一个递归函数。

设置显示位置的代码

        上面的函数获得的就是子树的宽度(与节点总数相同),将其设置到表格里就可以了:

	//树形显示,px为偏移量,左边元素数void _check_show_tree(Table& table, T_SIZE h, bool left = true, T_SIZE line = 0, T_SIZE px = 0){//thelog << h << " " << line << " " << px << endi;if (!_check_is_data_node(h)){//thelog << "空" << endi;return;}T_SIZE leftCount = _check_get_count(TREE_NODE::at(h).hLeft);//thelog << "leftCount " << leftCount << endi;T_SIZE pos = px + leftCount;table.SetData(line, pos, TREE_NODE::at(h).toString2(left));//设置自身数据//thelog << "TREE_NODE::at(h).hLeft " << TREE_NODE::at(h).hLeft << endi;_check_show_tree(table, TREE_NODE::at(h).hLeft, true, line + 1, px);//处理左子项//thelog << "TREE_NODE::at(h).hRight " << TREE_NODE::at(h).hRight << endi;_check_show_tree(table, TREE_NODE::at(h).hRight, false, line + 1, pos + 1);//处理右子项}

        解释一下这个代码:

        Table是个包装好的类,能通过table.SetData()直接对某个位置设置值。

        这当然也是一个递归函数。

输出数据的代码

        第一步,计算每个列的最大宽度

        第二步,按照每个列的最大宽度输出每个字段,为了格式整齐,一定要用空格来填补,不可以用tab。数据中最好不要有tab、回车换行之类的东西,也不要有中文。

        这两步不算很复杂,稍微有点耐心就能写好了,算不上一个算法课题。我这里用的是已经包装好的通用类Table:

Table table;
rbtree._check_show_tree(table, rbtree.tree_head->hHead);
thelog << endl << table.MakeTextTable() << endi;

        rbtree是红黑树对象。

        table.MakeTextTable()把整个表格转换为文本表格。这个类还有些别的功能,比如转换为html的表格或者生成JS更新数据的脚本。我会在后续整理出这个代码(捆绑了太多特殊需要,需要删减)。


(这里是结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/702282.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lerna实战(一)

前言 将大型代码仓库分割成多个独立版本化的 软件包&#xff08;package&#xff09;对于代码共享来说非常有用。但是&#xff0c;如果某些更改 跨越了多个代码仓库的话将变得很 麻烦 并且难以跟踪&#xff0c;并且&#xff0c; 跨越多个代码仓库的测试将迅速变得非常复杂。 …

Android Q - 音频通路调试

对于当前模块不是很清楚&#xff0c;刚好有个项目这方面有点问题&#xff0c;根据展锐支持文档一步步检查就可以了。首先得先弄清楚硬件具体是怎么连接的&#xff0c;比如文档提到的案例&#xff1a;sprd codec speaker output 连接外部 PA。 耳机接的是什么&#xff0c;speake…

Java线程生命周期:Java线程生命周期全景解读

1. 线程生命周期概述&#xff1a;不仅仅是状态转换 在多线程编程中&#xff0c;理解线程的生命周期对于编写有效、高效的代码至关重要。线程生命周期通常描述了线程从创建到死亡的一系列状态变化过程&#xff0c;但其实不仅仅局限于这些状态的简单转换。线程生命周期的理解应该…

Redis的集群模式——Java全栈知识(20)

1、主从模式 Redis 支持主从模式的集群搭建&#xff0c;这是 Redis 提供的最简单的集群模式搭建方案&#xff0c;目的是解决单点服务器宕机的问题。当单点服务器发生故障的时候保证 Redis 正常运行。 主从模式主要是将集群中的 Redis 节点分为主节点和从节点。然后读和写发生在…

buff禁售武器箱和胶囊的原因,及游戏搬砖人该如何应对

大家好&#xff0c;我是童话&#xff0c;相信大家都看到这个消息了&#xff0c;buff平台在14号中午11点左右&#xff0c;已经全面禁止了武器箱和胶囊&#xff0c;纪念包等的上架和售卖。在饰品市场直接搜索武器箱或者胶囊&#xff0c;是完全搜索不出来任何东西的哈。 面对这一消…

平衡三进制小数详解与进制转换

标准三进制是“逢三进一&#xff0c;退一还三”的机制&#xff0c;平衡三进制与之类似&#xff0c;但就是偏移了一下变得对称了&#xff0c;平衡三进制是逢/-2进1或进T的&#xff0c;平衡三进制与标准三进制可以相互转换&#xff0c;但这样显得有点多余了&#xff0c;所以这里只…

Nginx 7层负载均衡的搭建

目录 负载均衡的理解 修改配置文件 测试 1. 选择在 DMZ 区测试&#xff0c;使用 db 服务器进行测试 2.选择在外网测试负载均衡效果 负载均衡的理解 负载均衡&#xff1a;load balancer&#xff0c;简称LB Nginx 既是一个 web 服务器软件&#xff0c;也是一个负载均衡软件&a…

谷歌I/O 2024大会全面硬刚OpenAI

&#x1f989; AI新闻 &#x1f680; 谷歌发布升级版Gemini机器人 竞争OpenAI ChatGPT-4 摘要&#xff1a;谷歌展示了升级版的 Gemini 聊天机器人&#xff0c;其支持实时处理视频和语音输入&#xff0c;并准确回答问题。此次发布时机与 OpenAI 公布 ChatGPT-4o 新模型几乎同步…

在浏览器执行js脚本的两种方式

fetch请求get 在浏览器执行http请求,可以使用fetch函数; fetch(“url”).then(response => response.text()) .then(data => console.log(JSON.parse(data)[‘status’])) .catch(error => console.error(error)) 直接返回json数据: fetch(“url”).then(response…

Milvus 安装与配置

一、环境准备 在安装 Milvus 之前&#xff0c;确保你的系统满足以下要求&#xff1a; 操作系统&#xff1a;Milvus 支持 Linux 操作系统&#xff0c;如 Ubuntu、CentOS 等。硬件资源&#xff1a;推荐使用具有足够 CPU、内存和 SSD 存储的机器。对于大规模数据集&#xff0c;高…

在数据库中使用存储过程插入单组/多组数据

存储过程可以插入单组数据&#xff0c;也可以以字符串的形式插入多组数据&#xff0c;将字符串中的信息拆分成插入的数据。 首先建立一个简单的数据库 create database student; use student;选中数据库之后建立一张学生表 create table stu(uid int primary key,uname varc…