表达式的计算
Posted cjj2503
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了表达式的计算相关的知识,希望对你有一定的参考价值。
数据结构----表达式的计算
说明:
本程序为表达式的计算算法实现
(1)表达式支持整数的+ - * / ( )运算,可以有空格
(2)算法从文件input.txt 中读取表达式,表达式以#结束算法说明: (1)计算算术表达式的值时,可用两个栈作辅助工具。
(2)对于给出的一个表达式,从左向右扫描它的字符,并将操作数放入栈S1中,运算符放入栈S2中,
但每次扫描到运算符时,要把它同S2的栈顶运算符进行优先级比较,当扫描到的运算符的优先级不高于栈顶运算符的优先级时,
取出栈S1的栈顶和次栈顶的两个元素,以及栈S2的栈顶运算符进行运算将结果放入栈S1中(得到的结果依次用T1、T2等表示)。
(3)为方便比较,假设栈S2的初始栈顶为#(#运算符的优先级低于加、减、乘、除中任何一种运算)。输入举例: 34 + ((5*8)- 20+6)#
输出: 34 + ((5*8)- 20+6) = 60
测试案例
输入案例
34 + ((5*8)- 20+6)#
输出案例
34 + ((5*8)- 20+6) = 60
代码部分
SeqStack.h
#ifndef SEQSTACK_H
#define SEQSTACK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxStackSize 100
typedef int DataType;
typedef struct
{ DataType stack[MaxStackSize];
int top;
} SeqStack;
void StackInitiate(SeqStack *S);
int StackNotEmpty(SeqStack S);
int StackPush(SeqStack *S, DataType x);
int StackPop(SeqStack *S, DataType *d);
int StackTop(SeqStack S, DataType *d);
int StackLength(SeqStack S);
#endif
exp.h
#ifndef EXP_H
#define EXP_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
PLUS, MINUS, TIMES, OVER, LPAREN, RPAREN, JINHAO
}OpType; //頓炬륜잚謹
typedef enum
{
NUM, OP, ERROR
}Type; //데늦잚謹 꾸鱗鑒 꾸鱗륜 俚륜눔써監륜 페儉댄轎데늦
int scan(int* d);
int compareOp(OpType op1,OpType op2);
int compute(int op1,int op2, OpType ot,int* result);
int expCalculation(int *result);
#endif
SeqStack.c
#include "SeqStack.h"
//初始化
void StackInitiate(SeqStack *S)
{
S->top = 0;
}
//非空否
int StackNotEmpty(SeqStack S)
{
if(S.top <= 0) return 0;
else return 1;
}
//把数据元素值x存入顺序堆栈S中,入栈成功则返回0,否则返-1
int StackPush(SeqStack *S, DataType x)
{
if(S->top >= MaxStackSize-1)
{
printf("堆栈已满无法插入!");
return -1;
}
else
{
S->top ++;
S->stack[S->top] = x;
return 0;
}
}
//出栈 出栈成功则返回0,否则返-1
int StackPop(SeqStack *S, DataType *d)
{
if(S->top <= 0)
{
printf("堆栈已空无数据元素出栈!");
return -1;
}
else
{
*d = S->stack[S->top];
S->top --;
return 0;
}
}
//取栈顶数据元素 ,成功返回0,失败返回-1
int StackTop(SeqStack S, DataType *d)
{
if(S.top <= 0)
{
printf("堆栈已空无数据元素!");
return -1;
}
else
{ *d = S.stack[S.top];
return 0;
}
}
//栈中元素的个数
int StackLength(SeqStack S){
return S.top;
}
exp.c
```c
#include "exp.h"
#include "SeqStack.h"
extern char str[100];
extern int index;
int scan(int* d){
char temp[100];
int i=0;
while(str[index]==' ') //过滤空格
index++;
if(str[index]=='+'){
*d=PLUS;
index++;
return OP;
}
if(str[index]=='-'){
*d=MINUS;
index++;
return OP;
}
if(str[index]=='*'){
*d=TIMES;
index++;
return OP;
}
if(str[index]=='/'){
*d=OVER;
index++;
return OP;
}
if(str[index]=='('){
*d=LPAREN;
index++;
return OP;
}
if(str[index]==')'){
*d=RPAREN;
index++;
return OP;
}
while(str[index]>='0'&&str[index]<='9'){
temp[i]=str[index];
index++;
i++;
}
temp[i]='\\0';
if(i>0){
*d=atoi(temp);
return NUM;
}
if(str[index]=='#'){
*d=JINHAO;
return OP;
}
return ERROR;
}
//运算符优先表,用函数来表示,比较运算符 op1 和 op2 , op1>op2 返回1; < 返回-1 ; == 返回0; 非法运算符返回-2
int compareOp(OpType op1,OpType op2){
switch(op1){
case PLUS: {if(op2==PLUS||op2==MINUS) return 1; if(op2==TIMES||op2==OVER) return -1; if(op2== LPAREN) return -1;if(op2== RPAREN) return 1;if(op2== JINHAO) return 1;}
case MINUS: {if(op2==PLUS||op2==MINUS) return 1; if(op2==TIMES||op2==OVER) return -1; if(op2== LPAREN) return -1;if(op2== RPAREN) return 1;if(op2== JINHAO) return 1;}
case TIMES: {if(op2==PLUS||op2==MINUS) return 1; if(op2==TIMES||op2==OVER) return 1; if(op2== LPAREN) return -1;if(op2== RPAREN) return 1;if(op2== JINHAO) return 1;}
case OVER: {if(op2==PLUS||op2==MINUS) return 1; if(op2==TIMES||op2==OVER) return 1; if(op2== LPAREN) return -1;if(op2== RPAREN) return 1;if(op2== JINHAO) return 1;}
case LPAREN: {if(op2==PLUS||op2==MINUS) return -1; if(op2==TIMES||op2==OVER) return -1; if(op2== LPAREN) return -1;if(op2== RPAREN) return 0;if(op2== JINHAO) {printf("illegal expression:%s",str);return -2;} }
case RPAREN: {if(op2==PLUS||op2==MINUS) return 1; if(op2==TIMES||op2==OVER) return 1; if(op2== LPAREN) {printf("illegal expression:%s\\n",str);exit(0);} if(op2== RPAREN) return 1;if(op2== JINHAO) return 1;}
case JINHAO: {if(op2==PLUS||op2==MINUS) return -1; if(op2==TIMES||op2==OVER) return -1; if(op2== LPAREN) return -1;if(op2== RPAREN){printf("illegal expression:%s",str);return -2;} if(op2== JINHAO) return 0;}
default:{ printf("illegal expression!");return -2;}
}
}
//根据不同的运算符类型计算结果,成功返回0,失败返回-1
int compute(int op1,int op2, OpType ot,int* result){
switch(ot){
case PLUS: { *result = op1+op2; return 0;}
case MINUS: { *result = op1-op2; return 0;}
case TIMES: { *result = op1*op2; return 0;}
case OVER: { *result = op1/op2; return 0;}
default:{printf("illegal expression!");return -1;}
}
}
/*表达式求值算法描述:
(1)计算算术表达式的值时,可用两个栈作辅助工具。
(2)对于给出的一个表达式,从左向右扫描它的字符,并将操作数放入栈S1中,运算符放入栈S2中,
但每次扫描到运算符时,要把它同S2的栈顶运算符进行优先级比较,当扫描到的运算符的优先级不高于栈顶运算符的优先级时,取出栈S1的栈顶和次栈顶的两个元素,
以及栈S2的栈顶运算符进行运算将结果放入栈S1中(得到的结果依次用T1、T2等表示)。
(3)为方便比较,假设栈S2的初始栈顶为#(#运算符的优先级低于加、减、乘、除中任何一种运算)。
*/
int expCalculation(int *result){
SeqStack s1; //装操作数的堆栈
SeqStack s2; //装运算符的堆栈
StackInitiate(&s1);
StackInitiate(&s2);
StackPush(&s2, JINHAO);
int value=0;
Type type=-1;
int isSuccessFinish=0;
type=scan(&value); //扫描到到第一个单词类型
while(1){
if(type==NUM){ //如果当前扫描到的单词类型是操作数类型时,操作数进操作数栈
StackPush(&s1,value);
type=scan(&value); //读取下一个单词
}
else if(type==OP){ //如果当前扫描到的单词类型是操作符类型时,与栈顶操作符比较
OpType o;
if(StackNotEmpty(s2)==0){ //如果堆栈为空,表达式错误
isSuccessFinish=0;
break;
}
StackTop(s2,&o);
if(value==JINHAO&&o==JINHAO){ // 如果当前扫描到的单词和栈顶操作符都是#,表达式计算正确完成,设置成功标志,退出循环
isSuccessFinish=1;
break;
}
int result=compareOp(o,value); //如果当前操作符号不是#,栈顶符号和当前扫描到的运算符进行优先级比较
if(result==1){ //栈顶符号 > 当前符号, 运算符出栈并计算
//补充代码
OpType o;
DataType a,b;
int T1;
StackPop(&s2,&o);
if(StackNotEmpty(s1)==0)continue;
else StackPop(&s1,&b);
if(StackNotEmpty(s1)==0)continue;
else StackPop(&s1,&a);
compute(a,b,o,&T1);
StackPush(&s1,T1);
}
else if(result ==-1) //栈顶符号 < 当前符号, 当前符号进栈
{
//补充代码
StackPush(&s2,value);
type=scan(&value);
}
else //栈顶符号 == 当前符号,匹配
{
//补充代码
OpType o;
StackPop(&s2,&o);
type=scan(&value);
}
}
else if(type==ERROR)
{
printf("illegal expression:%s");
return -1;
}
}
if(isSuccessFinish&&StackLength(s1)==1)
{
StackTop(s1,result);
return 0;
}
else
{
printf("illegal expression:%s",str);
return -1;
}
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "exp.h"
/*
功能:
主函数
参数:
argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行参数。
例如通过命令行输入 "C:\\hello.exe -a -b" 后,main 函数的 argc 的值为 3,
argv[0] 指向字符串 "C:\\hello.exe",argv[1] 指向字符串 "-a",argv[2] 指向字符串 "-b"。
返回值:
成功返回 0, 失败返回 1
*/
char str[100];
int index=0;
int main(int argc, char* argv[])
{
// 使用第一个参数输入待处理文件的名称,若没有输入此参数就报告错误
if(argc < 2)
{
printf("Usage: app.exe filename\\n");
return 1;
}
// 打开待处理的文件。读取文件中的内容。
FILE* file= fopen(argv[1], "rt");
if(NULL == file)
{
printf("Can not open file \\"%s\\".\\n", argv[1]);
return 1;
}
char temp[100];
if(fgets(temp,100,file)!=NULL){
index=0;
int i=0;
int flag=0;
while(temp[i]!='\\0'){
str[i]=temp[i];
if(temp[i]=='#'){
flag=1;
break;
}
i++;
}
if(flag!=1){
printf("表达式要以#结尾!\\n")如何理解这段代码片段中的两对括号?