18.11.23
这是一道最近刚上的实验课的题目。。。。

基于C语言,欢迎指正

实验要求

掌握栈在解决实际问题中的应用,设计一个程序,演算用算符优先法对算术表达式求值的过程,利用算符优先关系,实现对算术四则混合运算表达式的求值

。。挺难的。。

思路在这!

思路

这个程序是这样,当你点击运行它的时候,你需要输一个表达式,然后按个回车,答案就出来了,跟个计算器一样

那么,在一开始,我们需要一个数组,来存入你所输入的表达式,这样就得到了一个字符数组,然后呢,我们需要创建两个栈,一个用来存运算符,我们叫他运算符栈opter,一个用来存操作数,我们叫它操作数栈opnd,然后我们开始读入我们输入的表达式,读到一个操作符就加到一个新的字符数组,比如说,23+1这个式子,先读入一个’2’存入字符数组,在读入一个’3’存入字符数组,当读到’+’ ,这个时候字符数组有两个元素,给字符数组的第三号位加上一个’\0’,就变成了一个字符串,这样用atof函数就是可以把这个字符串变成浮点型从而可以参与运算(不然如果还是字符状态是不能参与运算的),然后把得到的这个23压入操作数栈中进行相应操作,相应操作如下:

这是来自学校发的实验报告册上的:(认真看还是看的懂的)
(1)首先将操作数栈opnd设为空栈,而将’#'作为运算符栈opter的栈底元素,这样的目的是判断表达式是否求值完毕。
(2)依次读入表达式的每个字符,表达式须以’#‘结尾,若是操作数则入栈opnd,若是运算符,则将此运算符c与opter的栈顶元素top比较优先级后执行相应的操作,具体操作如下:
(i)若top的优先级小于c,即top<c,则将c直接入栈opter,并读入下一字符赋值给c;
(ii)若top的优先级等于c,即top=c,则弹出opter的才顶元素,并读入下一字符赋值给c,这一步目的是进行括号操作;
(iii)若top优先级高于c,即top>c,则表明可以计算,此时弹出opnd的栈顶两个元素,并且弹出opter栈顶的的运算符,计算后将结果放入栈opnd中。直至opter的栈顶元素和当前读入的字符均为’#’,此时求值结束。


表中需要注意的是θ1为opter的栈顶元素,θ2为从表达式中读取的操作符,此优先级表可以用二维数组实现。

有.思路了,咱们把整个程序拆开来看看

我们需要的东西

1. 一堆头文件
2. 一个用于优先级比较的数组,
3. 两个栈
(我们这里用的是顺序栈)

其中,这个用于运算符比较的数组是这个
“>><<<>>”,
“>><<<>>”,
“>>>><>>”,
“>>>><>>”,
“<<<<<=?”,
“>>>>?>>”,
“<<<<<?=”
即这个

代码如下

#include<stdio.h>
#include<stdlib.h>//包含exit()函数
#include<string.h>//跟字符处理有关的头文件
#include<math.h>#define Stack_Size 1000    //认为Stack_Size为1000char cmp[7][8]= {">><<<>>",">><<<>>",">>>><>>",">>>><>>","<<<<<=?",">>>>?>>","<<<<<?="};typedef struct{//定义一个运算符栈char Elem[Stack_Size];int top;//标记变量,记录表尾的变化
}Opter;typedef struct{//定义一个操作数栈double Elem[Stack_Size];int top;
}Opnd;

准备活动完成了,接下来是对栈的一些基础操作进行设定

设置一些栈操作要用的函数

比如说
(下面的S是传进来的栈的指针地址)

  1. 初始化栈:就一个操作,S->top=-1
  2. 入栈:首先,S->top++,然后再S->Elem[S->top]=传进来的元素
  3. 出栈:一个操作,S->top–;,当然要排除掉栈空的情况,即S->top==-1,这种情况就要exit()
  4. 取栈顶元素:我们用返回值返回S->Elem[S->top]就行啦,当然也要排除栈空

代码如下

