题目

这道题和后面的两道题,题目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. CTSC2016&&APIO2016游记

    4.30 下午衡中放假,我们因为比赛的缘故提前到中午12:00放假 然后我爸爸说要来接我,直到下午两点多他才到,然后衡中宿舍的楼管阿姨死活不给我开门 莫名其妙的等到了三点多快四点的时候我才跟实验班的一 ...

  2. 李洪强iOS开发之Foundation框架—集合

    Foundation框架—集合 一.NSArray和NSMutableArray (一)NSArray不可变数组 (1)NSArray的基本介绍 NSArray是OC中使用的数组,是面向对象的,以面向 ...

  3. VCL ActiveX 播放视频

    播放网络视频 string[] options = new string[] { ":sout=#duplicate{dst=display} :no-overlay" }; st ...

  4. 是什么让 Ubuntu 选用 Qt 而不是 GTK?

    是什么让 Ubuntu 选用 Qt 而不是 GTK? 一个正在发生的事实,Ubuntu正在不断Qt化!我曾一直在抱怨的Software Center,今日一看源码,竟然有softwarecenter/ ...

  5. java.util.regex.PatternSyntaxException: Unclosed character class near index解决办法

    使用str.split("[")时,出现java.util.regex.PatternSyntaxException: Unclosed character class near  ...

  6. java.util.zip.ZipOutputStream压缩无乱码(原创)

    package io; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.FileI ...

  7. 【原创】Kmeans算法 优缺点分析

    优点: 原理简单(靠近中心点),实现容易(1.2 天),聚类效果中上(依赖K的选择) 缺点: 1. 无法确定K的个数 (根据什么指标确定K) 2. 对离群点敏感 (容易导致中心点偏移) 3. 算法复杂 ...

  8. 浅谈PHP自动化代码审计技术

    原文出处: exploit   欢迎分享原创到伯乐头条 0×00 由于博客实在没什么可以更新的了,我就把目前做的事情总结一下,当做一篇博客,主要是谈一谈项目中所运用的一些技术.目前市面上有不少PHP的 ...

  9. 内核MKDEV(MAJOR, MINOR)宏

    版本:linux-2.6.24.4宏:    MKDEV(MAJOR, MINOR);  说明: 获取设备在设备表中的位置.        MAJOR   主设备号        MINOR   次设 ...

  10. json格式的字符串转为json对象遇到特殊字符问题解决

    中午做后台发过来的json的时候转为对象,可是有几条数据一直出不来,检查发现json里包含了换行符,造成这种情况的原因可能是编辑部门在编辑的时候打的回车造成的 假设有这样一段json格式的字符串 va ...