【算法】蓝桥杯2013国C 横向打印二叉树 题解

文章目录

  • 题目链接
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例
      • 自己的样例输入
      • 自己的样例输出
    • 思路
      • 整体思路
        • 存储二叉搜索树
        • 中序遍历并存储
        • 计算目标数的行号
        • dfs遍历并写入数组
        • 初始化和处理输入输出
          • 初始化
          • 处理输入
          • 处理输出
      • 完整的代码如下
    • 结束语
    • 更新
      • 初始化的修改
      • 存储二叉搜索树的修改
      • 中序遍历和dfs的修改
      • 最终完整ac代码

题目链接

P8603 [蓝桥杯 2013 国 C] 横向打印二叉树

题目描述

其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。

当遇到空子树时,则把该节点放入那个位置。

比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如图 1 1 1 所示。

本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横向打印该二叉树。

输入格式

输入数据为一行空格分开的 N N N 个整数。 N < 100 N<100 N<100,每个数字不超过 10000 10000 10000

N N N 并没有在输入中给出。

输入数据中没有重复的数字。

输出格式

输出该排序二叉树的横向表示,为了便于评卷程序比对空格的数目,请把空格用句点代替。

样例

自己的样例输入

5 2 3 4 45 35 11 20 15 30 25 121 1234 23 1 44 7 10 12 6 

自己的样例输出

.............|-1234
.......|-121-|
..|-45-|
..|....|....|-44
..|....|-35-|
..|.........|.........|-30-|
..|.........|.........|....|-25-|
..|.........|.........|.........|-23
..|.........|....|-20-|
..|.........|....|....|-15-|
..|.........|....|.........|-12
..|.........|-11-|
..|..............|...|-10
..|..............|-7-|
..|..................|-6
5-|
..|.......|-4
..|...|-3-|
..|-2-|
......|-1

思路

整体思路

我们使用数组的方法存储二叉搜索树,定义一个长度为1010的int类型数组ns和宽度,高度都为1010的char数组mymap,一个用于存二叉树、一个用于打印二叉树。

(其实按照题目给的数据范围N<100,int数组长度不应该取1010,应该取是 2 99 2^{99} 299次方,显然也会超过内存限制。但是我亲测取1010也能过全部样例,这里就怎么简单怎么来吧)

我们用数组存储二叉搜索树,下标 x x x为根, x ∗ 2 x*2 x2为左节点下标, x ∗ 2 + 1 x*2+1 x2+1为右节点下标,按照输入顺序存储。

在中序遍历并存储,因为二叉搜索树的中序是排序了的,所以直接中序遍历输出的数字存储起来就行了,排序后方便后面计算高度。

...|-12
10-|
...|-8-|
.......|...|-7
.......|-5-|
...........|-4

上面为某个输出样例,我们观察可以不难看出,从下往上看每个数字是升序的,所以某个数字的高度h为所有大于这个数字的个数+1,这样就可以求出这个数在mymap数组的行号。列号也可以用dfs算法遍历求出。

最后做完上面的步骤,直接用dfs遍历一遍再处理一下输出就行。

存储二叉搜索树

二叉树的存储根节点的下标为1,左右节点下标为2和3,依此类推,节点下标为 x x x,那么左节点下标为 x ∗ 2 x*2 x2,右节点的下标为 x ∗ 2 + 1 x*2+1 x2+1

int ns[1010], stn;
void insert(int x) {while (ns[stn] != -1) {if (ns[stn] > x)stn = stn * 2;else if (ns[stn] < x)stn = stn * 2 + 1;}ns[stn] = x;
}

这里的stn为全局变量每次插入的时候都初始为1(根节点下标)

中序遍历并存储

这里没什么好说的,直接中序排序后的数字压入vector就行了

vector<int> cn;
void in_dfs(int start) {if (ns[start] == -1)return;in_dfs(start * 2);// 存储到vector,存储完后自然排好序cn.push_back(ns[start]);in_dfs(start * 2 + 1);
}
计算目标数的行号