void InitOpter(Opter *S){//初始化运算符栈S->top=-1;
}
void InitOpnd(Opnd *S){//初始化操作数栈S->top=-1;
}int PopOpter(Opter *S)//弹出运算符栈
{if(S->top==-1){printf("运算符栈为空\n");exit(10);}S->top--;return 1;
}int PopOpnd(Opnd *S)
{if(S->top==-1){printf("运算符栈为空\n");exit(11);}S->top--;return 1;
}int PushOpter(Opter* S,char ch)
{if(S->top==Stack_Size-1){printf("运算符栈满\n");exit(12);}S->top++;S->Elem[S->top]=ch;return 1;
}int PushOpnd(Opnd* S,double ch)//入操作数栈
{if(S->top==Stack_Size-1){printf("运算符栈满\n");exit(13);}S->top++;S->Elem[S->top]=ch;return 1;
}char GetOpter(Opter *S)//获取运算符栈的栈顶元素,注意区分返回值类型
{if(S->top==-1){printf("运算符栈为空\n");exit(17);}return S->Elem[S->top];
}double GetOpnd(Opnd *S)
{if(S->top==-1){printf("操作数栈为空\n");exit(18);}return S->Elem[S->top];
}

有了这些基本工具,接下来是计算函数

计算函数

double Calc(double a,double b,char opt)//计算函数,传入两个数以及一个运算符
{double T;   //T用于存放计算得出的结果if(opt=='+') T=a+b;if(opt=='-') T=a-b;if(opt=='*') T=a*b;if(opt=='/')     //要防止发生除0错误{if(fabs(b)<0.00001){printf("发生除0错误\n");exit(15);}T=a/b;}printf("中间过程输出:  %.2lf %c %.2lf = %.2lf\n",a,opt,b,T);return T;    //返回得到的结果
}

在程序执行过程中,我们需要比较两个运算符的优先级来进行计算,所以我们需要创建一个比较函数

比较函数

int change(char ch)
{switch(ch){case '+':return 0;case '-':return 1;case '*':return 2;case '/':return 3;case '(':return 4;case ')':return 5;case '#':return 6;}
}int Compare(char ch1,char ch2)
{if(cmp[change(ch1)][change(ch2)]=='?'){printf("输入表达式错误");exit(16);}return cmp[change(ch1)][change(ch2)];
}

将运算符转变为优先级比较的数组的下标,通过查阅优先级比较数组中对应的结果,再传给函数,其中change函数就是起到查阅的作用

检查是否输入多余字符

我们可能输入表达式的时候会多输入了一些不在范围内的字符,这就需要一个检查函数来排查

int Check(char *S,int len)//检查函数,记得考虑输入带小数点的数字的情况
{int i;for(i=0;i<len;i++){if(S[i]>='0'&&S[i]<='9')continue;if(S[i]=='('||S[i]==')'||S[i]=='*'||S[i]=='/'||S[i]=='+'||S[i]=='-'||S[i]=='.')continue;return 0;}return 1;
}

有了上面的这些函数,我们就可以在主函数中进行调试了,我们一些具体的运算操作也是要在主函数中实现的

主函数该怎么写

我们直接在代码中进行解释
代码如下

