表达式的计算

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")如何理解这段代码片段中的两对括号?

通过 Java 正则表达式提取 semver 版本字符串的片段

4.3 合并重复的条件执行片段

jsp表达式语言

在 intellij 上调试评估表达式

从JVM的角度看JAVA代码--代码优化