因为排好序我们直接找到目标数所在的下标。

行号 = 数字个数 − 下标 行号=数字个数-下标 行号=数字个数下标

vector<int> cn;
int compute_h(int w) {vector<int>::iterator it = find(cn.begin(), cn.end(), w);int c = it - cn.begin();return cn.size() - c;
}
dfs遍历并写入数组

h,w为该数字的行号和列号,max_w为整个输出的最大列号定义为全局遍历,每次迭代取最大值。start是当前迭代的数字,d_idx为当前数字在ns数组中的下标

把当前数字转换为string类型,并计算长度n。l_idx为当前数字的左节点,r_idx为当前数字的右节点,l_h为当前数字的左节点的高度,r_h为当前数字的右节点的高度。

write函数为写入,传入一些重要参数

后面按顺序进行dfs遍历,此处为前序遍历

int max_w = 0;
void dfs(int h, int w, int start, int d_idx) {if (ns[d_idx] == -1)return;max_w = max(max_w, w);string n = to_string(start);int l_idx = d_idx * 2, r_idx = d_idx * 2 + 1;int l_h = compute_h(ns[l_idx]), r_h = compute_h(ns[r_idx]);write(h, w, l_idx, r_idx, l_h, r_h, n);dfs(l_h, w + n.size() + 3, ns[l_idx], l_idx);dfs(r_h, w + n.size() + 3, ns[r_idx], r_idx);
}
void write(int h, int w, int l_idx, int r_idx, int l_h, int r_h, string n) {int len = n.size();// 前面部分if (w - 2 >= 0)mymap[h][w - 2] = '|';mymap[h][w - 1] = '-';//中间数字部分for (int i = w; i < len + w; ++i) {mymap[h][i] = n[i - w];}// 后面部分if (ns[l_idx] != -1 || ns[r_idx] != -1) {mymap[h][len + w] = '-';mymap[h][w + len + 1] = '|';}// 补充'|'if (l_h - h > 1 && ns[l_idx] != -1) {for (int i = h; i < l_h; ++i) {mymap[i][w + len + 1] = '|';}}if (h - r_h > 1 && ns[r_idx] != -1) {for (int i = h; i > r_h; --i) {mymap[i][w + len + 1] = '|';}}
}
初始化和处理输入输出
初始化

结束dfs的方式判断当前数字为-1,先初始化ns数组全部为-1。

题目要求输出的空格打印为’.‘,那么就初始化mymap数组全部为’.'。

// 初始化
memset(ns, -1, sizeof ns);
memset(mymap, '.', sizeof mymap);
处理输入

这题没有指定读入多少个数字,所以在普通的编译器上面就不知道如何结束读入,好在OJ有一个特性我们正好可以利用。

我们简单的介绍这个OJ的特性:读入文本,读到文本末尾,程序会自动停止的。

这里就先存一下根节点,再把后面的节点读入进去

// 存储二叉树
int x;
cin >> x;
ns[1] = x;
while (cin >> x) {stn = 1;insert(x);
}
处理输出

显然cn的长度为输出的最大行号,max_w为最大宽度,我们遍历一下这个二维字符数组就行了

for (unsigned int i = 1; i <= cn.size(); ++i) {// 这里max_w 要加上大于1的数,因为要把结束字符存入max_w外面。// 反向遍历,处理结束符for (int j = max_w + 2; j >= 1; j --) {if ((mymap[i][j - 1] >= '0' && mymap[i][j - 1] <= '9') || mymap[i][j - 1] == '|') {// 存入结束字符'\0'mymap[i][j] = '\0';break;}}// 正向遍历,输出答案for (int j = 1; mymap[i][j]; ++j) {cout << mymap[i][j];}cout << endl;
}

完整的代码如下

