C++表达式求值(Stack and Expression)

表达式求值有几个核心的技术:

1 中缀infix表达式转后缀postfix表达式(文本解析)

解析中缀表达式到后缀表达式的核心思想就是对表达式逐步向前解析;

如果遇到一个空格就连续“吃掉”紧接着的空格;

如果遇到一个操作数就“继续吃掉紧接着的整数中的低位数字,完整一个完整整数的读取;

如果遇到了不应该出现的字符就抛出异常。

 

1.1 运算符操作优先级(使用整形作为特征值)

本文给出的方法简洁有效(比那个二维数组扯淡玩意儿高效简洁了不知道多少)

1.2 吃掉表达式中的任意空格和整数

2 后缀表达式求值(利用栈来快速求值)

类图

 

1 中缀infix表达式转后缀postfix表达式(文本解析)

 

//把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)  
void Calculator::ToPostfix(const string& pre , Expression& _postExpression)  
{  
	CStack<char> operatorStack;
	operatorStack.push('#');
	auto preItr = pre.begin() ;
	auto end = pre.end();
	string strNumber;
	while(preItr != pre.end())  
	{  
		ReadSpace(preItr, end);// space before expression 
		strNumber.clear();
		if(isdigit(*preItr)) 
		{  		
			ReadNumber(preItr, end, strNumber); // read number 1
			_postExpression.push_back(strNumber);
		}  
		else if (*preItr=='(')   // 遇到“(”不用比较直接入栈  
		{
			operatorStack.push(*preItr++);  
		}
		else if(*preItr ==')')  // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式  
		{  
			while(operatorStack.top()!='(')  
			{  
				_postExpression.push_back(string(1,operatorStack.pop()));  
			}  
			operatorStack.pop(); // discard '('
			++preItr;//discard ')'
		}  
		else if (IsOperator(*preItr))  
		{  
			while(Priority(*preItr) <= Priority(operatorStack.top()))   
			{  
				// 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程  
				_postExpression.push_back(string(1, operatorStack.pop()));  
			}  
			operatorStack.push(*preItr++); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈  
		}  
		else if (!isspace(*preItr))//Extra credit 1 for invalid input
		{
			throw CExpressionException("invalid input, character not supported!");
		}
	}  
	while(!operatorStack.empty()) // 将所有的操作符加入后缀表达式  
	{  
		if (operatorStack.top() == '(')
		{
			throw CExpressionException("invalid input in expression, missing ')'!");
		}
		_postExpression.push_back(string(1, operatorStack.pop()));
		
	}  
	_postExpression.pop_back();//discard #
}

 

2 后缀表达式求值(利用栈来快速求值)

 

int Calculator::GetValue(void)  const
{  
	if (m_infix.empty())
	{
		throw CExpressionException("no infix expression in Calculator!");
	}
	Expression post;
	ToPostfix(m_infix, post);

	CStack<int> stack;    // 操作数栈  
	int x1, x2;  

	auto itr = post.begin();
	while(itr != post.end())  
	{  
		if(!IsOperator((*itr)[0]))  
		{
			stack.push(std::stoi(*itr));
		}
		else if ((*itr)[0] =='+')  
		{  
			x2 = stack.pop();  
			x1 = stack.pop();  
			stack.push(x1+x2);  
		}  
		else if ((*itr)[0] =='-')  
		{  
			x2 = stack.pop();  
			x1 = stack.pop();  
			stack.push(x1-x2);  
		}  
		else if ((*itr)[0] =='*')  
		{  
			x2 = stack.pop();  
			x1 = stack.pop();  
			stack.push(x1*x2);  
		}  
		else if ((*itr)[0] =='/')  
		{  
			x2 = stack.pop();  
			x1 = stack.pop();  
			stack.push(x1/x2);  
		}
		else if ((*itr)[0] =='%')
		{
			x2 = stack.pop();  
			x1 = stack.pop();  
			stack.push(x1%x2); 
		}
		else if ((*itr)[0] == '^')
		{
			int power = 1;
			x2 = stack.pop();
			x1 = stack.pop();
			for (int i = 0; i < x2; ++i)
			{
				power *= x1;
			}
			stack.push(power);
		}
		++itr;
	}  
	return stack.top();  
}

 

