题目

思路

  • 构建二叉搜索树,并保存先序遍历和中序遍历的序列在samplePreOrder,sampleInOrder
  • 每遇到一个新的序列,构建一棵二叉搜索树,保存先序遍历和中序遍历的序列testPreOrder,testInOrder
  • 需要树一棵,字符串四个

实现中遇到的错误

  1. 递归基直接返回return creat(x);,少了一个操作,root = creat(x); return root;

    • 原因:递归的层次没有区分清楚,错误地认为构造一个节点,然后返回给M->lchild,这个想法中的M是上一层递归中的节点,不应出现在这层的递归实例中。
    • 正确思路:本层递归实例,是最底层的递归,要往空树中插入节点,空树就是root,构造一个节点,要赋值给root,再返回root。
  2. 非递归基时,没有写return,致命错误,递归最重要的接口是传入的参数和返回的值。
    • 如果不指明非递归基的递归实例中的返回值,将只能在递归基中返回,即只返回叶节点,每层递归结束后,树都只有一个节点!
    • 一层正确的递归应该是,传入一棵树,添加一个节点,再返回增加了节点以后的树。
    • 结合上述正确情况,再仔细想想不写return的情况,新一层的递归实例,不会增加树的节点!整体递归结束后,树只有一个节点——最后插入的节点。
    • 对递归函数insert()的理解需要再进一步,每次传入一棵树的根的指针,最后返回这个指针。
  3. 出现一个“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-二叉搜索树的更多相关文章

  1. 九度oj题目1009:二叉搜索树

    题目描述: 判断两序列是否为同一二叉搜索树序列 输入:                        开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接 ...

  2. 九度oj 题目1009:二叉搜索树

    题目1009:二叉搜索树 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5733 解决:2538 题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n&l ...

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

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

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

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

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

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

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

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

  7. 九度oj 题目1367:二叉搜索树的后序遍历序列

    题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 输入: 每个测试案例包括2行: 第一行为1个整数 ...

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

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

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

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

  10. 九度oj题目1002:Grading

    //不是说C语言就是C++的子集么,为毛printf在九度OJ上不能通过编译,abs还不支持参数为整型的abs()重载 //C++比较正确的做法是#include<cmath.h>,cou ...

随机推荐

  1. lintcode: search for a range 搜索区间

    题目 搜索区间 给定一个包含 n 个整数的排序数组,找出给定目标值 target 的起始和结束位置. 如果目标值不在数组中,则返回[-1, -1] 样例 给出[5, 7, 7, 8, 8, 10]和目 ...

  2. Linux和Linux之间共享目录

    1.Linux 服务器端NFS服务器的配置 以root身份登陆Linux服务器,编辑/etc目录下的共享目录配置文件exports,指定共享目录及权限等. 执行如下命令编辑文件/etc/exports ...

  3. 开源入侵检测系统OSSEC搭建之三:Web界面安装

    注意:以下操作需在OSSEC服务端进行设置 一.下载analogi,存放于/var/www/html/下并赋予权限 [root@localhost ~]# wget https://github.co ...

  4. 关于ssh的一篇很好的文章

    源地址:http://www.w3hacker.com/?p=156   ssh-agent的manual写得倒是挺详细,可看了好几次都没怎么搞明白.08年在网上找到了非常好的一篇文章,An Illu ...

  5. AndroidJNI 调用JAVA(转)

    转自:http://www.cnblogs.com/likwo/archive/2012/05/21/2512400.html   1. JNIEnv对象    对于本地函数    JNIEXPORT ...

  6. How to learn linux device driver

    To learn device driver development, like any other new knowledge, the bestapproach for me is to lear ...

  7. cololection

    package cn.bjsxt.col; /** * 简化迭代器原理 * hasNext * next * @author Administrator * */ public class MyArr ...

  8. Android动画 三种动画

    Android可以使用三种动画 Frame Animation-帧动画 ,就像GIF图片,通过一系列Drawable依次显示来模拟动画的效果 Tween Animation-补间动画,给出两个关键帧, ...

  9. gulp browser-sync自动刷新插件

    很久没弄gulp了,都快忘了,今天又来温习下browser-sync 自动刷新插件,在安装的时候出现以下提示: $ npm install browser-sync --save-dev> ws ...

  10. Android中View转换为Bitmap及getDrawingCache=null的解决方法

    1.前言 Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片:Coverflow中需要把一页一 页的view转换为Bitmap.以便实现复杂的图形效果 ...