#include <bits/stdc++.h>
#define endl '\n'using namespace std;const int N = 1010;int max_w = 0, stn, ns[N];
vector<int> cn;
char mymap[N][N];void insert(int x) {while (ns[stn] != -1) {if (ns[stn] > x)stn = stn * 2;else if (ns[stn] < x)stn = stn * 2 + 1;}ns[stn] = x;
}void in_dfs(int start) {if (ns[start] == -1)return;in_dfs(start * 2);cn.push_back(ns[start]);in_dfs(start * 2 + 1);
}int compute_h(int w) {vector<int>::iterator it = find(cn.begin(), cn.end(), w);int c = it - cn.begin();return cn.size() - c;
}void write(int h, int w, int l_idx, int r_idx, int l_h, int r_h, string n) {int len = n.size();// 前面部分if (w - 2 >= 0)mymap[h][w - 2] = '|';mymap[h][w - 1] = '-';//中间数字部分for (int i = w; i < len + w; ++i) {mymap[h][i] = n[i - w];}// 后面部分if (ns[l_idx] != -1 || ns[r_idx] != -1) {mymap[h][len + w] = '-';mymap[h][w + len + 1] = '|';}// 补充'|'if (l_h - h > 1 && ns[l_idx] != -1) {for (int i = h; i < l_h; ++i) {mymap[i][w + len + 1] = '|';}}if (h - r_h > 1 && ns[r_idx] != -1) {for (int i = h; i > r_h; --i) {mymap[i][w + len + 1] = '|';}}
}void dfs(int h, int w, int start, int d_idx) {if (ns[d_idx] == -1)return;max_w = max(max_w, w);string n = to_string(start);int l_idx = d_idx * 2, r_idx = d_idx * 2 + 1;int l_h = compute_h(ns[l_idx]), r_h = compute_h(ns[r_idx]);write(h, w, l_idx, r_idx, l_h, r_h, n);dfs(l_h, w + n.size() + 3, ns[l_idx], l_idx);dfs(r_h, w + n.size() + 3, ns[r_idx], r_idx);
}int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);// 初始化memset(ns, -1, sizeof ns);memset(mymap, '.', sizeof mymap);int x;// 存储二叉树cin >> x;ns[1] = x;while (cin >> x) {stn = 1;insert(x);}// 中序遍历并排序in_dfs(1);dfs(compute_h(ns[1]), 1, ns[1], 1);for (unsigned int i = 1; i <= cn.size(); ++i) {for (int j = max_w + 2; j >= 1; j --) {if ((mymap[i][j - 1] >= '0' && mymap[i][j - 1] <= '9') || mymap[i][j - 1] == '|') {mymap[i][j] = '\0';break;}}for (int j = 1; mymap[i][j]; ++j) {cout << mymap[i][j];}cout << endl;}return 0;
}

结束语

萌新,第一次在洛谷博客写一篇题解,有写得不好之处,请轻喷~~

更新

2023年12月4号

在上面说过了我这个方法不怎么对,用上面那种数组模拟二叉树存储在题目的限制范围会超出内存限制的,只适合像满二叉树那样,单枝树超过了8个节点就不行了,昨天因为是晚上知道这个问题后写完代码还能ac,就直接用这种简单的方法写完题解交了。今天马上就改进了,现在我们使用三个int类型数组来存储二叉树。

ns数组用来存储该下标节点的值,l数组用于存储下一个左节点的下标,r数组用于存储下一个右节点的下标。

修改如下:

初始化的修改

因为l[i]是存储i节点的左节点的下标,r[i]是存储的i节点的右节点的下标。所以我们可以递推实现预处理。

l[1] = 2;
r[1] = 3;
for (int i = 2; i < N; ++i)
{l[i] = l[i - 1] + 2;r[i] = r[i - 1] + 2;
}

存储二叉搜索树的修改

stn 还是每次进行insert的时候初始化根节点为1,然后从根节点找x应该存储在哪个节点上并赋值。

void insert(int x) {while (ns[stn] != -1) {if (ns[stn] > x)stn = l[stn];else if (ns[stn] < x)stn = r[stn];}ns[stn] = x;
}

