数据结构课程设计--表达式求值

【案例分析】
任何一个表达式都是由操作数(operand)、运算符(operator)和界限符(delimitear)组成的,统称它们为单词。一般地,操作数既可以是常数,也可以是被说明为变量或常量的标识符;动符可以分为算术运算符、关系运算符和逻辑运算符3类;基本界限符有左右括号和表达式结束符等。为了叙述的简洁,在此仅讨论简单算术表达式的求值问题;这种表达式只含加、减、乘、除4种运算符。读者不难将它推广到更一般的表达式上。
下面把运算符和界限符统称为算符。
我们知道,算术四则运算遵循以下3条规则:
(1)先乘除,后加减;
(2)从左算到右;
(3)先括号内,后括号外。
根据上述3条运算规则,在运算的每一步中,任意两个相继出现的算符t1和t2之间的优先关系,至多是下面3种关系之一:

t1<t2     t1的优先权低于t2
t1=t2     t1的优先权等于t2
t1>t2     t1的优先权高于t2
表3.1定义了算符之间的这种优先关系。

算符间的优先关系

t1    t2+-*/()#
+>><<<>>
->><<<>>
*>>>><>>
/>>>><>>
(<<<<<=
)>>>>>>
#<<<<<=

      由规则(1),先进行乘除运算,后进行加减运算,所以有  “+”  <  “*”;  “+” < “/” ;"*" > “+” ; "/" >"+"等。

       由规则(2),运算遵循左结合性,当两个运算符相同时,先出现的运算符优先级高,所以有“+” > “+”;“-”  > “-”;“*”  > “*”;“/”  > “/”。

       由规则(3),括号内的优先级高,+、一、*和/为t1时的优先性均低于“(”但高于“)”。

       表中的“(”=“)”表示当左右括号相遇时,括号内的运算已经完成。为了便于实现,假设每个表达式均以“#”开始,以“#”结束。所以“#”=“#”表示整个表达式求值完毕。“)”与“(” 、“#”与“)”以及“(”与“#”之间无优先关系,这是因为表达式中不允许它们相继出现,一旦遇到这种情况,则可以认为出现了语法错误。在下面的讨论中,我们暂假定所输入的表达式不会出现语法错误。
【案例实现】
为实现算符优先算法,可以使用两个工作栈,一个称做OPTR,用以寄存运算符,另一个称作OPND,用以寄存操作数或运算结果。

【思路说明】

1. 该程序总体上来说是借助栈的相关知识来实现的。该程序定义了两个顺序栈OPTR和OPND,其中OPTR用来寄存运算符,OPND用来寄存操作数或者运算结果。

2. EvaluateExpression()函数部分为该程序的主体部分,该部分通过调用二元运算函数Operate(ElemType c1, char y, ElemType c2),字符判断函数In(char ch)、字符优先级判断函数Precede(char a, char b)以及栈的相关操作来完成表达式的求值过程。该函数的运算的最终结果即为表达式的值。

#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define MAXSIZE 100000
typedef int ElemType;

//定义顺序栈
typedef struct {
	ElemType data[MAXSIZE];//静态数组存放栈中元素
	int top;//栈顶指针;
} SqStack;

//初始化栈
void InitStack(SqStack &S) {
	S.top = -1; //初始化栈顶指针
}

//入栈
int Push(SqStack &S, ElemType x) {
	if (S.top == MAXSIZE - 1) //栈满
		return ERROR;
	S.data[++S.top] = x; //top指针先加1,新元素再入栈
	return OK;
}

//获取栈顶元素
ElemType GetTop(SqStack S) {
	return S.data[S.top];
}

//出栈
int Pop(SqStack &S, ElemType &x) {
	if (S.top == - 1) //栈空
		return ERROR;
	x = S.data[S.top--]; //栈顶元素先出栈,top指针再减1
	return OK;
}

