实验三---四则运算表达式求值

一、基本要求:

( 1 ) 利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值。

( 2) 输入输出格式:
输入格式:在字符界面上输入一个中缀表达式,回车表示结束。
请输入表达式:
输入一个中缀表达式
输出格式:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后
缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。
逆波兰表达式为:

输出逆波兰表达式

运算结果为:输出运算后的结果

测试数据
输入: 21+23*( 12-6)
输出: 21 23 12 6 -*+

二、基本思路

中缀表达式-》二叉树-》后序遍历-》计算

1.中缀表达式-》二叉树の需要考虑的问题:

  • 保存的二叉树是什么样子的,才能使得后序遍历就能得到后缀表达式

操作符的等级设置

最上面的等级最小

设计函数ToTree来实现此过程:该过程递归

递归的判断:

1.怎样按同类更小问题解决:找到当前字符串中的最小等级操作符给data,左边的表达式给左子树,右边的表达式给右子树,左边和右边分别是一个更短的字符串的分支问题

2.各个递归怎么减小问题规模:左边和右边分别是一个更短的字符串的分支问题

3.什么情况可以当做基例:到叶子节点的情况,也就是说表达式里面没有运算符了,然后data=操作数,左右子树=NULL

4.能否最后达到基例:可以要么我写个P啊

  • 怎么找到当前字符串中的最小等级的操作符?

