算式表达式求值

第1章 问题描述与分析
1.1问题描述
一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正整数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)(23-28/4)#。引入表达式起始、结束符是为了方便。编程利用“算符优先法”求算术表达式的值。
从键盘读入一个合法的算术表达式,输出正确的结果;显示输入序列和栈的变化过程,操作数类型扩充到实数。
1.2设计分析
在算术表达式中,运算符位于两个操作数中间的表达式称为中缀表达式,例如1+2
3就是一个中缀表达式,中缀表达式是一种最常用的表达式形式,日常生活中的表达式一般都是用中缀表达式。对中缀表达式的运算,一般遵循先乘除后加减,从左到右计算,先括号内后括号外的规则,因此中缀表达式不仅要依赖运算符优先级,还要处理括号。算术表达式的另一种形式,后缀表达式或逆波兰表达式,就是在算术表达式中运算符在操作数的后面。1+23的后缀表达式为123+。后缀表达式中已经考虑了运算符的优先级,没有括号,只有操作数和运算符,而且越放在前面的运算符越优先执行。同样在算术表达式中,如果运算符在操作数的前面称为前缀表达式如1+23的前缀表达式为+123。后缀表达式是一种十分有用的表达式,它将复杂表达式转化为可以依靠简单的操作,得到计算结果的表达式,所以对中缀表达式的求值过程,是先将中缀表达式转化成后缀表达式,然后对该后缀表达式求值

第2章 数据结构与算法设计
2.1数据结构设计
所运用到的存储结构定义:
顺序栈结构
typedef struct
{
ElemType data[MaxSize]; //存放栈中的数据元素
int top; //栈顶指针,即存放栈顶元素在data数组中的下标
}SqStack; //顺序栈类型

