【数据结构】——中缀表达式求值

题目要求

从键盘输入中缀表达式,建立操作数与运算符堆栈,计算并输出表达式的求值结果。

基本要求:实现 +, -, *, /四个二元运算符以及();操作数范围为0至9。

提高要求:实现+, -两个一元运算符(即正、负号);操作数可为任意整型值(程序可不考虑计算溢出)。

若两个整数相除,结果只保留整数商(余数丢弃);可不处理表达式语法错误。

涉及知识点

栈与队列

数据结构设计

采用C++的模板类,分别创建元素类型为整型的操作数栈OPND和字符型的运算符栈OPTR,每个栈对象中,elem指针用来建立长度为n的数组,n表示栈中元素的最大个数,top表示栈顶指针。

算法描述

①中缀表达式以'#'结束,'#'字符也做运算符处理。

②'('、')'作为运算符处理,括号内运算结束后需要消除括号。

③需要建立两个不同类型的栈,整型的操作数栈OPND和字符型的运算符栈OPTR。

④算法主要步骤:

    a. 初始时,OPND置空,'#'作为OPTR栈底元素;

    b. 依次读入表达式中的每个字符,若是操作数,直接压入OPND栈;

    c. 若是运算符(记为\theta),则和OPTR栈顶运算符(记为\lambda)比较优先级;

        \lambda<\theta\theta压入OPTR栈,继续读下一个字符;

        \lambda=\theta,脱括号,继续读下一个字符;

        \lambda>\theta,执行\lambda运算(\lambda退栈),\theta等在栈外(不读下一个字符),即\theta继续和OPTR 栈顶运算符比较优先级(重复进行以上操作),直至\theta能入栈。

⑤对于一元运算符(即正、负号),用'P'代表'+','N'代表'-'。

程序代码

#include<iostream>
#include<stdio.h>
using namespace std;
template <typename T>
#define MAX 100
class Stack                     //模板类:栈
{
public:
	Stack();                //默认构造函数
	Stack(int n);           //构造函数,调用函数createStack(int n),创建长度为n的栈
	~Stack();               //虚构函数
	int createStack(int n); //创建长度为n的栈
	int empty();            //判断栈是否为空
	int full();             //判断栈是否为满
	int push(T e);          //将元素e压栈
	int pop(T &e);          //元素出栈,保存在e中
	T get_top();            //得到栈顶元素
	friend int isoperator(char &e);//判断字符e是否为运算符
	friend int isp(char &e);//返回栈中运算符的优先级
	friend int icp(char &e);//返回栈外运算符的优先级
	friend int compute(int x, char a, int y);//求值函数
private:
	T *elem;                //建立长度为n的数组
	int n;                  //栈中元素的最大个数
	int top;                //栈顶指针
};
template<typename T>
Stack<T>::Stack()
{
	top = -1;
}
template<typename T>
Stack<T>::Stack(int n)
{
	createStack(n);
}
template<typename T>
Stack<T>::~Stack()
{
	n = 0;
	top = -1;
	delete[]elem;
}
template<typename T>
int Stack<T>::createStack(int n)
{
	if (n <= 0)
		return 0;
	this->n = n;
	top = -1;
	elem = new T[n];
	if (!elem)
		return 0;
	return 1;
}
template<typename T>
int Stack<T>::empty()
{
	return top == -1;
}
template<typename T>
int Stack<T>::full()
{
	return top >= n - 1;
}
template<typename T>
int Stack<T>::push(T e)
{
	if (top >= n - 1)
		return 0;
	elem[++top] = e;
	return 1;
}
template<typename T>
int Stack<T>::pop(T & e)
{
	if (top == -1)
		return 0;
	e = elem[top--];
	return 1;
}
template<typename T>
T Stack<T>::get_top()
{
	return elem[top];
};
int isoperator(char &e)        //判断是否为运算符
{
	if (e == '+' || e == '-' || e == '*' || e == '/' || e == '(' || e == ')' || e == '#' || e == 'P' || e == 'N')
		return 1;      //是运算符返回1
	else
		return 0;      //不是运算符返回0
}
int isp(char &e)               //返回栈中运算符的优先级
{
	switch (e)
	{
	case '#':
		return 0; break;
	case '(':
		return 1; break;
	case '+':
	case '-':
		return 2; break;
	case '*':
	case '/':
		return 3; break;
	case 'P':
	case 'N':
		return 4; break;
	case ')':
		return 5; break;
	default:
		return -1; break;
	}
}
int icp(char &e)                 //返回栈外运算符的优先级
{
	switch (e)
	{
	case '#':
		return 0; break;
	case ')':
		return 1; break;
	case '+':
	case '-':
		return 2; break;
	case '*':
	case '/':
		return 3; break;
	case 'P':
	case 'N':
		return 4; break;
	case '(':
		return 5; break;
	default:
		return -1; break;
	}
}
int compute(int x, char a, int y)
{
	switch (a)
	{
	case '+':                //计算加法
		return x + y; break;
	case '-':                //计算减法
		return x - y; break;
	case '*':                //计算乘法
		return x * y; break;
	case '/':                //计算除法
		return x / y; break;
	default:
		return -1; break;
	}
}
int g1()
{
	char a, b, c;
	int i, j, f, value, firstOpnd, secondOpnd, m;
	Stack<char> OPTR(MAX);    //建立运算符栈
	Stack<int> OPND(MAX);     //建立操作数栈
	OPTR.push('#');           //'#'压栈
	cout << "请输入中缀表达式: ";
	a = getchar();
	while (a != '#' || OPTR.get_top() != '#')
	{
		if (!isoperator(a))   //不是运算符,即为操作数,操作数入栈
			OPND.push(a - 48);//将字符型转化为整型数字
		else                  //是运算符,与栈顶运算符比较优先级大小
		{
			b = OPTR.get_top();//得到栈顶元素
			i = isp(b);       //栈顶运算符的优先级
			j = icp(a);       //栈外运算符的优先级
			if (i < j)        //栈外运算符优先级高,运算符入栈
				OPTR.push(a);
			else
			{
				OPTR.pop(b);					
				if (b != '('&&i == j || i > j)
				{
					c = OPTR.get_top();
					if ((c == '(' || c == '#') && (b == 'P' || b == 'N'))    /*c为一元运
                                                                            算符:正负号*/
					{
						OPND.pop(firstOpnd); //得到操作数
						switch (b)
						{
						case 'P':            //正号
							f = firstOpnd * 1;
							break;
						case 'N':            //负号
							f = firstOpnd * (-1);
							break;
						}
					}
					else                     //c为二元运算符
					{
						OPND.pop(secondOpnd); //得到第二操作数
						OPND.pop(firstOpnd);  //得到第一操作数
						f = compute(firstOpnd, b, secondOpnd); //计算求值
					}
					OPND.push(f);             //求值结果压栈
					continue;
				}
			}
		}
		c = a;
		a = getchar();                         //继续读取字符
		while(!isoperator(a) && !isoperator(c))  /*若连续读取字符均为数字,则乘以位权
                                                  得到多位数*/
		{
			OPND.pop(m);
			m = m * 10 + a - 48;
			OPND.push(m);
			c = a;
			a = getchar();
		}
		
	}
	OPND.pop(value);
	return value;      //返回表达式的结果
}
int main()
{
	int a;
	a = g1();
	cout << "运算结果为:  " << a << endl;
    return 0;
}

