首先我要说,csdn上很多虽然可以AC的代码其实都是错的!不信还请您往下看。
一开始我本人对这题的符号匹配问题最开始有点迷,所以是上csdn上搜的题解,15.建立二叉树的二叉链表存储结构_杳杳_柒的博客-CSDN博客,用的是一次读两个字符的一种方法。
我看懂之后没多想,就这么过去了。
然后今天我看我朋友用一次读一个字符的思路写这道题的代码时候,发现了一个问题,cdsn上这道题的绝大多数题解,都没有考虑连续的两个‘)’的情景,第二个‘)’并没有参与树的构建,不相信的可以自行输入这个测试数据:
G(A(B(#,D),C(E(#,F),I(J,K))),H)
不过上面这个数据是连续的三个‘)’,本质一样的
你会发现最后一个H所在节点你并没有构建。
分析后知道是对读到')'之后的操作有些问题,但由于noj的测试数据并不多,这种情况没有考虑也可以AC。但其实真正写的话应该还是要考虑的。然后我就借朋友的代码稍微改了一下。
这是他的原始代码,可以实现测试数据并且AC,但无法实现刚刚那个特殊例子
#include <stdio.h>
#include <stdlib.h>
typedef struct BiNode
{
char data;
struct BiNode *Lchild, *Rchild;
} BiNode, *BiTree;
void BuildPreorder(BiTree *T)
{
char ch;
ch = getchar(); //读入一个字符
if (ch == ')') //如果是‘)’直接返回
{
return;
}
if (ch == ',') //如果是‘,’则下一个读入字符必然是字母,为节点
{
BuildPreorder(&(*T)); //构建新节点
}
if (('A' <= ch && ch <= 'Z') || ch == '#') //若是字母(#与字母无异),则当场构建节点
{
*T = (BiTree)malloc(sizeof(BiNode));
(*T)->data = ch;
(*T)->Lchild = NULL;
(*T)->Rchild = NULL;
ch = getchar(); //构建完成之后读入下一个字符
if (ch == ')' || ch == ',') //如果是‘)’‘,’则返回
{
return;
}
if (ch == '(') //如果是‘(’说明要构建左右子树
{
BuildPreorder(&((*T)->Lchild)); //递归
BuildPreorder(&((*T)->Rchild));
}
}
}
void PreorderTraverse(BiTree T) //简简单单的先序遍历
{
if (T == NULL)
return;
printf("%c", T->data);
PreorderTraverse(T->Lchild);
PreorderTraverse(T->Rchild);
}
int main()
{
BiTree T1; //根节点构建
T1 = (BiTree)malloc(sizeof(BiNode));
(T1)->Lchild = NULL;
(T1)->Rchild = NULL;
BuildPreorder(&T1);
PreorderTraverse(T1);
return 0;
}
我修改后的
#include<stdio.h>
#include<stdlib.h>
typedef struct BiNode
{
char data;
struct BiNode *Lchild,*Rchild;
}BiNode,*BiTree;
char getch() //对连续的‘)’进行处理的函数
{
char ch=getchar(); //读入‘)’的下一个字符
if(ch==')') //如果还是‘)’
return getch(); //递归再次调用函数
if(ch=='\n') //如果连续括号在字符串末尾,则返回NULL退出
return NULL;
//这里你一定会奇怪:逗号的情况呢?
//没啥奇怪的,我忘写了而已
//但这个代码成功构建了上面的三连括号的树
//还请首先请看下文我的具体思路
}
void BuildPreorder(BiTree* T)
{
char ch;
ch=getch();
if(ch==')')
{
ch=getchar();
if(ch==',')
{
BuildPreorder(&(*T));
}
else
return;
}
if(ch==',')
{
BuildPreorder(&(*T));
}
if(('A'<=ch&&ch<='Z')||ch=='#')
{
*T=(BiTree)malloc(sizeof(BiNode));
(*T)->data=ch;
(*T)->Lchild=NULL;
(*T)->Rchild=NULL;
ch=getchar();
if(ch==')'||ch==',')
{
return;
}
if(ch=='(')
{
BuildPreorder(&((*T)->Lchild));
BuildPreorder(&((*T)->Rchild));
}
}
}
void PreorderTraverse(BiTree T)
{
if(T==NULL)
return;
printf("%c",T->data);
PreorderTraverse(T->Lchild);
PreorderTraverse(T->Rchild);
}
int main()
{
BiTree T1;
T1=(BiTree)malloc(sizeof(BiNode));
(T1)->Lchild=NULL;
(T1)->Rchild=NULL;
BuildPreorder(&T1);
PreorderTraverse(T1);
return 0;
}
其实本质就是:
一般在遇到右括号之前,读入的都是一个字母、一个符号、一个字母、一个符号······的操作,然后“字母),”的情况下特殊处理一下,具体在此我不做赘述。
我修改的部分,在读完字母加符号的操作之后如果单独读到了‘)’的话,就会调用我定义的getch函数,进入递归,如果再读到‘)’则再调用,直到——读到‘,’,则创立当前树节点,因为逗号之后必然是字母,所以不会出错;又或者读到回车‘\n’,则返回NULL,树建立完毕,退出(是考虑连续的右括号出现在字符串最末端的情况,否则会陷入死循环,但后来发现其实也不需要这个判断语句,因为‘\n’也算是一个字符,最终会被读到,发现是非‘)’的字符,就会返回为BuildPreorder里的ch的值,并且在BuildPreorder不满足if条件而直接结束函数),然后我输入了最开始的那个特殊数据,成功正确构建了二叉树。
但是我和朋友梳理程序运行过程时发现,我的getch函数里并没有写ch==‘,’的代码,那为什么还是成功运行了呢?在我getch函数读到‘,’之后到底是怎么返回函数值的呢?
为此我把这段代码调出来进行测试
#include<stdio.h>
char getch()
{
char ch=getchar();
if(ch==')')
return getch();
if(ch=='\n')
return NULL;
}
int main()
{
char ch=getch();
printf("%c",ch);
return 0;
}
后来在我的vs上发现根本不给我运行,我之前是在dev上运行的,可以运行
说说当时用的几个测试数据:
输入
)), ),)
输出
, ,
然后我又换了几个写法(scanf等输入方法以及一些处理,在此不做赘述),最终得出结论,返回类型为char的函数,默认返回值是在缓冲区读到的最后一个字符。
至于为什么是缓冲区而不是其中的数据,因为我测试了这个代码
#include<stdio.h>
char getch()
{
char ch='*';
if(ch==')')
return getch();
if(ch=='\n')
return NULL;
if(ch==',')
return ',';
}
int main()
{
char ch=getch();
printf("%c",ch);
return 0;
}
也就是直接给ch赋值,然后在dev上输出了一个小方格,我也不太懂,反正就是不大行,我个人得出结论就是默认返回了缓冲区的最后一个字符。所以我在一开始没有写if(ch==',')的判断情况下、以及将if(ch=='\n')的情况删去,仍然可以成功运行代码。
算是我个人写代码过程中的一些小发现吧,百度了一下发现没人讲过这个char类型的默认返回值,就在此写了篇文章记录一下,如有错误还请大佬们批评指正。
最终完整代码如下
#include <stdio.h>
#include <stdlib.h>
typedef struct BiNode
{
char data;
struct BiNode *Lchild, *Rchild;
} BiNode, *BiTree;
char getch()
{
char ch = getchar();
if (ch == ')')
return getch();
if (ch == '\n')
return NULL;
if (ch == ',') //接上面朋友的代码,这里处理了‘,’的情况
return ','; //虽然按发现的默认返回值来看不影响,但还是写上正式一点
return NULL;
}
void BuildPreorder(BiTree *T)
{
char ch;
ch = getchar();
if (ch == ')')
{
ch = getch();
if (ch == ',')
{
BuildPreorder(&(*T));
}
else
return;
}
if (ch == ',')
{
BuildPreorder(&(*T));
}
if (('A' <= ch && ch <= 'Z') || ch == '#')
{
*T = (BiTree)malloc(sizeof(BiNode));
(*T)->data = ch;
(*T)->Lchild = NULL;
(*T)->Rchild = NULL;
ch = getchar();
if (ch == ')' || ch == ',')
{
return;
}
if (ch == '(')
{
BuildPreorder(&((*T)->Lchild));
BuildPreorder(&((*T)->Rchild));
}
}
}
void PreorderTraverse(BiTree T)
{
if (T == NULL)
return;
printf("%c", T->data);
PreorderTraverse(T->Lchild);
PreorderTraverse(T->Rchild);
}
int main()
{
BiTree T1;
T1 = (BiTree)malloc(sizeof(BiNode));
(T1)->Lchild = NULL;
(T1)->Rchild = NULL;
BuildPreorder(&T1);
PreorderTraverse(T1);
return 0;
}
感谢观看!!!