题目描述

二哥学了二叉树的顺序存储后,被下面一个问题难住了,于是他请你帮他解决。给你一个前序遍历和中序遍历,问顺序存储的数组是什么样子的。

输入格式

第一行为前序遍历,第二行为中序遍历,节点个数不超过26.

输出格式

输出一行,表示顺序存储的数组,以空格隔开,NULL表示空节点,数组空间不超过1000个节点.

样例输入

ABCD BADC

样例输出

A B C NULL NULL D

数据范围

(无)

题目分析

你有没有发现SJTU的OJ有一个二哥还有一个小可怜经常出题?二哥摘苹果,二哥种花生,二哥养兔子……
      这个题目需要的知识有函数的递归,二叉树的基本概念,前序遍历、中序遍历。如果没有学过可以看看数据结构的教材《数据结构:思想与实现(翁慧玉 俞勇)》- 第六章 树。只需要知道概念即可,可以看一下教材的P162-164,看完你就会做这个题目(确信)。
      程序设计的课程就学二叉树ACM班也太猛了吧! 不过我想趁这个题目复习一下字符串的知识,还有了解一下二叉树的基本知识。

二叉树

前序遍历: 先访问根节点,然后前序遍历左子树,前序遍历右子树
      中序遍历: 先中序访问左子树,再访问根节点,最后中序遍历右子树
      后序遍历: 先中序访问左子树,再中序遍历右子树,最后访问根节点
      一句话总结:前序、中序、后序指的是 根节点 在访问顺序的排序!

编号问题: 计算公式如下 (注意:树的根结点编号为 1) 右 儿 子 编 号 = 根 节 点 编 号 × 2 右儿子编号=根节点编号\times2 右儿子编号=根节点编号×2 左 儿 子 编 号 = 根 节 点 编 号 × 2 + 1 左儿子编号=根节点编号\times2+1 左儿子编号=根节点编号×2+1

字符串

(转载)字符串知识传送门,想看原版的可以走传送门,不想走的可以接着往下看,内容差不多。个人觉得要用的时候看也可,反正不是经常用的玩野。

读取方法:

编号 读取方法 读取特点
方法一 cin 接受一个字符串,遇“空格”、“Tab”、“回车”都结束
方法二 cin.get() 用法一:cin.get(字符变量名)可以用来接收字符
用法二:cin.get(字符数组名,接收字符数)用来接收一行字符串,可以接收空格
用法三:cin.get(无参数)没有参数主要是用于舍弃输入流中的不需要的字符,或者舍弃回车,弥补cin.get(字符数组名,接收字符数目)的不足。
方法三 cin.getline() cin.getline() ----接受一个字符串,可以接收空格并输出
方法四 getline() getline() // 接受一个字符串,可以接收空格并输出,需包含#include<string>
方法五 gets() gets()// 接受一个字符串,可以接收空格并输出,需包含#include<string>
方法六 getchar() getchar()//接受一个字符

长度获取:

  • 加上头文件:#include <string.h>
  • 定义一个字符数组 char pre[50];
  • 输入数据的时候可以这样 cin >> pre;
  • strlen(数组名);函数将会返回一个整数,表示一个字符数组内字符个数

题目解答

老套路,从我们之前写的就可以看出来:

前序遍历: 先访问根节点,然后前序遍历左子树,前序遍历右子树

前序遍历里面套娃前序遍历,明显是要递归解决!
      递归的核心:函数之间的通讯内容 [传递的信息] ,终止条件。
      我们不妨还是用课本的案例来:

课本案例:
已知一个二叉树的前序遍历,中序遍历,求这个二叉树:
二叉树前序遍历序列是:A、L、B、E、C、D、W、X
二叉树中序遍历序列是:B、L、E、A、C、W、X、D

  1. 由前序遍历序列找根节点,显然是 A
  2. 由中序遍历划分根节点左边的元素、右边的元素(具体方法:在中序遍历中找根节点A,根节点A左边的就是 根节点的左子树里面的元素,右边的是 根节点的右子树里面的元素
  3. 套娃循环,分别对 根节点的左子树里面的元素根节点的右子树里面的元素 重复递归,执行步骤一、二,直到每个元素位置确定!

回归话题:函数之间的通讯内容有:节点的编号、当前查找的序列在前序遍历数组的起点、终点、在中序遍历的起点、终点,终止条件:当前查找的元素只有一个!此时就要确定位置,位置就是当前节点的编号,上代码!

#include <iostream>
#include <string.h>
using namespace std;
char pre[50];       // 前序遍历序列
char in[50];        // 中序遍历序列
char ans[1050];     // 答案数组// 把中序遍历分割为左右两半
// 使用方法(0,num-1,0,num-1,1);
void solution(int prest,int preed,int inst,int ined,int rootnum)
{ans[rootnum] = pre[prest];    // 把根节点传入答案数组// 当前查找的元素只有一个!此时就要向答案数组里面传递信息,位置就是当前节点的编号 rootnumif (prest == preed && inst == ined){ans[rootnum] = pre[prest];return;}// 当前查找的元素超过一个,继续二分!else{int targetnum;           for (int i = inst; i <= ined; i++){if (in[i] == pre[prest]){targetnum = i;break;} // 在中序遍历中找根节点A,便于后续划分}if (targetnum > inst)// 下面这个函数递归的是左子树的元素 2 * rootnum是左儿子的编号solution(prest + 1, prest + targetnum - inst, inst, targetnum - 1, 2 * rootnum);if (targetnum < ined)// 下面这个函数递归的是右子树的元素 2 * rootnum + 1是右儿子的编号solution(preed - ined + targetnum + 1, preed, targetnum + 1, ined, 2 * rootnum + 1);}
}  int main()
{cin >> pre;cin >> in;int num = strlen(pre);  // 获取字符串的长度,也可以用下面的注释的方法// while (pre[num] >= 'A' && pre[num]<='Z')// {//     num++;// }// 此时num反映了输入的字符串个数!solution(0, num - 1, 0, num - 1, 1);// 去掉答案数组里无效的元素!int p = 1049;while (ans[p] < 'A' || ans[p] > 'Z'){p--;}// 输出答案!for (int i = 1; i <= p;i++){if (ans[i] >= 'A' && ans[i] <= 'Z')cout << ans[i] << " ";elsecout << "NULL" << " ";}system("pause");return 0;
}

一些其他的解法,可以参考,来源SJTU 解答集 OJ,方法各有千秋。

/* 二哥学二叉树 */
#include <iostream>
#include <cstring>
using namespace std;char a[1005];
char dlr[30], ldr[30];void restoreTree(char *dlr, char *ldr, int len, int root){if (len <= 0)return;char r = dlr[0];a[root] = r;int i = 0;while (ldr[i] != r)++i;restoreTree(dlr + 1, ldr, i, root * 2);restoreTree(dlr + i + 1, ldr + i + 1, len - i - 1, root * 2 + 1);
}int main(){cin >> dlr >> ldr;for (int i = 1; i <= 1004; ++i)a[i] = ' ';restoreTree(dlr, ldr, strlen(dlr), 1);int n = 1000;while (a[n] == ' ')--n;for (int i = 1; i <= n; ++i){if (a[i] == ' ')cout << "NULL ";elsecout << a[i] << ' ';}cout << endl;return 0;
}
#include "iostream"
#include "cmath"
#include "cstring"
using namespace std;//二叉树类
template <class T>
class myBinaryTree {public:class node {public:T data;T *lchild=nullptr, *rchild=nullptr;};node *root=nullptr;//清空void clear() {clear(root);}void clear(node *p) {if (p == nullptr)return;clear(p->lchild);clear(p->rchild);delete p;p = nullptr;}//构造myBinaryTree(){}//析构~myBinaryTree() {clear(root);}//判断是否非空bool empty() {return root == nullptr;}
};char tdata[1009] = { 0 };
int dataSize = 0;void createTree(int rootNum, char *tempData1,char *tempData2) {if (strlen(tempData1) == 0) return;char root = tempData1[0];tdata[rootNum] = root;dataSize = rootNum < dataSize ? dataSize : rootNum;char ldata1[50] = { 0 }, rdata1[50] = { 0 }, ldata2[50] = { 0 }, rdata2[50] = { 0 };int length = strlen(tempData1);bool flag = false;for (int i = 0,k=0; i < length; i++,k++) {if (tempData2[i] == root) {flag = true;k = -1;}else if (!flag) {ldata1[k] = tempData1[i + 1];ldata2[k] = tempData2[i];}else if (flag) {rdata1[k] = tempData1[i];rdata2[k] = tempData2[i];}}//递归createTree(rootNum * 2, ldata1, ldata2);createTree(rootNum * 2 + 1, rdata1, rdata2);
}int main() {char preData[50], postData[50];cin >> preData >> postData;createTree(1, preData, postData);//输出cout << tdata[1];for (int i = 2; i <= dataSize; i++) {if (tdata[i] == 0)cout << " NULL";elsecout << " " << tdata[i];}return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
char pre[100],in[100],ans[2000];
int maxn;
void dfs(int ps,int pe,int is,int it,int p)
{int root,leftlen,rightlen;for (root=is;root<it;++root){if (in[root]==pre[ps])break;}ans[p]=in[root];if (p>maxn) maxn=p;leftlen=root-is;if (leftlen>0) dfs(ps+1,ps+leftlen,is,root,p*2);rightlen=it-root-1;if (rightlen>0) dfs(ps+leftlen+1,pe,root+1,it,p*2+1);
}
int main() {cin>>pre;cin>>in;dfs(0,strlen(pre),0,strlen(in),1);for (int i=1;i<=maxn;++i)if (ans[i]) cout<<ans[i]<<" ";else cout<<"NULL ";return 0;
}

(新版)SJTU-OJ-1049. 二哥学二叉树相关推荐

  1. sjtu oj 1034 二哥的金链

    一道比较有意思的题目,我把队列改造了一下然后ac了,后来学数据结构的时候发现我改的队列还有个名词,叫单调队列,心里颇为激动,于是把题目和我的代码发上来与大家分享一下. Description 一个阳光 ...

  2. 最新版 | 李沐《动手学深度学习》中文版pdf重磅开源!

    强烈推荐李沐等人开源的<动手学深度学习>最新版!完整中文版 PDF 终于更新 可下载: <动手学深度学习>旨在向读者交付有关深度学习的交互式学习体验.书中不仅阐述深度学习的算法 ...

  3. SWUST OJ#978 #979 #980 二叉树的遍历

    目录 深度优先遍历 输出利用先序遍历创建的二叉树的前序遍历序列 思路 代码 #978 输出利用先序遍历创建的二叉树的中序遍历序列 题目 思路 代码 #979 输出利用先序遍历创建的二叉树的后序遍历序列 ...

  4. 九度oj 题目1078:二叉树遍历

    题目1078:二叉树遍历 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5326 解决:3174 题目描述: 二叉树的前序.中序.后序遍历的定义: 前序遍历:对任一子树,先访问跟,然后遍历 ...

  5. 【算法学习笔记】65. 双向扫描 SJTU OJ 1382 畅畅的牙签盒

    http://acm.sjtu.edu.cn/OnlineJudge/problem/1382 注意到 排序之后 i从前向后扫描时,cur恰好是从后向前的,所以即使是双重循环,也是O(n)的算法. # ...

  6. SWUST OJ#971 #972 返回二叉树宽度和深度

    目录 #971 统计利用先序遍历创建的二叉树的深度 题目 思路 代码 #972  统计利用先序遍历创建的二叉树的宽度 题目 思路 代码 #971 统计利用先序遍历创建的二叉树的深度 题目 题目描述 利 ...

  7. 二叉树OJ(一)二叉树的最大深度 二叉搜索树与双向链表 对称的二叉树

    二叉树的最大深度 二叉树中和为某一值的路径(一) 二叉搜索树与双向链表 对称的二叉树 二叉树的最大深度 描述 求给定二叉树的最大深度, 深度是指树的根节点到任一叶子节点路径上节点的数量. 最大深度是所 ...

  8. 【算法学习笔记】43.动态规划 逆向思维 SJTU OJ 1012 增长率问题

    1012. 增长率问题 Description 有一个数列,它是由自然数组成的,并且严格单调上升.最小的数不小于S,最大的不超过T.现在知道这个数列有一个性质:后一个数相对于前一个数的增长率总是百分比 ...

  9. 【算法学习笔记】57. 前缀树 字典序优化技巧 STL学习 SJTU OJ 1366 前缀匹配

    Description 给出一个总字符个数大小不超过1,000,000的字典(这个字典的单词顺序不为字典序)和不超过1000个长度不超过1000的前缀,输出字典中匹配该前缀,字典序为K_i的单词在字典 ...

最新文章

  1. 软件开发打败了 80 %的程序员
  2. 如何在yaml中表示一个空字段
  3. requests模块--python发送http请求
  4. 如何在Winform界面中设计图文并茂的界面
  5. vi文本编辑器的使用
  6. 顺序的分数 Ordered Fractions
  7. python空类型用什么表示_python中怎么表示空值
  8. 程序员的毕业设计,时隔一年,仍感觉头秃
  9. Linux Epoll ET模式EPOLLOUT和EPOLLIN触发时刻
  10. 3DLC系列之:工作色彩模型
  11. SVN回滚到某一版本
  12. 一键获取网页中的全部图片并批量下载(国内淘宝天猫京东网站+国外商品页面)——亲测有效
  13. 2021年第一季度Sumap网络空间测绘CVE漏洞趋势安全分析报告
  14. 杭州旭航集团,申请纳斯达克IPO上市,募资9800万美元
  15. Centos7 查看用户和用户组
  16. 软件设计师(八)汇总-选择题
  17. tensorflow学习笔记(八):LSTM手写体(MNIST)识别
  18. Go pprof 性能分析工具 - 详细使用图解
  19. 当编程语言都变成女孩子,你会不会喜欢她们!
  20. java中private,public,protected详解

热门文章

  1. 【读书笔记】ndss2018_K-Miner_ Uncovering Memory Corruption in Linux
  2. TCP/IP协议学习记录之九:Traceroute程序
  3. TextMate 小小心得
  4. Wopti.Utilities.Special.Edition.v7.8.8.218-TE
  5. 什么请求服务器响应快,HTTP请求与服务器响应流程
  6. 利用虚拟机复现漏洞 “永恒之蓝”
  7. 技术理论-【socket】- 计算机网络
  8. 『 canvas 特效』一文教你绘制绚丽的星空背景 TS + ES6
  9. 京东消息中间件的演进
  10. ipod固件已用迅雷下载怎样升级(转)