中序遍历和dfs的修改

设:start为一个节点的下标,那么这个点的左节点为l[start],r[start]。

void in_dfs(int start) {if (ns[start] == -1)return;in_dfs(l[start]);cn.push_back(ns[start]);in_dfs(r[start]);
}
void dfs(int h, int w, int start, int d_idx) {if (ns[d_idx] == -1)return;max_w = max(max_w, w);string n = to_string(start);int l_idx = l[d_idx], r_idx = r[d_idx];int l_h = compute_h(ns[l_idx]), r_h = compute_h(ns[r_idx]);write(h, w, l_idx, r_idx, l_h, r_h, n);dfs(l_h, w + n.size() + 3, ns[l_idx], l_idx);dfs(r_h, w + n.size() + 3, ns[r_idx], r_idx);
}

最终完整ac代码

#include <bits/stdc++.h>
#define endl '\n'using namespace std;const int N = 1010;int max_w = 0, stn, ns[N * 2 + 10], l[N], r[N];
vector<int> cn;
char mymap[N][N];void insert(int x) {while (ns[stn] != -1) {if (ns[stn] > x)stn = l[stn];else if (ns[stn] < x)stn = r[stn];}ns[stn] = x;
}void in_dfs(int start) {if (ns[start] == -1)return;in_dfs(l[start]);cn.push_back(ns[start]);in_dfs(r[start]);
}int compute_h(int w) {vector<int>::iterator it = find(cn.begin(), cn.end(), w);int c = it - cn.begin();return cn.size() - c;
}void write(int h, int w, int l_idx, int r_idx, int l_h, int r_h, string n) {int len = n.size();// 前面部分if (w - 2 >= 0)mymap[h][w - 2] = '|';mymap[h][w - 1] = '-';//中间数字部分for (int i = w; i < len + w; ++i) {mymap[h][i] = n[i - w];}// 后面部分if (ns[l_idx] != -1 || ns[r_idx] != -1) {mymap[h][len + w] = '-';mymap[h][w + len + 1] = '|';}// 补充'|'if (l_h - h > 1 && ns[l_idx] != -1) {for (int i = h; i < l_h; ++i) {mymap[i][w + len + 1] = '|';}}if (h - r_h > 1 && ns[r_idx] != -1) {for (int i = h; i > r_h; --i) {mymap[i][w + len + 1] = '|';}}
}void dfs(int h, int w, int start, int d_idx) {if (ns[d_idx] == -1)return;max_w = max(max_w, w);string n = to_string(start);int l_idx = l[d_idx], r_idx = r[d_idx];int l_h = compute_h(ns[l_idx]), r_h = compute_h(ns[r_idx]);write(h, w, l_idx, r_idx, l_h, r_h, n);dfs(l_h, w + n.size() + 3, ns[l_idx], l_idx);dfs(r_h, w + n.size() + 3, ns[r_idx], r_idx);
}void init() {// 初始化memset(ns, -1, sizeof ns);memset(mymap, '.', sizeof mymap);l[1] = 2;r[1] = 3;for (int i = 2; i < N; ++i){l[i] = l[i - 1] + 2;r[i] = r[i - 1] + 2;}
}int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);init();int x;// 存储二叉树cin >> x;ns[1] = x;while (cin >> x) {stn = 1;insert(x);}// 中序遍历并排序in_dfs(1);dfs(compute_h(ns[1]), 1, ns[1], 1);for (unsigned int i = 1; i <= cn.size(); ++i) {for (int j = max_w + 2; j >= 1; j --) {if ((mymap[i][j - 1] >= '0' && mymap[i][j - 1] <= '9') || mymap[i][j - 1] == '|') {mymap[i][j] = '\0';break;}}for (int j = 1; mymap[i][j]; ++j) {cout << mymap[i][j];}cout << endl;}return 0;
}

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

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

相关文章

C语言实现梁友栋-Barsky算法

