题目

这道题和后面的两道题,题目1201题目1009,主要内容是对递归的实现,在逻辑上,递归是容易理解的,这种实现方式和我们思考的方式是相吻合的。但是在转换为计算机语言时,要明确告知计算机应该从哪里开始启用新一层的递归,带着什么参数去启用新一层的递归,最终返回什么值。所谓的一层递归,界限在哪里,递归函数体中的形参和逻辑流程中的实参要区分清楚。这些问题都是在实现递归时需要好好琢磨的。

思路

  • 手工解决重构二叉树时,先在“先序序列”中确定根,再在“中序序列”中确定左右子树。
  • 转换为代码,用递归来实现上述过程。用结构体存放树。 用结构体来定义节点,用静态数组存放树。
    • 之所以用静态数组来存放树,是因为这样简化了内存操作。标准做法是动态申请、动态释放,但是这样做需要更小心。
    • 按照初始状态实现第一个递归实例
    • “递归总是以一个函数的形态出现”,实现第一个递归实例时,并没有意识到这一点,于是先在main中写出了递归的函数体,而后才抽出来写成新的递归函数体build()
    • 按照思路中直观地实现,给函数传递的参数都是“字符串”,包括先序序列、中序序列、左子序列、右子序列。
    • 然后就不知道怎么进行递归了:怎样自己(build)调用自己(build)呢?被困在这一步。

实现递归

  • 递归函数build的参数必须十分讲究:这些参数必须便于描述清楚“某次调用,将操作哪些数据。”

    • 反思:上面被困住的原因是,build的参数选择不当,每次都要传入字符串,而且会拆分字符串,第二层递归build调用了子串A,那么余下的子串B怎么处理?暂存?
    • 正确做法是,原来的数据本身在内存中一个地方不能动(不可传入递归做修改),能很方便地移动的是下标、指针。
  • 递归的参数一般都是“下标”或者“指针”这类索引性质的变量,不能是数据本身!
    • 反思:递归函数的参数是变量,上面实现第一个递归实例时的想法并没有这么明确
    • 只是想着先把第一次递归的操作实现出来。
    • 下一步的思路应该是,将这次实现中用到的递归函数的参数都“抽象出来、提取出来”——形成形式参数
    • 递归函数体中的形式参数是每一层递归实例中要用来接收实参的变量,如何从具体实现中选取合适的提取对象(形参的候选者)是关键。
  • 当递归函数的形式参数是下标或指针时,调用新一层递归,主要是如何对这些下标和指针进行运算,来传入正确的实参
    • 先具体:从第一次递归实例进入第二次递归实例,需要如何移动下标,加减下标,可以用一些具体数字计算
    • 后抽象:将上面用的数字,逐个抽象为公式
    • 类似于数学归纳。

调试中的小问题

  • strlen()在标准C++中的头文件是cstring,在Virsual Studio中包含string也可使用,但在标准C++中却编译出错。
  • if判断中,是否添加一个等号,都至关重要,可能就是一个等号,逻辑出错,而且不是语法错误,要选择全面的测试数据、调试很久才能发现。

完整代码

#include <stdio.h>
#include <string>
//二叉树结点定义
typedef struct BTNode {
char data;
BTNode * lchild;
BTNode * rchild;
} BTNode;
//二叉树定义
/*若用静态数组就不需要这个
typedef struct BTree {
BTNode * root;
int nodeNum;
} BTree;
*/
BTNode tree[50];
int loc; //用于保存静态数组中已分配出去的元素的个数
char pre[30];
char in[30];
//char ltemp[30];这是旧思路中使用的
//char rtemp[30];
//该函数根据前序和中序将序列分解
/*递归写的不好,传入的参数不对,返回值也不对
*传入子串,修改子串,是直观的,与思路相吻合的,但是不利于递归
*下面用下标来作为参数传入该递归函数,以下标来表示子串,便于递归操作
void splice(char & preOrder, char & inOder, char & leftTemp, char & rightTemp) {
int i;
for (i = 0; inOder[i] != preOrder[0]; i++);
for (int j = 0; j < i; j++) {
leftTemp[j] = preOrder[j];
}
i++;
for (int j = 0; preOrder[i] != 0; i++, j++) {
rightTemp[j] = preOrder[i];
}
}
*/
//如果是动态申请内存就是为新节点申请内存,这里只需要loc++就表示占用预分配的数组中一个位置,产生一个新节点
BTNode * creat() {
tree[loc].lchild = tree[loc].rchild = NULL;
return &tree[loc++];
}
//构建二叉树
BTNode * build(int s1, int e1, int s2, int e2) {
BTNode * ret = creat(); //最终要返回的指针
ret->data = pre[s1];
int rootIdx;
//【错误1】for (int i = s2; i < e2; i++) { 若子树中仅有一个节点,没有=直接不进入循环,造成错误
for (int i = s2; i <= e2; i++){ //找到根节点在中序序列中的下标
if (pre[s1] == in[i]) {
rootIdx = i;
break;
}
}
if (s2 != rootIdx) {
ret->lchild = build(s1 + 1, s1 + (rootIdx - s2), s2, rootIdx - 1); //【重要】递归的核心在此处的参数如何计算
}
if (rootIdx != e2) {
ret->rchild = build(s1 + (rootIdx - s2) + 1, e1, rootIdx + 1, e2);
}
return ret;
}
//后序遍历
void postOrder(BTNode *root) {
if (root->lchild)
postOrder(root->lchild);
if (root->rchild)
postOrder(root->rchild);
printf("%c", root->data);
}
int main()
{
while (scanf("%s%s", pre, in) != EOF) {
int start1 = 0, start2 = 0;
int end1 = strlen(pre) - 1, end2 = strlen(in) - 1;
loc = 0;
BTNode * BTRoot = build(start1, end1, start2, end2); //一次调用就构建了二叉树
postOrder(BTRoot);
printf("\n");
}
return 0;
}

