【九度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 ...
随机推荐
- flexbox弹性盒子布局
混合划分 demo1,css: #demo1{ width: 100%; background: #ccc; display: -webkit-flex;/*表示使用弹性布局*/ } #demo1 . ...
- sed and awk学习笔记
sed and awk 背景 awk起源追溯至sed和grep,进而追溯至共同的行编辑器ed.实用工具grep来源于ed命令:g/re/p .实用工具awk和sed有一个共同的选项-f用于指定脚本的名 ...
- java:访问权限-protected实例
在不同包,子类继承后可以使用父类的protect权限的属性或方法 父类: package com.tinyphp; public class Father { protected String nam ...
- Java API ——Collection集合类 & Iterator接口
对象数组举例: 学生类: package itcast01; /** * Created by gao on 15-12-9. */ public class Student { private St ...
- iOS处理XMl提供GDataXMLNode下载的链接
GDataXMLNode .好东西,处理xml 在iOS 中使用.可以编辑和读取Xml文档.支持Xpath.这个很好. GDataXMLNode.h GDataXMLNode.m 文件很不好找啊. / ...
- Fragment 和 FragmentActivity的使用(二)
今天继续完成剩下的学习部分,现在项目很多地方使用viewpager来提供滑动,今天记录学习viewpager配合fragment的显示,增加一个CallLogsFragment配合之前SMSLis ...
- bzoj1053: [HAOI2007]反素数ant
51nod有一道类似的题...我至今仍然不会写暴搜!!! #include<cstdio> #include<cstring> #include<iostream> ...
- asp.net获取当前页面源码并生成静态页面
StringWriter stringWriter = new StringWriter(); HtmlTextWriter htmlWriter = new HtmlTextWriter(strin ...
- websocket webworker
对我来说最快的学习途径是实践,所以找两个东西来练手.一个是websocket一个是webwoker,今天先说第一个. 要理解socket就要先理解http和tcp的区别,简单说就是一个是短链,一个是长 ...
- QPS、PV和需要部署机器数量计算公式(转)
术语说明: QPS = req/sec = 请求数/秒 [QPS计算PV和机器的方式] QPS统计方式 [一般使用 http_load 进行统计] QPS = 总请求数 / ( 进程总数 * 请求 ...