int main()
{char a[1000],b[1000];         //创建两个数组,a是用来存输入的表达式的,b是用来存操作数的int len;        //len为输入表达式的长度,通过strlen求得Opter S;    //创建一个运算符栈Opnd N;    //创建一个操作数栈InitOpnd(&N);   //初始化操作数栈InitOpter(&S);   //初始化运算符栈PushOpter(&S,'#');  //注意这里,我们事先在运算符栈中压入一个'#',在输入表达式后,在表达式数组中最后一个位置也设为'#',//之后在运算结束时这两个#会相见,比较函数返回'=',使得最终的运算结束printf("输入表达式:\n");scanf("%s",a);    //输入表达式,注意这里a不用取地址符&,因为数组其实就是一个地址,它保留的是数组第一个元素的首地址,a其实就是&a[0]len=strlen(a);   //求输入的表达式的长度,并打印出来printf("字符长度为%d\n",len);if(Check(a,len)==0)   //检查是否多输入了一些奇奇怪怪的东西{printf("输入中存在多余字符\n");exit(19);}int i,j=0,k=0;double x,y;  //x,y是从操作数中取出的两个即将用于计算的数a[len]='#';  //注意for(i=0;i<=len;i++)  //遍历我们输入的表达式{if((a[i]>='0'&&a[i]<='9')||a[i]=='.')//如果为数字{b[k++]=a[i];//将数字存入数组b中,注意此时数字仍为字符j=1;continue;  //在该循环下其余部分都不做了,直接进入下一次xunh}if(j)//条件成功即遇到了运算字符,将操作数压入操作数栈中{//此时数组b已经有了一个或者几个数字在里面,需要加一个'\0'使其成为字符串//再通过atof函数使其由字符型变为双精度型,然后加入操作数栈中进行相应运算b[k]='\0';PushOpnd(&N,atof(b));//atof函数可以使char变为doublej=0;k=0;  //k置零为下一次计数做准备}switch(Compare(GetOpter(&S),a[i]))//比较运算符栈的栈顶运算符top和运算符a[i]的优先级{ //底下的部分我们按照之前给的规则来写case '<'://即top<a[i],则将a[i]直接入栈OpterPushOpter(&S,a[i]);break;case'=':PopOpter(&S);break;case'>'://当为‘>'的情况,即需要进行运算,先取操作数栈中最上面的两个元素y=GetOpnd(&N),PopOpnd(&N);x=GetOpnd(&N),PopOpnd(&N);//然后将计算结果压入操作数栈中PushOpnd(&N,Calc(x,y,GetOpter(&S)));//已经用过的运算符就废掉了,弹出!!!PopOpter(&S);i--;//这句是为了重新把反括号入栈,使之与左括号配对,否则会造成左括号多余出来break;}}double answer=GetOpnd(&N);//最终操作数栈中的数就是我们想要的结果printf("最终结果为%.2lf",answer);return 0;}

那么用算符优先法对算术表达式求值的程序就算是写完啦

源程序调试

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>#define Stack_Size 1000char cmp[7][8]= {">><<<>>",">><<<>>",">>>><>>",">>>><>>","<<<<<=?",">>>>?>>","<<<<<?="};typedef struct{//定义一个运算符栈char Elem[Stack_Size];int top;
}Opter;typedef struct{//定义一个操作数栈double Elem[Stack_Size];int top;
}Opnd;void InitOpter(Opter *S){//初始化运算符栈S->top=-1;
}
void InitOpnd(Opnd *S){//初始化操作数栈S->top=-1;
}int PopOpter(Opter *S)//弹出运算符栈
{if(S->top==-1){printf("运算符栈为空\n");exit(10);}S->top--;return 1;
}int PopOpnd(Opnd *S)
{if(S->top==-1){printf("运算符栈为空\n");exit(11);}S->top--;return 1;
}int PushOpter(Opter* S,char ch)
{if(S->top==Stack_Size-1){printf("运算符栈满\n");exit(12);}S->top++;S->Elem[S->top]=ch;return 1;
}int PushOpnd(Opnd* S,double ch)//入操作数栈
{if(S->top==Stack_Size-1){printf("运算符栈满\n");exit(13);}S->top++;S->Elem[S->top]=ch;return 1;
}char GetOpter(Opter *S)//获取运算符栈的栈顶元素
{if(S->top==-1){printf("运算符栈为空\n");exit(17);}return S->Elem[S->top];
}double GetOpnd(Opnd *S)
{if(S->top==-1){printf("操作数栈为空\n");exit(18);}return S->Elem[S->top];
}double Calc(double a,double b,char opt)//计算函数,传入两个数以及一个运算符
{double T;   //T用于存放计算得出的结果if(opt=='+') T=a+b;if(opt=='-') T=a-b;if(opt=='*') T=a*b;if(opt=='/')     //要防止发生除0错误{if(fabs(b)<0.00001){printf("发生除0错误\n");exit(15);}T=a/b;}printf("中间过程输出:  %.2lf %c %.2lf = %.2lf\n",a,opt,b,T);return T;    //返回得到的结果
}int change(char ch)
{switch(ch){case '+':return 0;case '-':return 1;case '*':return 2;case '/':return 3;case '(':return 4;case ')':return 5;case '#':return 6;}
}int Compare(char ch1,char ch2)
{if(cmp[change(ch1)][change(ch2)]=='?'){printf("输入表达式错误");exit(16);}return cmp[change(ch1)][change(ch2)];
}int Check(char *S,int len)//检查函数,记得考虑输入带小数点的数字的情况
{int i;for(i=0;i<len;i++){if(S[i]>='0'&&S[i]<='9')continue;if(S[i]=='('||S[i]==')'||S[i]=='*'||S[i]=='/'||S[i]=='+'||S[i]=='-'||S[i]=='.')continue;return 0;}return 1;
}int main()
{char a[1000],b[1000];         //创建两个数组,a是用来存输入的表达式的,b是用来存操作数的int len;        //len为输入表达式的长度,通过strlen求得Opter S;    //创建一个运算符栈Opnd N;    //创建一个操作数栈InitOpnd(&N);   //初始化操作数栈InitOpter(&S);   //初始化运算符栈PushOpter(&S,'#');//注意这里,我们事先在运算符栈中压入一个'#',在输入表达式后,在表达式数组中最后一个位置也设为'#',//之后在运算结束时这两个#会相见,比较函数返回'=',使得最终的运算结束printf("输入表达式:\n");scanf("%s",a);    //输入表达式,注意这里a不用取地址符&,因为数组其实就是一个地址,它保留的是数组第一个元素的首地址,a其实就是&a[0]len=strlen(a);   //求输入的表达式的长度,并打印出来printf("字符长度为%d\n",len);if(Check(a,len)==0)   //检查是否多输入了一些奇奇怪怪的东西{printf("输入中存在多余字符\n");exit(19);}int i,j=0,k=0;double x,y;  //x,y是从操作数中取出的两个即将用于计算的数a[len]='#';  //注意for(i=0;i<=len;i++)  //遍历我们输入的表达式{if((a[i]>='0'&&a[i]<='9')||a[i]=='.')//如果为数字{b[k++]=a[i];//将数字存入数组b中,注意此时数字仍为字符j=1;continue;  //在该循环下其余部分都不做了,直接进入下一次xunh}if(j)//条件成功即遇到了运算字符,将操作数压入操作数栈中{//此时数组b已经有了一个或者几个数字在里面,需要加一个'\0'使其成为字符串//再通过atof函数使其由字符型变为双精度型,然后加入操作数栈中进行相应运算b[k]='\0';PushOpnd(&N,atof(b));//atof函数可以使char变为doublej=0;k=0;  //k置零为下一次计数做准备}switch(Compare(GetOpter(&S),a[i]))//比较运算符栈的栈顶运算符top和运算符a[i]的优先级{ //底下的部分我们按照之前给的规则来写case '<'://即top<a[i],则将a[i]直接入栈OpterPushOpter(&S,a[i]);break;case'=':PopOpter(&S);break;case'>'://当为‘>'的情况,即需要进行运算,先取操作数栈中最上面的两个元素y=GetOpnd(&N),PopOpnd(&N);x=GetOpnd(&N),PopOpnd(&N);//然后将计算结果压入操作数栈中PushOpnd(&N,Calc(x,y,GetOpter(&S)));//已经用过的运算符就废掉了,弹出!!!PopOpter(&S);i--;//这句是为了重新把反括号入栈,使之与左括号配对,否则会造成左括号多余出来break;}}double answer=GetOpnd(&N);//最终操作数栈中的数就是我们想要的结果printf("最终结果为%.2lf",answer);return 0;}

调试结果

NICE!!!

用算符优先法对算术表达式求值(六)相关推荐

  1. 算术表达式求值演示(C/C++实现)

    算术表达式求值演示 问题描述:表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的典型例子.设计一个程序,演示用算符优先法对算术表达式求值的过程. 基本要求:以字符序列的形式从键盘输入语法正确的 ...

  2. linux算术表达式求值数据结构,数据结构:算数表达式求值演示

    题目:设计一个程序,演示用算符优先法对算数表达式求值的过程. 一.需求分析 以字符序列的形式从终端读入输入语法正确.不含变量的整数表达式.利用教科书表3.1给出的算符优先关系,实现对算数四则混合运算表 ...

  3. 算术表达式求值的程序设计与实现_数据结构课程设计

    以下内容可且仅可供参考,如有错误欢迎指正. 部分思路借鉴算术表达式求值(C语言栈)_夜何其的博客-CSDN博客_c语言利用栈求解算术表达式侵删致歉 <算术表达式求值的程序设计与实现>题目要 ...

  4. 算术表达式求值(C语言栈)

    题目:算术表达式求值 题目描述:表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子.设计一个程序,演示用运算符优先法对算数表达式求值的过程. 基本要求:以字符序列的形式从终端输入语 ...

  5. 北京林业大学数据结构实验二 基于栈的算术表达式求值算法

    第1关:基于栈的中缀算术表达式求值 参见课本P75 例3.3 #include <iostream> #include<iomanip>#define MAXSIZE 100 ...

  6. c语言作业算术表达式求值,算术表达式求值演示(C语言版)

    //头文件预处理命令 #include #include //----------函数结果状态代码----------------- #define TRUE 1 #define FALSE 0 #d ...

  7. 数据结构—— 基于二叉树的算术表达式求值

    实验五 基于二叉树的算术表达式求值 数据结构--中序表达式求值(栈实现) 实验目的: 1.掌握二叉树的二叉链表存储表示和二叉树的遍历等基本算法. 2.掌握根据中缀表达式创建表达式树的算法 3.掌握基于 ...

  8. 《Algorithms》—— Dijkstra 的双栈算术表达式求值算法

    想当年学数据结构的时候,一直觉得这个是我一辈子都搞不懂的一个东西.现在看看...还挺简单的... 重点在于如何解析由括号.运算符和数字组成的字符串,并按照正确的顺序完成各种初级算术操作.利用了两个栈( ...

  9. 【经典算法】-算术表达式求值

    算术表达式求值 中缀表达式 我们平时写的计算式的式子一般是这样子 格式:"操作数1 操作符 操作数2"12 * (3 + 4) - 6 + 8 / 2; // 中缀表达式 中缀表达 ...

最新文章

  1. ACL 2020今日放榜,779篇论文被接收,姚班校友陈丹琦首日演讲
  2. Linux中为wget命令设置代理
  3. mysql 高级语法,SQL 语法高级
  4. CXF WebService 开发文档-目录索引
  5. 第三十三章 机械化印刷
  6. promise封装读取文件
  7. 「镁客·请讲」ETC社区发起人邹来辉(Roy):我为什么要做ETC社区和狗狗币基金会?...
  8. JavaWeb宠物管理系统(源码+文档)
  9. js+html空间数据编码问题--以姓名为例(代码设涉及文件读取,文本数字提取,特别是文本x,y坐标的提取)
  10. pandas的认识与dataframe的认识 day04课件代码
  11. 一台计算机连接两个投影,一台电脑两个投影仪要如何连接
  12. win10文件夹加密_文件隐私保护工具文件夹隐藏精灵
  13. k8s通过Service访问Pod
  14. 数十万互联网从业者的共同关注!
  15. chrome 浏览手机网站
  16. 为西部AV和IT集成商构建国际合作平台
  17. 北京 Java软件工程师薪资_【北京京东工资】java高级软件工程师待遇-看准网
  18. oracle 所有外键约束,如何在oracle中找到所有外键约束?
  19. ESXi服务器勒索补丁升级方法
  20. 虚拟机jupyter浏览器无法访问解决办法

热门文章

  1. 递归算法_字符串反转_20230412
  2. python安装lap_AP 升级到 LAP,或 LAP 降到 AP 的方法
  3. 论文总结:基于可编辑区块链的工业物联网数据管理机制
  4. 第二篇第一章概述及第二章生产和储存物品的火灾危险性分类 重点在于表格...
  5. 2019牛客暑期多校训练营(第二场)H Second Large Rectangle
  6. 消息模型与生成pdf
  7. 如何通过Darkvm注册阿里云国际版?
  8. 【综述】A Comprehensive Survey on Graph NeuralNetworks(4)
  9. 微信小程序接入腾讯云MQTT服务
  10. 详谈硬盘分区表格式MBR与GUID/GPT