表达式的计算

数据结构----表达式的计算

说明:
本程序为表达式的计算算法实现
(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");
	 		exit(0);
	 	}
		else
	 		str[i+1]='\0';
	 	
		int result=-1;
		int a=expCalculation(&result);
		str[i]='\0';
		if(a!=-1)
	  		printf("%s = %d",str,result);
	}
	fclose(file);
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
因各个项目中需要使用根据字符串计算数值,这里写出一个算法,专门计算字符串。配有大量常用公式。只有一个人方法,直接调用即可。 类名:CustomMath 函数名:Calculations(string value) 说明:求解算式表达式字符串的值 表达式中包含的符号或函数: truncate, ceiling,floor,round,log10, sign,sinh,sqrt, asin,atan,cosh, tanh, sin,cos,tan ,abs,acos, exp,log,max,min,pow,mod,+,-,*,/,',',(,) 函数说明:(不区分大小写) truncate(num) 计算指定数的整数部分 truncate(1.23)=1 ceiling (num) 返回大于或等于指定的双精度浮点数的最小整数值 ceiling(1.23)=2 floor(num) 返回小于或等于指定双精度浮点数的最大整数 floor(1.23)=1 round(num) 将双精度浮点值舍入为最接近的整数值 round(1.23)=1 round(num,num1) 将小数值按指定的小数位数舍入 round(1.23,1)=1.2 log10(num) 返回指定数字以 10 为底的对数 log10(10)=1 sign(num) 返回表示数字符号的值 sign(1.23)=1 sinh(num) 返回指定角度的双曲正弦值 sinh(1.23)=1.5644 sqrt(num) 返回指定数字的平方根 sqrt(9)=3 sqrt(num,num1) 返回指定数字的num1根 sqrt(27,3)=3 asin(num) 返回正弦值为指定数字的角度 asin(0.5)=PI/6 atan(num) 返回正切值为指定数字的角度 atan(1)=45 cosh(num) 返回指定角度的双曲余弦值 cosh(1.23)=1.8567 tanh(num) 返回指定角度的双曲正切值 tanh(1.23)=0.8425 sin(num) 返回指定角度的正弦值 sin(PI/6)=0.5 cos(num) 返回指定角度的余弦值 sin(PI/3)=0.5 tan(num) 返回指定角度的余切值 sin(PI/4)=1 abs(num) 返回数字的绝对值 abs(-12)=12 acos(num) 返回余弦值为指定数字的角度 acos(0.5)=PI/3 exp(num) 返回 e 的指定次幂 exp(1)=2.718 log(num) 返回指定数字的自然对数(底为 e) log(e)=1 log(num,num1) 返回指定数字在使用指定底的对数 log(e,e)=1 max(num,um1) 返回最大值 max(1,2)=2 min(num,num1) 返回最小值 min(1,2)=1 pow(num,num1) 返回指定数字的指定次幂 pow(2,2)=4 mod(num,num1) 返回余数 mod(3,2)=1 常量: PI 值:3.14159265358979323846 E 值:2.7182818284590452354 YEAR 值:当前年份 MONTH 值:当前月份 DAY 值: 当前日 HOUR 值:当前 MINUTE 值:当前分 SECOND 值:当前秒 RANDOM 值:一个随机数(0-1 之间) 实例 系统计算:1+2*3/4-0.5=2 函数计算:1+2*3/4-0.5=2 调用方式:CustomMath.Calculations("1+2*3/4-0.5") 系统计算:(1+2)*3/4-0.5=1.75 函数计算:(1+2)*3/4-0.5=1.75 调用方式:CustomMath.Calculations("(1+2)*3/4-0.5") 系统计算:(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6=1.20185042515466 公式计算:(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6=1.20185042515466 调用方式:CustomMath.Calculations("(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6") 系统计算:sin(pow(3,2)/4)+3.5-9*sqrt(81)=-76.7219268031121 函数计算:sin(pow(3,2)/4)+3.5-9*sqrt(81)=-76.7219268031121 调用方式:CustomMath.Calculations("sin(pow(3,2)/4)+3.5-9*sqrt(81)")
表达式计算说明 很久就想编一个这样的计算器,只可惜一直没什么思路,最近突然灵感来了,所以就写下 这个程序。现在还在测试阶段,所以功能不是很完善。 程序功能:基本的表达式运算,可以自定义函数跟常量,分别保存在 “常数.txt” 和 “函数.txt”,方便自己添加。双击相应的函数名或常数名就可以将函数或常量添加到表达式中。 计算过程只能当表达式只有一行有效。 实例1:计算sqr(19+tan(98)*tan(91)-sin(122)*(5*5-(19-11)))/2 计算过程sqr(19+tan(98)*tan(91)-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*tan(91)-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*(5*5-8))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*17)/2 =20.3032618253667/2 =10.1516309126834 实例2:计算 a=34 b=55 c=a+1 圆的面积(c) a*b c=a+b 圆的面积(c) 以下是计算结果: 圆的面积(c)=3848.4510006475 a*b=1870 圆的面积(c)=24884.5554090847 内置函数: !(x) - x 的阶乘 lg(x),log(x) 以10为底的对数 ln(x) 以 e为底x的对数 pow(x,y) x的y方次幂 prime(x) 判定x是否是素数,如果是直接将s2返回,否则将其各因子用连乘返回 sqr(x),sqrt(x) - x 的二次方根 arcsin(x) - x 的反正弦 arccos(x) - x 的反余弦 arcsec(x) - x 的反正割 arccsc(x) - x 的反余割 atn(x),arctg(x) - x 的反正切 arcctg(x) - x 的反余切 sin(x) - x 的正弦 cos(x) - x 的余弦 sec(x) - x 的正割 csc(x) - x 的余割 tg(x),tan(x) - x 的正切 ctg(x) - x 的余切 harcsin(x) - x 的反双曲正弦 harccos(x) - x 的反双曲余弦 harcsec(x) - x 的反双曲正割 harccsc(x) - x 的反双曲余割 harctg(x),harctan(x) - x 的反双曲正切 harcctg(x) - x 的反双曲余切 hsin(x) - x 的双曲正弦 hcos(x) - x 的双曲余弦 hsec(x) - x 的双曲正割 hcsc(x) - x 的双曲余割 htg(x),htan(x) - x 的双曲正切 hctg(x) - x 的双曲余切 有什么意见或建议可以跟我联系Email: ldm.menglv@gmail.com
HTML 是一种用于创建网页的标记语言,它本身不支持表达式计算。但是,我们可以使用 JavaScript 来实现在 HTML 页面中进行表达式计算。JavaScript 是一种脚本语言,可以嵌入到 HTML 中,在浏览器端运行。 通过在 HTML 页面中嵌入 JavaScript 代码,我们可以实现简单的表达式计算。比如,我们可以在 HTML 页面中添加一个输入框和一个按钮,当用户输入一个表达式并点击按钮,JavaScript 代码可以解析这个表达式计算出结果,最后将结果显示在页面上。 下面是一个简单的 HTML 页面示例,其中包含一个输入框和一个按钮,点击按钮计算输入框中的表达式并显示结果: ```html <!DOCTYPE html> <html> <head> <title>表达式计算</title> <script> function calculate() { // 获取输入框中的表达式 var expr = document.getElementById("expr").value; // 使用 eval 函数计算表达式的值 var result = eval(expr); // 将结果显示在页面上 document.getElementById("result").innerHTML = result; } </script> </head> <body> <h1>表达式计算</h1> <input type="text" id="expr" /> <button onclick="calculate()">计算</button> <div id="result"></div> </body> </html> ``` 请注意,eval 函数可以将字符串解析为 JavaScript 代码并执行。因此,在使用 eval 函数应该非常小心,避免安全问题。同,在实际开发中,我们也应该使用更加严谨和安全的方法来进行表达式计算

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值