首先先要把各个字符都赋好等级,我把数字也赋值了,最开始没有,还写了个函数提取了所有操作符,后来发现这样很难把等级数组和算式相对应,又推倒重新写了一次,我心在滴血!,如果把数字都负上就可以对上了,查找最小的时候下标是可以返回的,对应了相应的操作符。

 for(i=0;suanshi[i]!='\0';i++){if(suanshi[i]=='('){duoshaoji++;//记录第几层括号,几层括号就把里面的运算符的等级提高n*100<img alt="惊讶" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/ohmy.gif" />☜它好聪明!dengji[i]=0;dengji[i]=0;}else if(suanshi[i]==')'){duoshaoji--;dengji[i]=0;}else if(suanshi[i]=='+'||suanshi[i]=='-')dengji[i]=1+duoshaoji*100;else if(suanshi[i]=='*'||suanshi[i]=='/')dengji[i]=2+duoshaoji*100;elsedengji[i]=-1;}
  • 怎么处理()的问题

因为在树中我们不需要(),所以()肯定不能到树里,但是我们还需要()来辅助判断运算等级,经过分析发现,只要把最开始进函数的表达式两边的括号去掉就行了,这样就对后面的不影响了。

 if(suanshi[0]=='('&&suanshi[length]==')'){suanshi++;suanshi[length-1]='\0';}//去括号的过程,只去那种开头是括号结尾是括号的情况
  • 最后的数字和前面的char型不符合,怎么办?

最开始我设的树节点是一个char,后来用了什么ASII的编码把char-》int的变来变去,还是不成,最后只好托马重写,改成了char数组的形式,这样就随之而来一些问题,在之后的后序遍历赋值里会遇到。

  • 这一段是我闹心的心情札记:接着昨天的唠唠叨叨,心碎,今天被猪脚再次挑出个毛病,算起来又是我之前写的逆波兰的程序的错误,我觉得有时间的话我真的应该把逆波兰的程序在写一遍了,我不会说我上节课改逆波兰改了4次吧,算上这回应该有5、6次了吧,心碎,不过也确实怪我自己考虑问题不全,没有想到数字和操作符的数目可能不相符的情况,又让这个猪脚挑出了猫饼,以后我要叫他猫饼猪脚。这么萌的名字一定配的上他用的可爱的少女心的粉色本本~
void ToTree(BiTree &T,char *suanshi)
{  int duoshaoji=0,i=0,length=suanshilength(suanshi),j=0,min=0,minn=0,k=0;char *lsuanshi=NULL,*rsuanshi=NULL,exc=NULL;if(suanshi[0]=='('&&suanshi[length]==')'){suanshi++;suanshi[length-1]='\0';}//去括号的过程,只去那种开头是括号结尾是括号的情况length=suanshilength(suanshi);int *dengji;dengji=(int *)malloc((length+1)*sizeof(int));for(i=0;suanshi[i]!='\0';i++){if(suanshi[i]=='('){duoshaoji++;dengji[i]=0;}else if(suanshi[i]==')'){duoshaoji--;dengji[i]=0;}else if(suanshi[i]=='+'||suanshi[i]=='-')dengji[i]=1+duoshaoji*100;else if(suanshi[i]=='*'||suanshi[i]=='/')dengji[i]=2+duoshaoji*100;elsedengji[i]=-1;}T=(BiTreeNode *)malloc(sizeof(BiTreeNode));if(checkfuhao(suanshi))//有符号的情况{for(j=1;j<length+1;j++){if(dengji[j]>0){min=dengji[j];minn=j;break;}}for(j=1;j<length+1;j++){if(dengji[j]>0&&min>dengji[j]){  min=dengji[j];minn=j;}}T->data[0]=suanshi[minn];T->data[1]='\0';//printf("****%c\n",T->data);lsuanshi=suanshi;lsuanshi[minn]='\0';rsuanshi=&suanshi[minn+1];ToTree(T->leftChild,lsuanshi);ToTree(T->rightChild,rsuanshi);}else//没有符号的情况{strcpy(T->data,suanshi);T->leftChild=NULL;T->rightChild=NULL;}free(dengji);
}
  • 进行后序遍历时:要注意我们后序遍历输出的同时,主要的操作是把后序遍历的结果给到逆序的字符串里,这个要用到strcat……全都是我的鱼唇的想法,大家有好的思路可以告诉我,我觉得自己做的好蠢
void preorder(BiTree t,char *p)
{  int k=0,x=0;if(t){  preorder(t->leftChild,p);  preorder(t->rightChild,p);if(t->data[0]=='+'||t->data[0]=='-'||t->data[0]=='/'||t->data[0]=='*'){printf("%c ",t->data[0]);if(*p!='\0'){  strcat(p," ");strcat(p,t->data);}else{ strcat(p,t->data);}}else{printf("%s ",t->data);if(*p!='\0'){ strcat(p," ");strcat(p,t->data);}else{ strcat(p,t->data);}}}
}
  • 最开始的时候极其鱼唇,居然没有建立树,给树空间,导致后面怎么都不对,后来看了一遍又一遍才知道自己里错了。

其他的是上次的逆波兰~

贴一下所有代码

//#include "stdafx.h"
#define MAXNUM 100
#define OVERFLOW -2;
#include<iostream>
#include<string>
#include<stdlib.h>
#include<stdio.h>
#include<iomanip>
using namespace std; char suan[MAXNUM],*p=suan;typedef struct node
{  struct node *leftChild;  struct node *rightChild;  char data[15];
}BiTreeNode, *BiTree;int suanshilength(char *suanshi)
{int i=0,k=0;for(i=0;suanshi[i]!='\0';i++){k++;}k--;return k;
}bool checkkuohao(char *suanshi)
{int i=0,k=0;bool flag=1;for(i=0;suanshi[i]!='\0';i++){if(k<0){flag=0;break;}if(suanshi[i]=='(')k++;if(suanshi[i]==')')k--;}if(k!=0)flag=0;return flag;} bool checkfuhao(char *suanshi)
{int i=0;bool flag=0;for(i=0;suanshi[i]!='\0';i++){if(suanshi[i]=='+'||suanshi[i]=='-'||suanshi[i]=='*'||suanshi[i]=='/'){flag=1;}}return flag;
}void ToTree(BiTree &T,char *suanshi)
{  int duoshaoji=0,i=0,length=suanshilength(suanshi),j=0,min=0,minn=0,k=0;char *lsuanshi=NULL,*rsuanshi=NULL,exc=NULL;if(suanshi[0]=='('&&suanshi[length]==')'){suanshi++;suanshi[length-1]='\0';}//去括号的过程,只去那种开头是括号结尾是括号的情况length=suanshilength(suanshi);int *dengji;dengji=(int *)malloc((length+1)*sizeof(int));for(i=0;suanshi[i]!='\0';i++){if(suanshi[i]=='('){duoshaoji++;dengji[i]=0;}else if(suanshi[i]==')'){duoshaoji--;dengji[i]=0;}else if(suanshi[i]=='+'||suanshi[i]=='-')dengji[i]=1+duoshaoji*100;else if(suanshi[i]=='*'||suanshi[i]=='/')dengji[i]=2+duoshaoji*100;elsedengji[i]=-1;}T=(BiTreeNode *)malloc(sizeof(BiTreeNode));if(checkfuhao(suanshi))//有符号的情况{for(j=1;j<length+1;j++){if(dengji[j]>0){min=dengji[j];minn=j;break;}}for(j=1;j<length+1;j++){if(dengji[j]>0&&min>dengji[j]){  min=dengji[j];minn=j;}}T->data[0]=suanshi[minn];T->data[1]='\0';//printf("****%c\n",T->data);lsuanshi=suanshi;lsuanshi[minn]='\0';rsuanshi=&suanshi[minn+1];ToTree(T->leftChild,lsuanshi);ToTree(T->rightChild,rsuanshi);}else//没有符号的情况{strcpy(T->data,suanshi);T->leftChild=NULL;T->rightChild=NULL;}free(dengji);
} void preorder(BiTree t,char *p)
{  int k=0,x=0;if(t){  preorder(t->leftChild,p);  preorder(t->rightChild,p);if(t->data[0]=='+'||t->data[0]=='-'||t->data[0]=='/'||t->data[0]=='*'){printf("%c ",t->data[0]);if(*p!='\0'){  strcat(p," ");strcat(p,t->data);}else{ strcat(p,t->data);}}else{printf("%s ",t->data);if(*p!='\0'){ strcat(p," ");strcat(p,t->data);}else{ strcat(p,t->data);}}}
}  typedef struct nibolanstack //建立栈类
{double *base;double *top;int stacksize;
}nibolans;bool InitStack(nibolans &S){  //创建一个空栈S.base=(double *)malloc(50*sizeof(double));  //  if(!S.base) exit(OVERFLOW);  S.top=S.base;  S.stacksize=50;  return 1;
}  bool push(nibolans &S,double e)  //插入元素{  if(S.top-S.base>=S.stacksize) {  S.base=(double *)realloc(S.base,(S.stacksize+20)*sizeof(double));  if(!S.base)  exit(-2);  S.top=S.base+S.stacksize;  S.stacksize=S.stacksize+20;  }  *(S.top)=e;S.top++;return 1;  }  bool pop(nibolans &S,double &e)  //出栈{ if(S.top==S.base)  return 0;S.top--;e=*S.top;  return 1;  }  void check(char s[],nibolans &S)
{char *p=s,q[10];int i=0,k=0;double m,x,y,z;
//  cout<<s<<endl;while(*p!='#'){if(*p==' '){    //  cout<<endl;m=atof(q);//  cout<<m<<endl;if(m!=0)push(S,m);for(int j=0;j<i;j++){q[j]='\0';//char型置空}i=0;}else {//   cout<<*p<<" ";//  cout<<(*p=='+');if((*p=='+')||(*p=='-')||(*p=='*')||(*p=='/')){pop(S,x);pop(S,y);if(*p=='+'){z=x+y;push(S,z);}if(*p=='-'){z=y-x;push(S,z);}if(*p=='*'){z=x*y;push(S,z);}if(*p=='/'){z=y/x;push(S,y/x);}}else{q[i]=*p;i++;}}p++;}
//  return z;}
bool checkk(char s[])
{bool flag=0;char *p=s;char *q=s;while(*q!='\0'){if((*q=='+')||(*q=='-')||(*q=='*')||(*q=='/')){flag=1;}q++;}while(*p!='\0'){if((*p!='0')&&(*p!='1')&&(*p!='2')&&(*p!='3')&&(*p!='4')&&(*p!='5')&&(*p!='6')&&(*p!='7')&&(*p!='8')&&(*p!='9')&&(*p!='+')&&(*p!='-')&&(*p!='*')&&(*p!='/')&&(*p!=' ')&&(*p!='#')){flag=0;}p++;}return flag;}int main(int argc, char* argv[])
{char suanshi[MAXNUM];double jieguo;BiTree BT;nibolans S;InitStack(S);printf("请输入中缀表达式:\n");gets(suanshi);if(checkkuohao(suanshi)){ToTree(BT,suanshi);preorder(BT,p);cout<<endl;strcat(suan,"#");puts(suan);if(checkk(suan)){check(suan,S);pop(S,jieguo);cout<<fixed<<setprecision(2)<<jieguo;}else cout<<"表达式错误!"<<endl;}else cout<<"表达式错误!"<<endl;return 0;}

接下来是我几个不太熟悉的函数总结一下:

1.复制字符串

strcpy(T->data,suanshi);

把后面的复制到前面的地方。C语言标准库函数strcpy,把从src地址开始且含有 '\0'结束符的字符串复制到以dest开始的 地址空间。

2.字符串后追加字符串

strcat(p,t->data)

把p指向的字符串追加到t-》data后面,两者都得有‘、0’

四则运算表达式求值の各种心碎相关推荐

  1. Bailian4132 四则运算表达式求值【文本处理】

    4132:四则运算表达式求值 总时间限制: 1000ms 内存限制: 65536kB 描述 求一个可以带括号的小学算术四则运算表达式的值 输入 一行,一个四则运算表达式.''表示乘法,'/'表示除法 ...

  2. c语言求不定式的最大值,C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算...

    运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateEx ...

  3. 栈的应用(递归:例子裴波那契数列 四则运算表达式求值 :后缀(逆波兰) )

    递归: -栈有一个很重要的应用:在程序设计语言中实现递归. 当你往镜子前面一站,镜子里面就有-一个你的像. 但你试过两面镜子一起照吗?如果A.B两面镜子相互面对面放着,你往中间- -站,嘿,两面镜子里 ...

  4. 分别用C++和JavaScript 实现四则运算表达式求值

    博主16年4.19去面腾讯实习生,其中一个问题是让写一个函数求四则运算表达式的值,输入是字符串,输出为表达式结果.当时只记得这是数据结构里堆栈的应用,表达式要变顺序,但是实现就想不起来了,自然程序写的 ...

  5. 栈运算 java_栈的应用——四则运算表达式求值(Java实现)

    首先介绍几个概念 中缀式:平常我们所用到的标准的四则运算表达式就是中缀式,如9+(3-1)*3+10/2,这就是一个中缀式 后缀式(逆波兰式):一种不需要括号的后缀表达法,我们也把他称为逆波兰式,如将 ...

  6. 四则运算表达式求值(栈的应用)

    1.前/中/后缀表达式的转换(首先需要明白三者之间的转换)    自然表达式转换为前/中/后缀表达式,其实是很简单的.首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/ ...

  7. 经典笔试上机考题-表达式求值

    相信参加过笔试面试同学应当见到过表达式求值这道题,下面列举的一道经典的考题,本文将同大家一起细细探讨一下表达式求值这一类问题的求法,希望抛砖引玉,其中有不妥的地方也请大家多多批评指正. /* 功能:四 ...

  8. [数据结构]表达式求值

    一.问题描述 表达式求值是数学中的一个基本问题,也是程序设计中的一个简单问题.我们所涉及的表达式中包含数字和符号,本实验中处理的符号包括'+'.'-'.'*'.'/'.'('和')',要求按照我们所习 ...

  9. 利用SLR实现可编程计算器(表达式求值)

    有些计算器,只能进行单步计算,就是说只能输入数字和加减乘除四则运算符号,而不能有括号的出现.可编程计算器就是指能输入括号.数字和四则运算符号,并对所输入的四则运算表达式进行分析,得最终计算出结果的计算 ...

最新文章

  1. Microsoft PowerToys for Windows XP
  2. 负载均衡(Load Balancing)学习笔记(二)
  3. ewebeditor编辑器ASP/ASPX/PHP/JSP版本漏洞利用总结及解决方法
  4. 设计模式(一)单例模式:5-单元素枚举类模式
  5. 华为麒麟1020处理器曝光:性能提升50%,5nm制程!Mate 40有望成为首发机型
  6. (转)c# Invoke和BeginInvoke区别
  7. win10更新后开不了机_坚决不更新!被微软雪藏的win10系统版本,只要3GB,老爷机的克星!...
  8. 【电力负荷预测】基于matlab灰狼算法优化LSTM短期电力负荷预测【含Matlab源码 1518期】
  9. 2020美赛结果查询
  10. 论用户体验测试:牛逼的功能千篇一律,好的体验万里挑一
  11. 安装magicdrawUML出现的问题
  12. 【实验分享】通过Console口登录到Cisco设备
  13. 联机系统的服务器,远程联机服务器系统
  14. 敏捷迭代是什么意思_我认为“敏捷”的方向是第4部分:“敏捷”是什么意思?...
  15. el-input实现防抖
  16. python变量名长度有限制吗_怎么去除 Python 下载文件时的文件名长度 50 限制
  17. excel表格怎么调整行高和列宽_Excel 表格技巧—一键调整行高列宽的方法
  18. 客户端访问https时应无浏览器(含终端)安全警告信息;_Http升级Https(Let#x27;s Encrypt)...
  19. 苹果电脑mac系统运行卡顿 反应慢怎么办?
  20. AtCoder Beginner Contest 167 D Teleporter 找周期

热门文章

  1. 小甲鱼主讲—P22—数组02
  2. 环回测试能够提供什么信息_Wish为什么要为订单提供物流追踪信息?
  3. 用myeclipse编写css,myeclipse怎么用css
  4. Excel一键删除所有打开工作簿的条件格式
  5. SIMATIC WINCC授权使用方法
  6. 寻找女仆完美替身:7款智能扫地机器人擂台赛
  7. USB驱动程序之一(USB介绍、USB数据传输、USB设备枚举)
  8. 关于视频直播系统源码所开发的直播平台全流程分析
  9. python是支撑人工智能应用的主流语言对吗_人工智能首选语言是什么 究竟Python有多强大...
  10. android模拟器webservice,已解决:android 模拟器调用本地的webservice 引用不到