2.2算法设计
中缀表达式转后缀表达式的函数算法执行步骤如下,
第一步,从exp中读取字符
第二步,判断字符是否为’\0’。若为’\0’,则将Optr中的所有运算符依次出栈并存放到postexp中,转至第八步。若不为’\0’,则继续执行第三步
第三步,判断读取的字符是否为数字,若为数字则依次将所有的数字存放到postexp中,以#结束,转至第一步。若不为数字字符继续执行下一步
第四步,判断是否为操作符,若是则转至下一步。若不是则执行第六步
第五步,判断Optr是否为空或者栈顶元素为’(’,若不是则比较与栈顶元素的优先级,若栈顶元素优先级高,则将栈顶元素出栈,存入postexp中,将该操作符进栈,反之直接将该操作符存入postexp中。若Optr为空或者栈顶元素为’(’,则将该操作符直接进栈。无论哪一种情况,最终转至第一步。
第六步,判断读取的字符是否为’)’,若是,则将栈中元素依次出栈存入postexp中,直到遇到’(’,将其出栈后便停止出栈,转至第一步,若不是则转至下一步
第七步,该元素为‘(’,直接将其进Optr,转至第一步。
第八步,输出postexp,其结果为后缀表达式

后缀表达式求值的函数算法执行步骤如下,
第一步,从postexp中读取字符
第二步,判断读取的字符是否为’\0’,若是则转至第七步,若不是则执行下一步
第三步,判断读取的字符是否为数字字符,若是则将连续的数字串转换为对应的数值并将其进数值栈Opnd,转至第一步。若不是则转至下一步
第四步,该字符是为操作符,判断该操作符为单目运算符,还是双目运算符。若为单目运算符,转至第五步,若为双目运算符,转至第六步。
第五步,将Opnd栈顶元素弹出,进行运算,将运算结果再次压入Opnd栈顶。返回第一步。
第六步,将Opnd栈顶元素与次栈顶元素弹出进行运算,次栈顶对栈顶进行运算。结果再次压入Opnd栈顶。返回第一步。
第七步,返回栈顶元素,该元素则为最终的结果。

附录
(该章将程序的所有代码写入)

#include<iostream>
#include<stdlib.h>
using namespace std;
#include<malloc.h>
#include<math.h>
#define MaxSize 100
typedef char ElemType;
typedef double ElemType1;
typedef struct
{
	ElemType data[MaxSize];		//存放栈中的数据元素
	int top;		//栈顶指针,即存放栈顶元素在data数组中的下标
}SqStack;		//顺序栈类型
void InitStack(SqStack * &s)		//初始化栈的函数
{
	s=(SqStack *)malloc(sizeof(SqStack));		//分配一个顺序栈空间,首地址存放在s中
	s->top=-1;		//栈顶指针置为-1,表示栈空
}
void DestroyStack(SqStack *&s)		//销毁栈的函数
{
	free(s);
}
bool StackEmpty(SqStack *s)		//判断栈是否为空,该函数实际上用于判断s->top==-1是否成立
{
	return(s->top==-1);
}
bool Push(SqStack * &s,ElemType e)		//进栈
{
	if(s->top==MaxSize-1)	//栈满的情况,即栈上溢出
		return false;
	s->top++;		//栈顶指针增1
	s->data[s->top]=e;		//元素e放在栈顶指针处
	return true;
}
bool Pop(SqStack * &s,ElemType &e)		//出栈
{
	if(s->top==-1)		//栈为空的情况,即栈下溢出
		return false;
	e=s->data[s->top];		//取栈顶元素
	s->top--;		//栈顶指针减1
	return true;
}
bool GetTop(SqStack *s,ElemType &e)		//取栈顶元素
{
	if(s->top==-1)		//栈为空的情况,即栈下溢出
		return false;
	e=s->data[s->top];		//取栈顶元素
	return true;
}
typedef struct
{
	ElemType1 data[MaxSize];		//存放栈中的数据元素
	int top;		//栈顶指针,即存放栈顶元素在data数组中的下标
}SqStack1;		//顺序栈类型
void InitStack(SqStack1 * &s)		//初始化栈的函数
{
	s=(SqStack1 *)malloc(sizeof(SqStack1));		//分配一个顺序栈空间,首地址存放在s中
	s->top=-1;		//栈顶指针置为-1,表示栈空
}
void DestroyStack1(SqStack1 *&s)		//销毁栈的函数
{
	free(s);
}
bool StackEmpty(SqStack1 *s)		//判断栈是否为空,该函数实际上用于判断s->top==-1是否成立
{
	return(s->top==-1);
}
bool Push1(SqStack1 * &s,ElemType1 e)		//进栈
{
	if(s->top==MaxSize-1)	//栈满的情况,即栈上溢出
		return false;
	s->top++;		//栈顶指针增1
	s->data[s->top]=e;		//元素e放在栈顶指针处
	return true;
}
bool Pop1(SqStack1 * &s,ElemType1 &e)		//出栈
{
	if(s->top==-1)		//栈为空的情况,即栈下溢出
		return false;
	e=s->data[s->top];		//取栈顶元素
	s->top--;		//栈顶指针减1
	return true;
}
bool GetTop1(SqStack1 *s,ElemType1 &e)		//取栈顶元素
{
	if(s->top==-1)		//栈为空的情况,即栈下溢出
		return false;
	e=s->data[s->top];		//取栈顶元素
	return true;
}
void trans(char *exp,char postexp[])		//将算术表达式exp转化成后缀表达式postexp
{
	char e;
	int i=0;
	SqStack*Optr;		//定义运算符栈指针
	InitStack(Optr);		//初始化运算符栈
	while( *exp!='\0')		//exp表达式未扫描完时循环
	{
		switch(*exp)
		{
		case '('://判定左括号
			exp++;
			if(*exp=='-')
			{
				exp--;
				Push(Optr,'(');		//左括号进栈
				exp+=2;
				postexp[i++]='@';
				break;
			}
			exp--;
			Push(Optr,'(');	
			exp++;		//继续扫描其他字符
			break;
		case ')':		//判定右括号
			Pop(Optr,e);		//出栈元素e
			while(e!='(')		//不为(时循环
			{
				postexp[i++]=e;		//将e存放到postexe中
				Pop(Optr,e);		//出栈元素e
			}
			exp++;		//继续扫描其他字符
			break;
		case '+':		//判定为+或-号
		case '-':
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e!='(')		//e不是'('
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是'('时退出循环
			}
			Push(Optr,*exp);		//将'+'或'-'进栈
			exp++;		//继续扫描其他字符
			break;
		case '*':		//判定为'*'或'/'号
		case '/':
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='*'||e=='/')		//e是'*'或'/'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非'*'或'/'时退出循环
			}
			Push(Optr,*exp);		//将'*'或'/'进栈
			exp++;		//继续扫描其他字符
			break;
		case '^':		//判断为^号
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='^')		//e是'^'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非'^'时退出循环
			}
			Push(Optr,*exp);		//将'^'进栈
			exp++;		//继续扫描其他字符
			break;
		case 'l':		//判断为log号
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='l')		//e是'l'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非'l'时退出循环
			}
			Push(Optr,*exp);		//将'l'进栈
			exp+=3;		//继续扫描其他字符
			break;
		case'c':	//判断为cos号
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='c')		//e是'l'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非'c'时退出循环
			}
			Push(Optr,*exp);		//将'c'进栈
			exp+=3;		//继续扫描其他字符
			break;
		case's':	//判断为sin号
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='s')		//e是's'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非's'时退出循环
			}
			Push(Optr,*exp);		//将's'进栈
			exp+=3;		//继续扫描其他字符
			break;
		case't':	//判断为tan号
			while(!StackEmpty(Optr))		//栈不空循环
			{
				GetTop(Optr,e);		//取栈顶元素e
				if(e=='t')		//e是't'
				{
					postexp[i++]=e;		//将e存放到postexp中
					Pop(Optr,e);		//出栈元素e
				}
				else
					break;		//e是非't'时退出循环
			}
			Push(Optr,*exp);		//将't'进栈
			exp+=3;		//继续扫描其他字符
			break;
		default:		//处理数字字符
			while( *exp>='0'&&*exp<='9'||*exp=='.')		//判定为数字和小数点字符
			{
				postexp[i++]= * exp;
				exp++;
			}
			postexp[i++]='#';		//用#标识一个数字串结束
		}
	}
	while(!StackEmpty(Optr))		//此时exp扫描完毕,栈不空时循环
	{
		Pop(Optr,e);		//出栈元素e
		postexp[i++]=e;		//将e放到postexp中
	}
	postexp[i]='\0';		//给postexp表达式添加结束的标志
	DestroyStack(Optr);		//销毁栈
}
double compvalue(char *postexp)		//计算后缀表达式的值
{
	double d,a,b,c,e;
	int n,m=1,w=1;
	SqStack1*Opnd;		//定义操作数栈
	InitStack(Opnd);		//初始化操作数栈
	while( *postexp!='\0')		//postexp字符串未扫描完时循环
	{
		switch( *postexp)
		{
		case'+':		//判定为'+'号
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			c=b+a;		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;
		case'-':		//判定为'-'号
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			c=b-a;		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;
		case'*':		//判定为'*'号
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			c=b*a;		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;
		case'/':		//判定为'/'号
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			if(a!=0)
			{
				c=b/a;		//计算c
				Push1(Opnd,c);		//将计算结果c进栈
				break;
			}
			else
			{
				printf("\n\t除零错误!\n");
				exit(0);		//异常退出
			}
		case'^':		//判定为'^'号
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			c=pow(b,a);		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;
		case'l':		//判定为log函数
			Pop1(Opnd,a);		//出栈元素a
			Pop1(Opnd,b);		//出栈元素b
			c=(log(a))/(log(b));		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;	
		case'c':		//判定为cos函数
			Pop1(Opnd,a);		//出栈元素a
			c=cos(a);		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;	
		case's':		//判定为sin函数
			Pop1(Opnd,a);		//出栈元素a
			c=sin(a);		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;	
		case't':		//判定为tan函数
			Pop1(Opnd,a);		//出栈元素a
			c=tan(a);		//计算c
			Push1(Opnd,c);		//将计算结果c进栈
			break;	
		default:
			d=0;		//处理数字字符
			n=0;
			while( *postexp>='0'&& *postexp<='9'||*postexp=='.'||*postexp=='@')		//判定为数字或者小数点
			{
				if(*postexp=='@')
				{m=-1;
				*postexp++;}
				d=10*d+ *postexp-'0';
				postexp++;
				if( *postexp=='.')		//处理小数点之后的数字
				{
					W=-1;
					*postexp++;		//跳过小数点
					n=0;		//无论前面n加了多少次,一旦遇到'.'就从小数点之后开始重新计数
				}
				n++;
			}
			d=d/pow(10,(n-1));		
			d=m*d;
			if(w!=-1)
			{
				d=d*pow(10,n-1);
			}
			m=1;
			w=1;
			Push1(Opnd,d);		//将数值d进栈
			break;
		}
			postexp++;		//处理其他字符
	}
		GetTop1(Opnd,e);		//取栈顶元素
		DestroyStack1(Opnd);		//销毁栈
		return e;		//返回e
}
void behind(char*postexp)    //输出后缀表达式
{
	int t;
	t=strlen(postexp);
	for(int i=0;i<t;i++)
	{
		if(*(postexp+i)=='s') {cout<<"sin";continue;}
		if(*(postexp+i)=='l') {cout<<"log";continue;}
		if(*(postexp+i)=='c') {cout<<"cos";continue;}
		if(*(postexp+i)=='t') {cout<<"tan";continue;}
		if(*(postexp+i)=='@') {cout<<"-";continue;}
		cout<<*(postexp+i);
	}
	cout<<endl;
}
int main()
{
	while(1)
	{
	int q;
	cout<<"**- 请输入算术表达式 -**"<<endl;
	char exp[MaxSize];
	char postexp[MaxSize];
	cin>>exp;		//输入算术表达式
	trans(exp,postexp);
	cout<<"中缀表达式:"<<exp<<endl;
	cout<<"后缀表达式";
	behind(postexp);
	cout<<"表达式的值"<<compvalue(postexp)<<endl;
	cout<<"enter '1' clear  the  screen  "<<endl;
	cin>>q;
	switch(q)
	{
	case 1:system("cls");
	default :break;
	}
	}
	return 1;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值