示例

(1)程序输入:3+5*(9-5)/10#

         程序输出:5

(2)程序输入:P9+10*(N2*8/4)-10#

         程序输出:-41

(3)程序输入:20-3*25+(N41/3)*100#

         程序输出:-1355

  • 10
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
中缀表达式求值是指将一个中缀表达式转换为后缀表达式,并计算后缀表达式的值的过程。具体步骤如下: 1. 创建一个操作数和一个运算符。 2. 从左到右扫描中缀表达式的每个元素。 3. 如果当前元素是操作数,则将其压入操作数中。 4. 如果当前元素是运算符,则进行如下操作: 1. 如果运算符为空,或者顶运算符为左括号,则将当前运算符压入运算符中。 2. 如果当前运算符的优先级大于顶运算符的优先级,则将当前运算符压入运算符中。 3. 否则,将运算符顶的运算符弹出并压入操作数中,直到当前运算符的优先级大于顶运算符的优先级。 5. 如果当前元素是左括号,则将其压入运算符中。 6. 如果当前元素是右括号,则进行如下操作: 1. 将运算符顶的运算符弹出并压入操作数中,直到遇到左括号。 2. 将左括号弹出,但不压入操作数中。 7. 如果中缀表达式的所有元素都已经扫描完毕,则将运算符中的所有运算符依次弹出并压入操作数中。 8. 最后,操作数中的唯一元素就是中缀表达式的值。 下面是一个示例中缀表达式求值的代码实现,使用C++模板类实现操作数和运算符: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; template<typename T> class Stack { public: Stack(int n) { elem = new T[n]; top = -1; max_size = n; } ~Stack() { delete[] elem; } bool push(T x) { if (top == max_size - 1) { return false; } elem[++top] = x; return true; } bool pop(T& x) { if (top == -1) { return false; } x = elem[top--]; return true; } bool top(T& x) { if (top == -1) { return false; } x = elem[top]; return true; } bool empty() { return top == -1; } private: T* elem; int top; int max_size; }; int priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; default: return 0; } } int evaluate(string expr) { Stack<int> opnd(expr.length()); Stack<char> optr(expr.length()); int i = 0; while (i < expr.length()) { if (isdigit(expr[i])) { int num = 0; while (i < expr.length() && isdigit(expr[i])) { num = num * 10 + (expr[i] - '0'); i++; } opnd.push(num); } else if (expr[i] == '(') { optr.push(expr[i]); i++; } else if (expr[i] == ')') { char op; optr.pop(op); while (op != '(') { int b, a; opnd.pop(b); opnd.pop(a); switch (op) { case '+': opnd.push(a + b); break; case '-': opnd.push(a - b); break; case '*': opnd.push(a * b); break; case '/': opnd.push(a / b); break; } optr.pop(op); } i++; } else if (expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/') { char op = expr[i]; while (!optr.empty() && optr.top() != '(' && priority(op) <= priority(optr.top())) { int b, a; opnd.pop(b); opnd.pop(a); char op2; optr.pop(op2); switch (op2) { case '+': opnd.push(a + b); break; case '-': opnd.push(a - b); break; case '*': opnd.push(a * b); break; case '/': opnd.push(a / b); break; } } optr.push(op); i++; } else { i++; } } while (!optr.empty()) { int b, a; opnd.pop(b); opnd.pop(a); char op; optr.pop(op); switch (op) { case '+': opnd.push(a + b); break; case '-': opnd.push(a - b); break; case '*': opnd.push(a * b); break; case '/': opnd.push(a / b); break; } } int result; opnd.pop(result); return result; } int main() { string expr = "3+4*5-(6+7)*8/9"; int result = evaluate(expr); cout << result << endl; return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值