【九度OJ】题目1078-二叉树遍历的更多相关文章

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

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

  2. 九度oj题目1181:遍历链表

    题目1181:遍历链表 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2600 解决:1125 题目描述: 建立一个升序链表并遍历输出. 输入: 输入的每个案例中第一行包括1个整数:n(1 ...

  3. 九度oj 题目1181:遍历链表

    题目1181:遍历链表 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3483 解决:1465 题目描述: 建立一个升序链表并遍历输出. 输入: 输入的每个案例中第一行包括1个整数:n(1 ...

  4. 九度OJ 1184:二叉树遍历 (二叉树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3515 解决:1400 题目描述: 编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储). 例如如下的 ...

  5. 九度oj题目&amp;吉大考研11年机试题全解

    九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码).    http://ac.jobdu.com/problem.php?pid=11 ...

  6. 九度OJ 题目1384:二维数组中的查找

    /********************************* * 日期:2013-10-11 * 作者:SJF0115 * 题号: 九度OJ 题目1384:二维数组中的查找 * 来源:http ...

  7. hdu 1284 关于钱币兑换的一系列问题 九度oj 题目1408:吃豆机器人

    钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  8. 九度oj 题目1007:奥运排序问题

    九度oj 题目1007:奥运排序问题   恢复 题目描述: 按要求,给国家进行排名. 输入:                        有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...

  9. 九度oj 题目1087:约数的个数

    题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...

  10. 九度OJ题目1105:字符串的反码

    tips:scanf,cin输入字符串遇到空格就停止,所以想输入一行字符并保留最后的"\0"还是用gets()函数比较好,九度OJ真操蛋,true?没有这个关键字,还是用1吧,还是 ...

随机推荐

  1. posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序

    posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...

  2. SDK 与MFC

    SDK 就是Software Development Kit 软件开发包MFC 就是Microsoft Foundation Classes 微软函数类库.是以C++类的形式封装了Windows的AP ...

  3. 用React.addons.TestUtils、Jasmine进行单元测试

    一.用到的工具 1.React.addons.TestUtils 2.Jasmine 3.Browserify(处理jsx文件的require依赖关系) 4.Reactify(能和browserify ...

  4. Google不做坏事吗?

    说中国足球为什么冲不出亚洲,那是因为咱中国人太文气,足球是种“斗牛士”式的游戏,得玩的有点儿“野蛮”色彩.记得以前在英国的时候,遇上联赛,晚上大街小巷全民皆兵,曼切斯特队的粉丝在街道一边酒吧里,利物浦 ...

  5. chrome中tcmalloc的使用

    chrome中内存分配采用了第三方库tcmalloc,这个库主要提供给应用程序内存管理方面的优化,按资料说内存存取速度会从300ns降到50ns.更具体的关于这个tcmalloc的信息大家可以查网上的 ...

  6. sql 随笔 2015-06-30

    清除多余字符 --清除多余字符 --' --char(9) 水平制表符 --char(10)换行键 --char(13)回车键 REPLACE( REPLACE( REPLACE(REPLACE([P ...

  7. 29 个 PHP 的 Excel 处理类

    下面的 PHP Excel 处理类中,包含 Excel 读写.导入导出等相关的类,列表如下: PHP Excel Reader classes 1. Read Excel Spreadsheets u ...

  8. python 字符串换行的三种方式

    if __name__ == '__main__': #第一种: 三个单引号 print ''' aaaaaaaaaaaaaaaa         bbbbbbbbbbbbbb''' #第二种: 三个 ...

  9. CFF前端沙龙总结

    一. -OOCSS + Sass ——大漠 1. OOCSS 结构<=>皮肤 分离 容器<=>内容 分离 2. Sass 工具.处理器 SCSS(CSS风格)<=> ...

  10. Awesome Javascript(中文翻译版)

    [导读]:GitHub 上有一个 Awesome – XXX 系列的资源整理.awesome-javascript 是 sorrycc 发起维护的 JS 资源列表,内容包括:包管理器.加载器.测试框架 ...