【九度OJ】题目1009-二叉搜索树
思路
- 构建二叉搜索树,并保存先序遍历和中序遍历的序列在samplePreOrder,sampleInOrder
- 每遇到一个新的序列,构建一棵二叉搜索树,保存先序遍历和中序遍历的序列testPreOrder,testInOrder
- 需要树一棵,字符串四个
实现中遇到的错误
- 递归基直接返回
return creat(x);
,少了一个操作,root = creat(x); return root;
。- 原因:递归的层次没有区分清楚,错误地认为构造一个节点,然后返回给
M->lchild
,这个想法中的M是上一层递归中的节点,不应出现在这层的递归实例中。 - 正确思路:本层递归实例,是最底层的递归,要往空树中插入节点,空树就是root,构造一个节点,要赋值给root,再返回root。
- 原因:递归的层次没有区分清楚,错误地认为构造一个节点,然后返回给
- 非递归基时,没有写return,致命错误,递归最重要的接口是传入的参数和返回的值。
- 如果不指明非递归基的递归实例中的返回值,将只能在递归基中返回,即只返回叶节点,每层递归结束后,树都只有一个节点!
- 一层正确的递归应该是,传入一棵树,添加一个节点,再返回增加了节点以后的树。
- 结合上述正确情况,再仔细想想不写return的情况,新一层的递归实例,不会增加树的节点!整体递归结束后,树只有一个节点——最后插入的节点。
- 对递归函数
insert()
的理解需要再进一步,每次传入一棵树的根的指针,最后返回这个指针。
- 出现一个“Runtime Error”
- 参考序列为sampleString,待考察序列为testString。
- 第一组testString读入并构造二叉搜索树后,没有清空loc,使第二组testString直接在前面的树中插入。
- 当测试数据再多几组时,loc一直增加,使得保存遍历结果的字符串testInOrder超出了预设的长度,内存访问错误。
- 在Visual Studio中,运行时不会检查字符串是否以0结束,strcmp()仍然会做比较,并给出NO的结果,似乎输出正确,实则访问了非法地址而没有提示。
总结
- 递归
- 在逻辑上,要区分开层次,每层递归调用不可互相干扰。
- 表现在实现上,要写好每层递归的:
- 传入的参数;
- 返回的值;
- 递归基的语句中是对谁操作,谁是指参与操作的变量是属于哪层递归调用(调用栈)的。
- 函数体,是一次调用过程中,对形参的操作(语句中全是形参);上一层递归调用本层递归,将以实参的形式向本层传入数据,不要被实参干扰本层递归的思路。
- 一两组数据测试的结果不可信,运行时的错误不易被发现,只看静态代码很难找出逻辑错误。当遇到运行时的错误,调试的能力至关重要
- 合理设置断点,合理选择单步、逐过程、继续。
- 合理选择监视哪些变量,程序运行到什么阶段,从哪里开始出错,全是从监视的变量中观察到的。
完整代码
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct BTNode {
BTNode * lchild;
BTNode * rchild;
char data;
}BTNode;
BTNode tree[15];
int loc;
int strIdx; //遍历树时存储到字符串的当前位置
//构造节点
BTNode * creat(char x) {
tree[loc].data = x;
tree[loc].lchild = tree[loc].rchild = NULL;
return &tree[loc++];
}
//将节点插入树,构建二叉搜索树
BTNode * insert(char x, BTNode * root) {
if (root == NULL) {
/*return creat(x); 【错误1】,到达递归基,直接返回一个指针
*到达递归基时insert(x, M->lchild)
*M无lchild,插入后要将M->lchild->data=x,
*而这里仅仅创造了一个新节点,没有把新创造的节点插入树中
*将新构造的节点插入树中的方法是将creat返回的指针赋值给root
*/
root = creat(x);
return root;
}
else if (x < root->data) {
//insert(x, root->lchild);到达递归基后返回一个指针,不保存这个返回值,错
root->lchild = insert(x, root->lchild);
}
else if (x > root->data) {
root->rchild = insert(x, root->rchild);
}
/*【错误2】没有写return,因此所有的返回值都是上面那个return返回的
*在main中,往树根插入节点,并将insert的返回值赋值给根节点
*若此处返回值总是上面那个return,则每次将新构造的节点返回给根节点
*树永远无法往下生长,每新插入一个节点,都把这个节点作为根
*/
return root;
}
//遍历树,将结果保存在字符串str中
void preOrder(BTNode * root, char str[]) {
str[strIdx] = root->data;
str[++strIdx] = 0; //每写入一个字符都添加结束符
if (root->lchild) {
preOrder(root->lchild, str);
}
if (root->rchild) {
preOrder(root->rchild, str);
}
}
void inOrder(BTNode * root, char str[]) {
if (root->lchild) {
inOrder(root->lchild, str);
}
str[strIdx] = root->data;
str[++strIdx] = 0;
if (root->rchild) {
inOrder(root->rchild, str);
}
}
void postOrder(BTNode * root, char str[]) {
if (root->lchild) {
postOrder(root->lchild, str);
}
if (root->rchild) {
postOrder(root->rchild, str);
}
str[strIdx] = root->data;
str[++strIdx] = 0;
}
int main()
{
int n;
while (scanf("%d", &n) != EOF) {
if (n == 0) break;
char sampleString[15];
char samplePreOrder[15];
char sampleInOrder[15];
char testString[15];
char testPreOrder[15];
char testInOrder[15];
char blank[5];
//gets_s(blank); //消除第一行的换行符的影响
//gets_s(sampleString);
scanf("%s", sampleString);
loc = 0;
BTNode * R;
//构造作为参照的二叉搜索树
R = NULL;
for (int i = 0; sampleString[i] != '\0'; i++) {
//insert(sampleString[i], R);这个不保存insert的返回值会使R一直就是空树
R = insert(sampleString[i], R);
}
strIdx = 0; //字符串下标回到0
preOrder(R, samplePreOrder);
strIdx = 0;
inOrder(R, sampleInOrder);
loc = 0; //将树清空
for (int j = 0; j < n; j++) { //循环n次,每次输出一个结果YES或NO
//构造测试数据组成的树,并存储遍历序列
//gets_s(testString);
scanf("%s", testString);
R = NULL;
//【错误3】这里忘记将树清空,如果n=2时,将把第二组testString继续往树中插入,从而造成数组越界
loc = 0;
for (int i = 0; testString[i] != '\0'; i++) {
R = insert(testString[i], R);
}
strIdx = 0;
preOrder(R, testPreOrder);
strIdx = 0;
inOrder(R, testInOrder);
//输出判断结果
if (strcmp(samplePreOrder, testPreOrder) == 0 && strcmp(sampleInOrder, testInOrder) == 0) {
printf("YES\n");
}
else {
printf("NO\n");
}
} //for
} //while
return 0;
}
【九度OJ】题目1009-二叉搜索树的更多相关文章
- 九度oj题目1009:二叉搜索树
题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接 ...
- 九度oj 题目1009:二叉搜索树
题目1009:二叉搜索树 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5733 解决:2538 题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n&l ...
- 九度OJ 题目1384:二维数组中的查找
/********************************* * 日期:2013-10-11 * 作者:SJF0115 * 题号: 九度OJ 题目1384:二维数组中的查找 * 来源:http ...
- hdu 1284 关于钱币兑换的一系列问题 九度oj 题目1408:吃豆机器人
钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 九度oj题目&吉大考研11年机试题全解
九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码). http://ac.jobdu.com/problem.php?pid=11 ...
- 九度oj 题目1007:奥运排序问题
九度oj 题目1007:奥运排序问题 恢复 题目描述: 按要求,给国家进行排名. 输入: 有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...
- 九度oj 题目1367:二叉搜索树的后序遍历序列
题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 输入: 每个测试案例包括2行: 第一行为1个整数 ...
- 九度oj 题目1087:约数的个数
题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...
- 九度OJ题目1105:字符串的反码
tips:scanf,cin输入字符串遇到空格就停止,所以想输入一行字符并保留最后的"\0"还是用gets()函数比较好,九度OJ真操蛋,true?没有这个关键字,还是用1吧,还是 ...
- 九度oj题目1002:Grading
//不是说C语言就是C++的子集么,为毛printf在九度OJ上不能通过编译,abs还不支持参数为整型的abs()重载 //C++比较正确的做法是#include<cmath.h>,cou ...
随机推荐
- cojs 疯狂的粉刷匠 疯狂的斐波那契 题解报告
疯狂的斐波那契 学习了一些奇怪的东西之后出的题目 最外层要模p是显然的,然而内层并不能模p 那么模什么呢,显然是模斐波那契的循环节 那么我们可以一层层的求出每层的斐波那契循环节 之后在从内向外用矩阵乘 ...
- lintcode:合并区间
题目: 合并区间 给出若干闭合区间,合并所有重叠的部分. 样例 给出的区间列表 => 合并后的区间列表: [ [ [1, 3], [1, 6], [2, 6], => [8, 10], [ ...
- 3.Spring-用反射模拟IoC
1.BeanFactory.java package com.jike.spring.chapter03.reflect; import java.io.InputStream; import jav ...
- 测试Tomcat
- netty 解决TCP粘包与拆包问题(三)
今天使用netty的固定长度进行解码 固定长度解码的原理就是按照指定消息的长度对消息自动解码. 在netty实现中,只需要采用FiexedLengthFrameDecoder解码器即可... 以下是服 ...
- Ubuntu中MySQL中文乱码解决
1.以root登陆,在终端输入命令 sudo gedit /etc/mysql/my.cnf在打开的文件中找到[client]在下面加入default-character-set=utf8 找到 [m ...
- ios程序开发杂记
ios程序开发杂记 一.程序构建 与一般的程序构建无太大区别,都是源文件编译链接这一套,通常是在mac上做交叉编译,也就是利用xcode里带的ios编译工具集去生成arm架构的ios程序(或是x86的 ...
- ASP.NET MVC 学习3、Controller左手从Model获取数据,右手传递到View页面
参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/accessing-your-models-dat ...
- UVa 548 Tree【二叉树的递归遍历】
题意:给出一颗点带权的二叉树的中序和后序遍历,找一个叶子使得它到根的路径上的权和最小. 学习的紫书:先将这一棵二叉树建立出来,然后搜索一次找出这样的叶子结点 虽然紫书的思路很清晰= =可是理解起来好困 ...
- [Sciter系列] MFC下的Sciter–3.Sciter脚本与底层交互
[Sciter系列] MFC下的Sciter–3.Sciter脚本与底层交互,脚本调用底层自定义的方法函数. 本系列文章的目的就是一步步构建出一个功能可用,接口基本完善的基于MFC框架的SciterF ...