题目的来源是我们的学校数据结构课程的实验报告~~~
这个题目不能说是很有难度吧,但是这个题目的研究过程确实是把我逗笑了,因为这个题目我误解了,第一次感受到在这个编程的圈子里面,居然会出现“歧义”的现象;
代码还是放一份吧,这个只能说是二叉树初学者的水平,这个题目就是打印输出这个已知的二叉树的广义表,以及三种遍历方式的结果输出;
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
// 二叉树节点结构体
typedef struct node {
char data;
struct node* lchild;
struct node* rchild;
} BinNode;
// 创建二叉树
BinNode* CreateBinTree() {
BinNode* t;
char ch='0';
ch = getchar();
if (ch == '0')
{
t = NULL;
}
else
{
t = (BinNode*)malloc(sizeof(BinNode));
t->data = ch;
t->lchild = CreateBinTree();
t->rchild = CreateBinTree();
}
return t;
}
// 广义表表示二叉树
void ListBinTree(BinNode* t) {
if (t != NULL) {
printf("%c", t->data);
if (t->lchild != NULL || t->rchild != NULL) {
printf("(");
ListBinTree(t->lchild);
if (t->rchild != NULL) {
printf(",");
}
ListBinTree(t->rchild);
printf(")");
}
}
}
// 前序遍历
void PreOrder(BinNode* t) {
if (t != NULL) {
printf("%3c ", t->data);
PreOrder(t->lchild);
PreOrder(t->rchild);
}
}
// 中序遍历
void InOrder(BinNode* t) {
if (t != NULL) {
InOrder(t->lchild);
printf("%3c ", t->data);
InOrder(t->rchild);
}
}
// 后序遍历
void PostOrder(BinNode* t) {
if (t != NULL) {
PostOrder(t->lchild);
PostOrder(t->rchild);
printf("%3c ", t->data);
}
}
int main() {
BinNode* t = NULL;
printf("请先进行这个前序序列的输入,虚节点使用0进行表示:\n");
t = CreateBinTree();
printf("下面的这个就是广义表表示的二叉树:\n");
ListBinTree(t);
printf("\n二叉树的前序遍历的结果是:\n");
PreOrder(t);
printf("\n二叉树的中序遍历的结果是:\n");
InOrder(t);
printf("\n二叉树的后序遍历的结果是:\n");
PostOrder(t);
return 0;
}
下面的这个是老师给出来的这个示例:这个输出在我们的程序里面也是有所体现的;
先来看一下我是怎么理解这个问题的(错误的理解):开始的时候老师没有给这个二叉树,但是我根据下面的这个示例就画出来了左边的这个情况,补成一个满二叉树之后,我发现这个0代表的就是这个没有节点的地方呗,实际上这个输入的内容就是一个满二叉树(没有的地方使用这个0进行代替);
于是我按照老师的这个案例进行输入,发现这个确实是没有问题的,但是我还是想看一下这个程序的健壮性,于是就有了我自己的这个输入;
下面的这个图的右边是我自己构建的一个二叉树,我按照上面的这个理解输入了这个我认为的这个应该输入的内容,但是发现这个打印的结果却差强人意;于是我开始怀疑这个代码的问题;
我当时也问了老师,但是老师并没有给出回应,我课下问了其他的老师,其他的老师看了我的这个输入之后告诉我我的这个二叉树的创建是有问题的;
于是我就在这个二叉树的创建上面下功夫,但是这个就是一个简单的递归过程,我真的看不出来问题(这个是上周三的问题,明天是又要去上这个数据结构的课),今天又换了一个老师去问,因为我不想把一个错误的代码提交上去(当时的我还是坚持认为这个代码是有问题的);
我今天又问了一个老师:才知道这个题目具体是在干什么:
下面的这个才是我们的输入的正确理解:就是当遇到0的时候,他就没有这个叶子结点了,所以这个是第一个错误的地方,第二个就是即使我们走到了这个叶子结点的位置,我们还是要继续向下判断的,判断这个是不是叶子结点(这个代码里面就是判断这个是不是0,就是说即使到了这个叶子结点,我们还要往下多走一步)
因此,这个二叉树的正确的输入应该是下面的这个情况:
同理,对于老师的这个给的案例:这个枚举是正确的,但是我的这个理解是不对的;下面的这个才是正确的理解,就是我们走到G之后还是要继续向下进行判断的;
但是发现即使我们理解正确了,这个输入是没有变化的,就是我们的这个正确理解和错误理解的这个输入情况是一致的,这个就比较离谱了,也就是说,我们会以为我们的理解是正确的,实际上我们的理解是错误的;
通过这个题目,我想要表达的观点是什么:
1)首先必须承认我确实是技不如人,如果我很清楚这个二叉树里面的这个create创建二叉树的过程的代码逻辑,我也不会理解错,但是我是根据这个输入的情况去倒退的,这个思路就是不对的;
2)很多时候,看似自己理解的是对的,实际上是不正确的(我是通过这个题目才真正的体会到这句话的含义的);
3)因为这个题目是我自己钻研了很久的,所以从这个自己独立完成,到老师解答,错误理解,正确理解这个过程我是全部经历了一遍,所以当老师把这个错误说出来时候,我是真的有一种很明朗的感觉;
但是对于其他人而言,没有经历这个过程,所以即使看完这个过程,可能也觉得没有什么,但是对于经历的人而言不是这个样子的;
4)我只是发现,不仅是对于这个题目,其实对于其他的知识而言,我们可能觉得我们理解了,但是我们可能真的没有理解;在当下,我们太过于想要速成或者是快速掌握某种东西了,这个其实并不好,我之前也是学习过这个二叉树的,但是这个题目就可以证明我学的并不咋地;
我只是根据这个题目的研究过程,确实是很有感慨,发现我们的这个学习心理是不对的,我最近也是学到了这个javaweb,但是真的做一个简单的demo的时候,发现自己连这个post,get之间的区别都不知道,cs之间是如何进行通信的也是一头雾水,只能再回去补了;
是这个题目就可以证明我学的并不咋地;
我只是根据这个题目的研究过程,确实是很有感慨,发现我们的这个学习心理是不对的,我最近也是学到了这个javaweb,但是真的做一个简单的demo的时候,发现自己连这个post,get之间的区别都不知道,cs之间是如何进行通信的也是一头雾水,只能再回去补了;
我想到一个词:省流,看似我们很聪明,短时间里面学到了这个精华,但是没有经过系统深入的学习理解,往往是学不到精髓的,我只是接这篇文章的机会,总结下最近的学习,想让自己的这个学习的脚步慢下来,多一些思考和反思的时间,愿你们亦然~~