前言&#xff1a; &#xff08;引用梁友栋-Barsky裁剪算法_梁友栋 barsky算法-CSDN博客&#xff09; Cyrus和Beck用参数化方法提出了比Cohen-Sutherland更有效的算法。后来梁友栋和Barsky独立地提出了更快的参数化线段裁剪算法&#xff0c;也称为Liany-Barsky&#xff08;LB&…

oops-framework框架 之 音频管理(六)

引擎&#xff1a; CocosCreator 3.8.0 环境&#xff1a; Mac Gitee: oops-game-kit 注&#xff1a; 作者dgflash的oops-framework框架QQ群&#xff1a; 628575875 简介 在CocosCreator中&#xff0c;音频的播放主要通过组件: AudioSource 来管理音乐、音效的播放、暂停和停止…

【尚硅谷】第07章:随堂复习与企业真题(面向对象-进阶)

来源&#xff1a;尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备) 基本都是宋老师发的资料里面的内容&#xff0c;只不过补充几个资料里没直接给出答案的问题的答案。 不想安装markdown笔记的app所以干脆在这里发一遍。 第07章&#xff1a;随堂复习…

k8s的部署管理以及prometheus相关监控

安装运行prometheus和grafana编辑prometheus配置文件&#xff0c;增加采集prometheus自身数据的采集规则grafana上导入prometheus相关图表的dashboard 前面三步主要根据https://blog.csdn.net/shnu_cdk/article/details/132182858?spm1001.2014.3001.5506 用Go编写一个prome…

C# 热键注册工具类

写在前面 介绍一个验证过的热键注册工具类&#xff0c;使用系统类库user32.dll中的RegisterHotkey函数来实现全局热键的注册。 代码实现 [Flags]public enum KeyModifiers{Alt 1,Control 2,Shift 4,Windows 8,NoRepeat 0x4000}public static class HotKeyHelper{[DllImp…

01、pytest:帮助你编写更好的程序

简介 ​pytest框架可以很容易地编写小型、可读的测试&#xff0c;并且可以扩展以支持应用程序和库的复杂功能测试。使用pytest至少需要安装Python3.7或PyPy3。PyPI包名称为pytest 一个快速的例子 content of test_sample.py def inc(x):return x1def test_ansewer():assert i…

OpenCV-Python:图像卷积操作

目录 1.图像卷积定义 2.图像卷积实现步骤 3.卷积函数 4.卷积知识考点 5.代码操作及演示 1.图像卷积定义 图像卷积是图像处理中的一种常用操作&#xff0c;主要用于图像的平滑、锐化、边缘检测等任务。它可以通过滑动一个卷积核&#xff08;也称为滤波器&#xff09;在图像…

MySQL之时间戳(DateTime和TimeStamp)

MySQL之时间戳&#xff08;DateTime和TimeStamp&#xff09; 文章目录&#xff1a; MySQL之时间戳&#xff08;DateTime和TimeStamp&#xff09;一、DateTime类型二、TimeStamp类型三、DateTime和TimeStamp的区别 当插入数据时&#xff0c;需要自动记录一个时间时候&#xff0c…

MT4下载常见问题解答:解决安装过程中的技术难题

MetaTrader 4(简称MT4)是全球广泛使用的外汇交易平台&#xff0c;它以强大的功能、用户友好的界面和高度定制性获得了众多金融交易者的青睐。然而&#xff0c;对于初次接触MT4的用户来说&#xff0c;下载和安装MT4软件可能会遇到一些技术难题。本文作为一位资深金融技术专家的分…

人工智能_机器学习059_非线性核函数_poly核函数_rbf核函数_以及linear核函数效果对比---人工智能工作笔记0099

人工智能_机器学习059_非线性核函数介绍---人工智能工作笔记0099 那么我们应该如何调整这个SVC的参数,也就是我们应该使用哪种核函数,比较合适呢?这取决于我们的数据,适合使用哪个核函数,正好我们有 提供的score = accuracy_score(y_test,y_pred) 这样的评分函数,我们可以根据…