3 运算符操作优先级(使用整形作为特征值)

 

int Calculator::Priority(char op)  
{  
	switch(op)  
	{  
	case '#':  
		return -1;  
	case '(':  
		return 0;  
	case '+':  
	case '-':  
		return 1;  
	case '*':  
	case '/':  
	case '%':  
		return 2;  
	case '^':  
		return 3;  
	default :  
		return -1;  
	}  
} 

上面的代码中其中第一个表达式解析的核心思想就是对表达式逐步向前解析,根据已经捕获的表达式预期后续表达式内容,如果不符合就抛出异常。为了能够更好的表达代码和思路,封装几个必要的“吃掉”表达式中指定子结构的函数是必要的。

 

例如吃掉表达式中的任意空格和整数

4 吃掉表达式中的任意空格和整数

 

void Calculator::ReadSpace(string::const_iterator& _itr, string::const_iterator& _end)
{
	while(_itr != _end) 
	{
		if (isspace(*_itr))
		{
			++_itr;
		}
		else
		{
			break;
		}
	}
}
void Calculator::ReadNumber(string::const_iterator& _itr, string::const_iterator& _end, string& _value)
{
	while(_itr != _end)//read number as 275
	{
		if (isdigit(*_itr))
		{
			_value.push_back(*_itr++);
		}
		else
		{
			break;
		}
	}
}

5 测试程序:

 

 

#include <iostream>
#include <string>
#include <cassert>
#include <list>
using namespace std;

#include "Stack.h"
#include "Calculator.h"

void Input(list<Calculator>& listCalculator);
void Output(const list<Calculator>& listCalculator);
void TestAll(list<Calculator>& listCalculator);

int main(int argc, char** argv)
{
	cout<<"Please input some expressions with one expression in one line:"<<endl;
	cout<<"Tokens are always separated by one space."<<endl;
	cout<<"Input 0 for end your input."<<endl;

	list<Calculator> listCalculator;

	TestAll(listCalculator);

	//Input(listCalculator);//Extra credit 1:(1)any space (2)catch invalid input
	//Output(listCalculator);
	
	return 0;
}
void Input(list<Calculator>& listCalculator)
{
	while (true)
	{
		string sLine, invalidInfor;
		getline(cin, sLine);
		if (sLine == "0")
		{
			break;
		}
		if (Calculator::Check(sLine, invalidInfor) == false)//Extra credit 1:(1)any space (2)catch invalid input
		{
			cout<<invalidInfor<<endl;
			continue;
		}
		listCalculator.push_back(sLine);
	}
}
void Output(const list<Calculator>& listCalculator)
{
	cout<<"infix list:"<<endl;
	for(auto itr = listCalculator.begin(); itr != listCalculator.end(); ++itr)
	{
		cout<<itr->GetExpression()<<endl;
	}

	cout<<"postfix list:"<<endl;
	for(auto itr = listCalculator.begin(); itr != listCalculator.end(); ++itr)
	{
		cout<<itr->ToPostfix()<<endl;
	}

	cout<<"values of expressions are:"<<endl;
	for(auto itr = listCalculator.begin(); itr != listCalculator.end(); ++itr)
	{
		cout<<itr->GetValue()<<endl;
	}
}
void TestAll(list<Calculator>& listCalculator)
{
	list<string> listExp;
	
	
	listExp.push_back("(5+1) * ( 2 + 3");
	listExp.push_back("(5+1) * ( 2 + 3)");
	listExp.push_back("(5+(1+1)) * ( 2 + 3)");
	listExp.push_back("1++1");
	listExp.push_back("1&1");
	listExp.push_back("17 / ( 2 + 3 ) - 13");
	listExp.push_back("5 * 2 ^ 3");
	listExp.push_back("1+   (2-3)*4   ^5%6     /         78");

	for (auto itr = listExp.begin(); itr != listExp.end(); ++itr)
	{
		string invalidInfor;
		if (Calculator::Check(*itr, invalidInfor) == false)//Extra credit 1:(1)any space (2)catch invalid input
		{
			cout<<invalidInfor<<endl;
			continue;
		}
		listCalculator.push_back(*itr);
	}	
	Output(listCalculator);
	listCalculator.clear();
}


