题目来源:http://ac.jobdu.com/problem.php?pid=1008
我的代码:已ac
// 二叉搜索树
//scanf每遇到(空格 回车 跳格键 非法输入)时作为一个数据的输入结束,
//而不是scanf函数的结束,scanf函数 只有在每一个数据域均有数据 回车后才结束 ;
//也就是说,比如 scanf("%s",str) 输入 i love you 回车 输出时只输出 i %s接收了i作为其数据,并在回车后结束函数scanf 但注意!!!love you 字符串还在缓冲区
//对于%c 把空格和转义字符也都作为一个字符
#include <iostream>
#include <stdio.h>
#include <string>
#include <stdlib.h> //int atoi(const char* nptr)将字符转换为整数
using namespace std;
int p[21][1024];
void erchasort(int i,int array[][1024],int a,int current){
if(a<array[current][i]){
if(array[current][2*i]==-1)
array[current][2*i]=a;
else
erchasort(2*i,array,a,current);
}
else if(a>array[current][i]){
if(array[current][2*i+1]==-1)
array[current][2*i+1]=a;
else
erchasort(2*i+1,array,a,current);
}
}
int main(){
int n=0;
while(scanf("%d",&n)!=EOF){
if (n==0) break;
for(int i=0;i<21;i++) //要时刻注意这种初始化问题!!!
for(int j=0;j<1024;j++)
p[i][j]=-1;
for(int j=0;j<=n;j++){
//输入一个序列p[0][],随后输入n个序列p[i][](i>0)
//对于一个序列,如果第t个数据后面第数小于这个数据,就存在array[2*t-1]中,如果大于它就存在array[2*t]中,如果相等就忽略
char tem[10]; //用于存储每次输入的待比较序列
int tep[10];
int tag=0;//上一个数据所在位置
scanf("%s",tem);
for(int i=0;i<10&&tem[i]!=0;i++){
// tep[i]=atoi(&tem[i]); //atoi的用法
tep[i]=(int)(tem[i])-48;
// cout<<"tep["<<i<<"]="<<tep[i]<<endl;
if(tag==0){
tag=1;
p[j][1]=tep[i];
// cout<<p[i][1];
}
else
erchasort(1,p,tep[i],j);
}
}
for(int i=1;i<=n;i++){
int j=1;
for(;j<=1024;j++)
if(p[i][j]!=p[0][j]){
cout<<"NO"<<endl; //cout<<"p[0]["<<j<<"]="<<p[0][j];cout<<"p["<<i<<"]["<<j<<"]="<<p[i][j];
break;}
if (j==1025) cout<<"YES"<<endl;
// else cout<<"NO"<<endl;
}
}
return 0;
}
1.首先查看根节点是否有数据,若没有,该数据即为根节点;
2.若根节点已存在,比较该数据与根节点数据的大小,若相等,忽略,不做任何操作,若比根小,插入到左子树,若比根大,插入到右子树;
3.要注意二叉树的存储方式 若节点下标为i, 其左孩子坐标为2*i,右孩子坐标为2*i+1 根节点下标为1. 二维数组 p[n][m]用来存储各个二叉树,所以n=21,考虑到特殊情况二叉树如果十个节点都是右孩子的情况,则需要存储单元为 1+2+2^2+...+2^9=1023 因根节点下标从1开始,所以m=1024 ( 这里可以发现二叉树的顺序存储方式是比较浪费空间的,但是查找速度比较快)。
按照上述方法,可以看出用递归可以很容易实现void erchasort (int i,int array[][1024],int a,int current);
我自己遇到的问题是处理输入数据:scanf函数
scanf函数经常困惑我的是如何判断输入结束,因为它常会被用到这种形式 while(scanf(...)!=EOF){...} 可能有多组输入,而每运行一次scanf ()作为一组输入 。回车并不代表一次输入的结束!! scanf每遇到空格/回车/跳格键以及非法输入时作为一个输入数据的结束,如果它的数据域中还有每接收到数据的情况,它会等到再次收到数据时作为下一个数据域的数据,只有在每一个数据域均收到数据时,回车,本次scanf函数才算结束。
另外,还要特别注意键盘盘缓冲区中的数据。比如 scanf("%s",str) 输入 i love you 回车 输出时只输出 i %s接收了i作为其数据,并在回车后结束函数scanf 但注意!!!love you 字符串还在缓冲区。
当在括号参数中固定输入的格式时,我们可以很容易判断输入完成(这种情况一般是我们肯定地知道一组输入数据的数目),但是,当一组输入数据的个数是不确定时,我们最好把输入当作字符串处理。注意,scanf接收的是没有空格的字符串,若希望把带有空格的输入均作为一次输入,可以使用gets()函数。
本题中的情况是输入多个一位的数字,我们可以接收后转化为数字(之前是想利用atoi函数,但是发现它将当前指针指向的字符到结尾的一次全部转化,然后作为一个int整数,这不是我们本题中所希望的),所以手动的利用ascii进行转换。
写程序的时候逻辑关系一定要清楚,比如一些初始条件的设定(下标从0还是1开始)、一些条件的判断、代码片段之间的关系(比如本题中for循环是放到while循环的里面还是外面),一些逻辑错误可能会导致无限循环,很多错误其实都是很简单的。
还有特别注意每次的初始化问题!!不注意的话很容易将上次处理的结果遗留到本次处理中来,从而影响结果的正确性。实现所需要的功能是目的,利用技巧节省时间或空间是次要的。