二叉树实现四则运算计算器(含源码演示和详细说明)
作者:互联网
说明:禁止转载,对源码的要求是禁止把这个东西原封不动或非常小量改动后用于课程设计(我很建议你自己动手实现,你会做的比我更好),源码仅供学习参考,思路仅供参考,仍有不足,欢迎评论指出。
1.问题定义及需求分析
二叉树算术表达式求值,设计十进制整数四则运算计算器。
1)采用二叉树等存储结构。
2)给定表达式字符串,生成二叉树。
3)对二叉树遍历求值并输出。
2.概要设计
通过宏定义预先定义可输入的最大长度maxsize。用一个结构体BtreeNode代表二叉树的节点。
通过afaToBtree函数将输入的字符串转化成二叉树,然后通过cal函数将所生成的二叉树进行遍历,从而计算出最终结果。
3.详细设计
结构体的设计:
因为二叉树的节点既有可能存放运算符,有有可能存放数字,因此在定义结构体时,除了左右孩子,又定义的存放数字的double型变量data和存放运算符的char型变量yunsuan。
typedef struct BtreeNode{
double data;//数字型节点
char yunsuan;//运算符型节点
struct BtreeNode *lchild;
struct BtreeNode *rchild;
}BtreeNode;
生成二叉树的设计:创建函数afaToBtree,输入字符串,起点s和终点e。若改字符串全为数字组成,则计算出所对应的数字,将其存储在data中。若不全为数字,则寻找优先级最低的运算符,既括号外且最右侧的+-或*/符号(都有则取+-),将其作为根节点,将改节点左侧和右侧的内容作为左右孩子,重复调用函数,通过不断调用函数,生成叶子节点均为数字的二叉树。
BtreeNode* afaToBtree(char *input,int s,int e)
{
int local_r=0,flag=0,i;
int m_m_p=0,a_s_p=0,x=0,xishu;
for(i=s;i<e;i++)
if(input[i]=='+'||input[i]=='-'||input[i]=='*'||input[i]=='/')
x++;//判断是否全为数字,如果是x取零
if(!x)
{
int y;
y=input[e-1]-'0';
for(i=e-2,xishu=1;i>=s;i--)
{
xishu=10*xishu;
y=y+xishu*(input[i]-'0');
}//将该字符串所代表的数字算出
BtreeNode* bn=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));
bn->data=y;
bn->yunsuan=NULL;
bn->lchild=NULL;
bn->rchild=NULL;
return bn;//将该数字的值返回给节点的data中
}
for(i=s;i<e;i++)
{
if(input[i]=='(')
flag++;
else if(input[i]==')')
flag--;//判断该字符是否在括号内,在内flag为1,在外为0
if(!flag)
{
if(input[i]=='*'||input[i]=='/')
m_m_p=i;//将括号外的最右侧的*或/号的位置记录下来
else if(input[i]=='+'||input[i]=='-')
a_s_p=i;//将括号外的最右侧的+或-号的位置记录下来
}
}
if((m_m_p==0)&&(a_s_p==0))
afaToBtree(input,s+1,e-1);//去掉最外层的括号
else
{
if(a_s_p>0)
local_r=a_s_p;
else if(m_m_p>0)
local_r=m_m_p;//将记录下的+-或*/号记录下来,作为根节点
BtreeNode* b=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));
b->yunsuan=input[local_r];
b->lchild=afaToBtree(input,s,local_r);
b->rchild=afaToBtree(input,local_r+1,e);//对该根节点的左侧和右侧分别再次操作
return b;
}
}
遍历二叉树求值的设计:通过double型函数cal,输入二叉树的根节点,从该根节点出发,若为数字则直接返回给函数,若为运算符则判断为加减乘除,并对该节点两端的式子进行相应的运算,若两端仍为表达式则继续调用该函数,直至全为数字,并计算出结果。
double cal(BtreeNode *root){
switch(root->yunsuan){
case '+':{
return cal(root->lchild)+cal(root->rchild);
break;
}
case '-':{
return cal(root->lchild)-cal(root->rchild);
break;
}
case '/':{
return cal(root->lchild)/cal(root->rchild);
break;
}
case '*':{
return cal(root->lchild)*cal(root->rchild);
break;
}//通过对根节点的运算符的遍历,判断加减乘除并进行操作,最后将结果返回
}
return root->data;
}
4.调试分析:
在测试中,发现了输出结果一直为0的问题,后发现将double型数据当作int型用%d输出了,将其改为%lf后恢复正常。后在测试中发现了计算结果与实际结果不符的问题,经验证,是根节点的右孩子的计算出现了问题。通过不断的排查,发现在红字体i=s处,写成了i=0,从而导致无论s是几,都会从i=0开始遍历,因此对左指数无影响,而对右子树有影响,因为s不再是0,从而导致计算结果错误。在改正该错误后,问题得到解决,计算结果正确。
for(i=s;i<e;i++)
if(input[i]=='+'||input[i]=='-'||input[i]=='*'||input[i]=='/')
x++;//判断是否全为数字,如果是x取零
if(!x)
{
int y;
y=input[e-1]-'0';
for(i=e-2,xishu=1;i>=s;i--)
{
xishu=10*xishu;
y=y+xishu*(input[i]-'0');
}//将该字符串所代表的数字算出
5.使用说明
调整最大输入长度,可以通过修改宏定义来实现。如设置最大长度为100,则输入
#define maxsize 100
输入时可输入数字及+-*/符号,优先计算的可用()括起来,计算顺序与我们日常的计算顺序一致。如输入:12+(21-4)/3+(3+2)*14
6.测试结果
7.附录
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxsize 100//可输入的最大长度
typedef struct BtreeNode{
double data;//数字型节点
char yunsuan;//运算符型节点
struct BtreeNode *lchild;
struct BtreeNode *rchild;
}BtreeNode;
BtreeNode* afaToBtree(char *input,int s,int e)
{
int local_r=0,flag=0,i;
int m_m_p=0,a_s_p=0,x=0,xishu;
for(i=s;i<e;i++)
if(input[i]=='+'||input[i]=='-'||input[i]=='*'||input[i]=='/')
x++;//判断是否全为数字,如果是x取零
if(!x)
{
int y;
y=input[e-1]-'0';
for(i=e-2,xishu=1;i>=s;i--)
{
xishu=10*xishu;
y=y+xishu*(input[i]-'0');
}//将该字符串所代表的数字算出
BtreeNode* bn=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));
bn->data=y;
bn->yunsuan=NULL;
bn->lchild=NULL;
bn->rchild=NULL;
return bn;//将该数字的值返回给节点的data中
}
for(i=s;i<e;i++)
{
if(input[i]=='(')
flag++;
else if(input[i]==')')
flag--;//判断该字符是否在括号内,在内flag为1,在外为0
if(!flag)
{
if(input[i]=='*'||input[i]=='/')
m_m_p=i;//将括号外的最右侧的*或/号的位置记录下来
else if(input[i]=='+'||input[i]=='-')
a_s_p=i;//将括号外的最右侧的+或-号的位置记录下来
}
}
if((m_m_p==0)&&(a_s_p==0))
afaToBtree(input,s+1,e-1);//去掉最外层的括号
else
{
if(a_s_p>0)
local_r=a_s_p;
else if(m_m_p>0)
local_r=m_m_p;//将记录下的+-或*/号记录下来,作为根节点
BtreeNode* b=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));
b->yunsuan=input[local_r];
b->lchild=afaToBtree(input,s,local_r);
b->rchild=afaToBtree(input,local_r+1,e);//对该根节点的左侧和右侧分别再次操作
return b;
}
}
double cal(BtreeNode *root){
switch(root->yunsuan){
case '+':{
return cal(root->lchild)+cal(root->rchild);
break;
}
case '-':{
return cal(root->lchild)-cal(root->rchild);
break;
}
case '/':{
return cal(root->lchild)/cal(root->rchild);
break;
}
case '*':{
return cal(root->lchild)*cal(root->rchild);
break;
}//通过对根节点的运算符的遍历,判断加减乘除并进行操作,最后将结果返回
}
return root->data;
}
int main()
{
char input[maxsize-1];//保存输入的字符串
int s=0,e;
double result;
printf("请输入需计算的表达式:");
scanf("%s",&input);//读入结果
e=strlen(input);//计算字符串的长度
result=cal(afaToBtree(input,s,e));//生成二叉树并计算出结果
printf("计算结果为%lf\n",result);//输出最终结果
}
标签:四则运算,源码,二叉树,cal,input,BtreeNode,root,节点 来源: https://blog.csdn.net/qq_42181309/article/details/93867808