问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。
测试样例
样例1:
输入:
expression = "1+1"输出:2
样例2:
输入:
expression = "3+4*5/(3+2)"输出:7
样例3:
输入:
expression = "4+2*5-2/1"输出:12
样例4:
输入:
expression = "(1+(4+5+2)-3)+(6+8)"输出:23
样例5:
输入:
expression = "2*(5+5*2)/3+(6+8*3)"输出:40
过程分析
我们学到了栈的存储结构,该结构可以被用来处理这个问题。 首先我们来定义一个栈的结构
typedef struct{
ElemType data[MaxSize]; int top;
}SqStack;
接着栈的使用方法。
//顺序栈的初始化:
void InitStack(SqStack &S)
{
memset(S.data,'\0',MaxSize);
S.top=-1;
}
//获取栈顶元素(不是出栈操作!!)
bool GetTop(SqStack &S,ElemType &x)
{
if(S.top==-1)return false;
x=S.data[S.top];
return true;
}
//入栈操作:
bool Push(SqStack &S,ElemType x)
{
if(S.top==(MaxSize-1))return false;
S.data[++S.top]=x;
return true;
}
//出栈操作:
bool Pop(SqStack &S,ElemType &x)
{
if(S.top==-1)return false;
x=S.data[S.top--];
return true;
}
做这道题,我们首先要明白怎么存储。 拿一个简单的10%2-3来举例 我们需要将它转变为后缀表达式 即数字正常存储 而符号则根据以下规定存储。
- 遇到界限符,遇到“(”直接入栈,遇到“)”则将之前的所有操作符弹出,知道遇到“(”
- 遇到运算符,依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若遇到“(”或栈空则停止,之后再把当前运算符入栈。 按上述步骤做完后,我们就将表达式转化为后缀表达式了。 比如A+B-CD/E+F 就变为了AB+CDE/-F+ 随后的事就交给计算机吧。
我们设定一下关于运算符间的比较大小
bool Priority(char a,char b)
{
if((a=='+'||a=='-')&&(b=='+'||b=='-'||b=='*'||b=='/'))
{
return true;
}
else if((a=='*'||a=='/')&&(b=='*'||b=='/'))
{
return true;
}
return false;
}
接着就是开始计算。 按照上述所说的计算规则,将符号或是操作数逐步压入栈中再进行逐步的计算。 最后我们便可以得出最后的表达式的答案
-
时间复杂度: O(n),其中 n 是表达式的长度
-
主要操作是遍历表达式字符串一次
-
每个字符最多被处理一次
-
栈操作(push和pop)的时间复杂度是O(1)
-
递归处理括号时,虽然有递归调用,但每个字符仍然只被处理一次
2. 空间复杂度: O(n)
-
在最坏情况下(比如表达式中有很多嵌套括号),递归调用栈的深度可能达到O(n)
-
存储中间结果的栈在最坏情况下也可能需要O(n)的空间