//判断读入的字符ch是否为运算符
int In(char ch) {
	if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '#') //ch是运算符
		return OK;
	return ERROR;
}

//判断运算符的栈顶元素与读入的运算符之间的优先级关系
char Precede(char a, char b) {
	if (a == '+' || a == '-') {
		if (b == '+' || b == '-' || b == '#' || b == ')')
			return '>';//a运算符的优先级高于b
		else
			return '<';    //a运算符的优先级低于b
	} else if (a == '*' || a == '/') {
		if (b == '(')
			return '<';	   //先运算括号内的
		else
			return '>';        //先乘除,后加减,且运算符相同时先出现的优先级高
	} else if (a == '(') {
		if (b == ')')
			return '=';   //括号内运算完成
		else
			return '<';		  //先运算括号内的,再运算括号外的
	} else if (a == '#') {
		if (b == '#')
			return '=';   //整个表达式求值完毕
		else
			return '<';       //a的优先级低于b
	} else
		return '0';       //输入异常,出现错误
}

//二元运算函数
ElemType Operate(ElemType c1, char y, ElemType c2) {
	if (y == '+')
		return c1 + c2;
	else if (y == '-')
		return c1 - c2;
	else if (y == '*')
		return c1 * c2;
	else if (y == '/')
		return c1 / c2;
	else
		return 0;
}

//算术表达式求值的算符优先算法
ElemType EvaluateExpression() {
	SqStack OPTR, OPND;      //定义数字栈OPTR和OPND,OPTR寄存运算符,OPND寄存操作数和运算结果
	InitStack(OPTR);	//初始化OPTR栈
	InitStack(OPND);	//初始化OPND栈
	ElemType theta, b, a, x; //theta,x存储OPTR栈顶的运算符,a,b存储OPND栈顶的两个运算数
	char ch;
	cin >> ch;
	ElemType cnt = 0;						//cnt表示要入OPND栈的数字
	bool flag = false, first = false;		//flag用来判断是否有数字输入,first用来判断输入的是否是第一个字符
	if (!first && ch == '#') {				//将第一个输入的'#'压入OPTR栈
		Push(OPTR, (ElemType)'#');
		first = true;
		cin >> ch;
	}
	while (ch != '#' || (char)GetTop(OPTR) != '#') { //表达式没有扫描完毕或OPTR的栈顶元素不为’#‘
		while (!In(ch)) {				//ch不是运算符
			cnt = cnt * 10 + ch - '0';
			cin >> ch;
			flag = true;
		}
		if (flag) {							//只有有数字输入时才会执行此操作,将输入的数字压入OPND栈
			Push(OPND, (ElemType)cnt);
			cnt = 0;
			flag = false;
		} else {
			switch (Precede((char)GetTop(OPTR), ch)) { //比较OPTR栈顶元素和ch的优先级
				case '<':
					Push(OPTR, (ElemType)ch);			//当前字符压入OPTR栈
					cin >> ch;				//读入下一字符ch
					break;
				case '>':
					Pop(OPTR, theta);		//弹出OPTR栈顶的运算符
					Pop(OPND, b);
					Pop(OPND, a); //弹出OPND栈顶的两个运算数
					Push(OPND, Operate(a, (char)theta, b)); //将运算结果压入OPND栈
					break;
				case '=':					//OPTR的栈顶元素是'('且ch是')'
					Pop(OPTR, x);
					cin >> ch;	//弹出OPTR栈顶的'(',读入下一字符ch
					break;
				case '0':
					cout << "输入不符合要求" << endl;
					exit(1);      //输入出现错误,退出程序
			}
		}
	}

	return GetTop(OPND);					//OPND栈顶元素即为表达式求值结果
}

int main() {
	cout << EvaluateExpression() << endl;
	return 0;
}

【不足之处】

只能实现正整数的加减乘除运算,而且计算结果不够精确。如果出现问题,欢迎批评指正啊

  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值