运行结果:


 

 

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明
根据提供的引用内容,这是一个C++表达式求值代码,其中包含了栈的实现。具体实现过程如下: 1.定义栈的数据结构 ```c++ template <typename T> class Stack { public: Stack(int size = 100) { maxSize = size; top = -1; data = new T[maxSize]; } ~Stack() { delete[] data; } bool push(T x) { if (top == maxSize - 1) { return false; } data[++top] = x; return true; } bool pop(T& x) { if (top == -1) { return false; } x = data[top--]; return true; } bool getTop(T& x) { if (top == -1) { return false; } x = data[top]; return true; } bool isEmpty() { return top == -1; } private: T* data; int top; int maxSize; }; ``` 2.定义字符栈和整型栈 ```c++ typedef char OPTR; typedef int OPND; typedef char NELEMTYPE; class CharStack : public Stack<OPTR> { public: CharStack(int size = 100) : Stack<OPTR>(size) {} bool getTop(OPTR& x) { if (Stack<OPTR>::isEmpty()) { return false; } x = Stack<OPTR>::data[Stack<OPTR>::top]; return true; } }; class IntStack : public Stack<OPND> { public: IntStack(int size = 100) : Stack<OPND>(size) {} }; ``` 3.定义运算符优先级函数 ```c++ int precede(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': return 3; case ')': return 0; default: return -1; } } ``` 4.定义判断字符是否为运算符的函数 ```c++ bool isOptr(char c) { return (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')'); } ``` 5.定义运算函数 ```c++ int operate(int a, char op, int b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } ``` 6.定义表达式求值函数 ```c++ NELEMTYPE EvaluateExpression(CharStack& optrStack, IntStack& opndStack) { NELEMTYPE c; NELEMTYPE lastOptr = '#'; int lastOptrFlag = 0; int lastOptrPrecede = 0; int lastOptrPos = 0; int lastOptrPosFlag = 0; int lastOptrPosPrecede = 0; int lastOptrPosFlag2 = 0; int lastOptrPosPrecede2 = 0; int lastOptrPosFlag3 = 0; int lastOptrPosPrecede3 = 0; int lastOptrPosFlag4 = 0; int lastOptrPosPrecede4 = 0; int lastOptrPosFlag5 = 0; int lastOptrPosPrecede5 = 0; int lastOptrPosFlag6 = 0; int lastOptrPosPrecede6 = 0; int lastOptrPosFlag7 = 0; int lastOptrPosPrecede7 = 0; int lastOptrPosFlag8 = 0; int lastOptrPosPrecede8 = 0; int lastOptrPosFlag9 = 0; int lastOptrPosPrecede9 = 0; int lastOptrPosFlag10 = 0; int lastOptrPosPrecede10 = 0; int lastOptrPosFlag11 = 0; int lastOptrPosPrecede11 = 0; int lastOptrPosFlag12 = 0; int lastOptrPosPrecede12 = 0; int lastOptrPosFlag13 = 0; int lastOptrPosPrecede13 = 0; int lastOptrPosFlag14 = 0; int lastOptrPosPrecede14 = 0; int lastOptrPosFlag15 = 0; int lastOptrPosPrecede15 = 0; int lastOptrPosFlag16 = 0; int lastOptrPosPrecede16 = 0; int lastOptrPosFlag17 = 0; int lastOptrPosPrecede17 = 0; int lastOptrPosFlag18 = 0; int lastOptrPosPrecede18 = 0; int lastOptrPosFlag19 = 0; int lastOptrPosPrecede19 = 0; int lastOptrPosFlag20 = 0; int lastOptrPosPrecede20 = 0; int lastOptrPosFlag21 = 0; int lastOptrPosPrecede21 = 0; int lastOptrPosFlag22 = 0; int lastOptrPosPrecede22 = 0; int lastOptrPosFlag23 = 0; int lastOptrPosPrecede23 = 0; int lastOptrPosFlag24 = 0; int lastOptrPosPrecede24 = 0; int lastOptrPosFlag25 = 0; int lastOptrPosPrecede25 = 0; int lastOptrPosFlag26 = 0; int lastOptrPosPrecede26 = 0; int lastOptrPosFlag27 = 0; int lastOptrPosPrecede27 = 0; int lastOptrPosFlag28 = 0; int lastOptrPosPrecede28 = 0; int lastOptrPosFlag29 = 0; int lastOptrPosPrecede29 = 0; int lastOptrPosFlag30 = 0; int lastOptrPosPrecede30 = 0; int lastOptrPosFlag31 = 0; int lastOptrPosPrecede31 = 0; int lastOptrPosFlag32 = 0; int lastOptrPosPrecede32 = 0; int lastOptrPosFlag33 = 0; int lastOptrPosPrecede33 = 0; int lastOptrPosFlag34 = 0; int lastOptrPosPrecede34 = 0; int lastOptrPosFlag35 = 0; int lastOptrPosPrecede35 = 0; int lastOptrPosFlag36 = 0; int lastOptrPosPrecede36 = 0; int lastOptrPosFlag37 = 0; int lastOptrPosPrecede37 = 0; int lastOptrPosFlag38 = 0; int lastOptrPosPrecede38 = 0; int lastOptrPosFlag39 = 0; int lastOptrPosPrecede39 = 0; int lastOptrPosFlag40 = 0; int lastOptrPosPrecede40 = 0; int lastOptrPosFlag41 = 0; int lastOptrPosPrecede41 = 0; int lastOptrPosFlag42 = 0; int lastOptrPosPrecede42 = 0; int lastOptrPosFlag43 = 0; int lastOptrPosPrecede43 = 0; int lastOptrPosFlag44 = 0; int lastOptrPosPrecede44 = 0; int lastOptrPosFlag45 = 0; int lastOptrPosPrecede45 = 0; int lastOptrPosFlag46 = 0; int lastOptrPosPrecede46 = 0; int lastOptrPosFlag47 = 0; int lastOptrPosPrecede47 = 0; int lastOptrPosFlag48 = 0; int lastOptrPosPrecede48 = 0; int lastOptrPosFlag49 = 0; int lastOptrPosPrecede49 = 0; int lastOptrPosFlag50 = 0; int lastOptrPosPrecede50 = 0; int lastOptrPosFlag51 = 0; int lastOptrPosPrecede51 = 0; int lastOptrPosFlag52 = 0; int lastOptrPosPrecede52 = 0; int lastOptrPosFlag53 = 0; int lastOptrPosPrecede53 = 0; int lastOptrPosFlag54 = 0; int lastOptrPosPrecede54 = 0; int lastOptrPosFlag55 = 0; int lastOptrPosPrecede55 = 0; int lastOptrPosFlag56 = 0; int lastOptrPosPrecede56 = 0; int lastOptrPosFlag57 = 0; int lastOptrPosPrecede57 = 0; int lastOptrPosFlag58 = 0; int lastOptrPosPrecede58 = 0; int lastOptrPosFlag59 = 0; int lastOptrPosPrecede59 = 0; int lastOptrPosFlag60 = 0; int lastOptrPosPrecede60 = 0; int lastOptrPosFlag61 = 0; int lastOptrPosPrecede61 = 0; int lastOptrPosFlag62 = 0; int lastOptrPosPrecede62 = 0; int lastOptrPosFlag63 = 0; int lastOptrPosPrecede63 = 0; int lastOptrPosFlag64 = 0; int lastOptrPosPrecede64 = 0; int lastOptrPosFlag65 = 0; int lastOptrPosPrecede65 = 0; int lastOptrPosFlag66 = 0; int lastOptrPosPrecede66 = 0; int lastOptrPosFlag67 = 0; int lastOptrPosPrecede67 = 0; int lastOptrPosFlag68 = 0; int lastOptrPosPrecede68 = 0; int lastOptrPosFlag69 = 0; int lastOptrPosPrecede69 = 0; int lastOptrPosFlag70 = 0; int lastOptrPosPrecede70 = 0; int lastOptrPosFlag71 = 0; int lastOptrPosPrecede71 = 0; int lastOptr

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++程序员Carea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值