题目

这道题和后面的两道题,题目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. lintcode:Length of Last Word 最后一个单词的长度

    题目: 最后一个单词的长度 给定一个字符串, 包含大小写字母.空格' ',请返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 样例 给定 s = "Hello World& ...

  2. XE2编译出来的DLL的DLLMain的退出地方用到了halt0

    DelphiXE2内存加模块升级版.支持32位和64位模块. 已转至新的博客 http://www.raysoftware.cn/?p=51 很多年以前写过内存加载DLL的一片技术. http://b ...

  3. 63. Unique Paths II

    题目: Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. H ...

  4. C++:纯虚函数与抽象类

    5.4.3 纯虚函数和抽象类 纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但是要求在派生类中根据需要对它进行定义,或仍然说明为纯虚函数. 声明纯虚函数的一般格式是: virtual 函数 ...

  5. 在屏幕上显示C盘根目录下的所有文件和文件夹

    1 import java.io.File; //在屏幕上显示C盘根目录下的所有文件和文件夹 public class ListDemo { public static void main(Strin ...

  6. 6、JPA_映射单向多对一的关联关系(n的一方有1的引用,1的一方没有n的集合属性)

    单向多对一的关联关系 具体体现:n的一方有1的引用,1的一方没有n的集合属性 举个例子:订单Order对顾客Customer是一个单向多对一的关联关系.Order是n的一方,有对Customer的引用 ...

  7. Tomcat 管理页面

    一.配置刚下载的解压版的apache-tomcat,启动后,通过浏览器访问:http://127.0.0.1:8080/(或者http://localhost:8080)然后点击下图的Server s ...

  8. Intellij IDEA 快速创建Spring Web 项目

    相关软件: Intellij Idea14:http://pan.baidu.com/s/1nu16VyD JDK7:http://pan.baidu.com/s/1dEstJ5f Tomcat(ap ...

  9. Java API —— 反射

    1.类加载器     1)类的加载         · 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化.         · 加载 :就是 ...

  10. 三个特殊资源目录 /res/xml /res/raw 和 /assets

    在android开发中,我们离不开资源文件的使用,从drawable到string,再到layout,这些资源都为我们的开发提供了极大的便利,不过我们平时大部分时间接触的资源目录一般都是下面这三个. ...