ffmpeg 实现多视频轨录制到同一个文件

引言 在视频录制中&#xff0c;有时会碰到这样一个需求&#xff0c;将不同摄像头的画面写入到一个视频文件&#xff0c;这个叫法很多&#xff0c;有的厂家叫合流模式&#xff0c;有的叫多画面多流模式。无论如何&#xff0c;它们的实质都是在一个视频文件上实现多路不同分辨率视…

记录66666

为了在两台运行RHEL 8的服务器上配置PostgreSQL 14的主从架构&#xff0c;你需要按照以下步骤操作。这里&#xff0c;假设你有两台服务器&#xff0c;主服务器的IP为192.168.1.100&#xff0c;从服务器的IP为192.168.1.101。我们将设置数据目录为/data/&#xff0c;归档日志目录…

保护你的数据:深入了解安全测试!

安全测试是一种非功能性测试。与功能测试不同&#xff0c;功能测试关注的是软件的功能是否正常工作&#xff08;软件做什么&#xff09;&#xff0c;非功能测试关注的是应用程序是否被正确设计和配置。 安全测试的主要目标&#xff1a; 识别资产-需要保护的东西&#xff0c;如…

STM32单片机项目实例:基于TouchGFX的智能手表设计(1)项目介绍及GUI界面基础

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;1&#xff09;项目介绍及GUI界面基础 一、项目介绍 1.1方案提供 1.2主控选择 1.3硬件平台 1.4 开发环境 1.5 关于华清 二、GUI界面基础 2.1.1 嵌入式绘图系统 2.1.1 色彩格式 2.1.1帧缓冲区 …

力扣374周赛

力扣第374场周赛 找出峰值 模拟 class Solution { public:vector<int> findPeaks(vector<int>& mountain) {vector<int>ans;for(int i 1 ; i < mountain.size() - 1; i ){if(mountain[i] > mountain[i-1] && mountain[i] > mountai…

CleanMyMac X2024最新免费Mac中文版安装包下载

CleanMyMac X for Mac中文2024版只需两个简单步骤就可以把系统里那些乱七八糟的无用文件统统清理掉&#xff0c;节省宝贵的磁盘空间。cleanmymac x个人认为X代表界面上的最大升级&#xff0c;功能方面有更多增加&#xff0c;与最新macOS系统更加兼容&#xff0c;流畅地与系统性…

【Vulnhub 靶场】【Prime (2021): 2】【简单 - 中等】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/prime-2021-2,696/ 靶场下载&#xff1a;https://download.vulnhub.com/prime-2021/Prime-2.ova 靶场难度&#xff1a;简单 - 中等 发布日期&#xff1a;2021年5月9日 文件大小&#xff1a;3.7 GB 靶场作者&am…

Json.NET 单个对象Json字符串反序列成两个不同实体对象

本文主要介绍Newtonsoft.JSON(Json.NET)中&#xff0c;将一个对象的Json字符串反序化成两个不同的实体对象的方法代码。具体效果如下&#xff1a; Json字符串&#xff1a; [{"guardian_id": "1453","guardian_name": "Foo Bar",&quo…

能源企业管理ERP系统都有哪些?可以帮助企业解决哪些难点

能源企业在不同的发展阶段面对的经营压力以及遇到的管理问题各异&#xff0c;随着部分产品结构的复杂化&#xff0c;日常经营管理工作也愈加繁琐。 有些能源企业内部存在信息传递不畅、经营数据统计不及时、部门协作效率低、多仓库和多平台数据不统一等情况&#xff0c;而这些…

GPT3年终总结

User You 程序员年度绩效总结 ChatGPT ChatGPT 程序员年度绩效总结通常包括以下几个方面&#xff1a; 目标达成情况&#xff1a; 回顾年初设定的目标&#xff0c;评估在项目完成、技能提升等方面的达成情况。 工作贡献&#xff1a; 强调在项目中的个人贡献&#xff0c;包括…