西工大 数据结构 noj 15 :建立二叉树的二叉链表存储结构(严6.70) 其他很多AC了的题解都少考虑了一类情况 以及本人的一些小发现

首先我要说,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;
}

感谢观看!!!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值