中缀表达式转后缀表达式
中缀表达式转后缀表达式的方法是利用堆栈进行操作。
举个例子说明:2*3 + (4 * ( 5 - 2 ) ) /6 - 7
一般地,我们找到优先级最高的开始计算,在这个运算里,“()”是最高的优先级,换一个角度说,括号里的可以看成是一个独立的表达式,那么从左到右扫描的过程中若遇到括号我们把它当成是一个独立的表达式来计算,可以使用递归,这样就可以解决多个括号的问题。
另一个要点是:按照怎样的规则不断进行入栈和出栈操作就能得到后缀表达式?一般规则是这样的,我们把优先级较低的放在表达式的后面,把优先级高的放在表达式的前面,这好像是废话,但我觉得这点很重要,我认识的很多人看到这类问题就不知从何下手,胡乱地进行入栈出栈,最后还是得不到结果。下面我来说明如何编码实现这个功能以及讨论其步骤,因为是按照自已的思维顺序直接写出来的代码,所以有点长。
1. 从左到右扫描这个字符串,当遇到数字或者小数点时将其写入表达式中,若是操作符字符,则进行第2步,若是括号,则进行第3步:
2. 判断该操作符与栈顶操作符的优先级,若优先级较高或者相同则加入到操作符堆栈中,
若优先较较低则将栈内元素出栈并加入到表达式中,(这就是不断地把优先级较高的往前移动,使它那先进行计算,当然,括 号其实是优先级最高,其实也是进行同样的计算)
然后将该操作符字入栈。
3. 将左括号写入堆栈中,然后类似地执行步骤1操作,当再次遇到括号时,再次调用处理遇到括号的方法。
4. 在前3个步骤都完成后,把操作符堆栈里的操作符出栈,加入到表达式中,最终完成整个转换。
以下我的实现代码:
#include <iostream>
using namespace std;
#include <vector>
#define MAX 64
struct OperStack
{ //操作符栈
char s[MAX]; //存储操作符字符
int top; //指向栈顶元素,从下标为64开始
};
void init_stack(OperStack** stack)
{//初始化操作符栈
*stack = new OperStack;
(*stack) -> top = MAX;
}
bool push(OperStack* stack, char* val)
{//将元素入栈
if(stack -> top < 0)//若下标到达顶部则返回false
return false;
else
stack->s[--(stack->top)] = *val;//入栈
return true;
}
bool pop(OperStack* stack, char* val)
{//出栈
if(stack->top > MAX - 1)//若下标超过栈底
return false;
*val = stack->s[stack->top]; //出栈
stack->s[(stack->top)++] = '\0';//将栈的前一个元素设为结束符
return true;
}
int compare(OperStack* stack, char c)
{//与栈首元素比较,若优先级大于栈首元素,则返回1,否则返回-1
int top = stack->top;//栈顶下标
char cVal = stack->s[top];//栈顶元素
switch(c)
{
case '+':
if(cVal == '*' || cVal == '/')
return -1;
case '-':
if(cVal == '*' || cVal == '/')
return -1;
case '*':
if(cVal == '+' || cVal == '-')
return 1;
case '/':
if(cVal == '+' || cVal == '-')
return 1;
}
return 0;
}
void solve_num(char* val, vector<char>* exp)
{
exp->push_back(*val);//直接入栈
}
void solve_oper(char* s, int& i, vector<char>* exp, OperStack* stack)
{
char* temp = new char;//用于接收出栈的元素
int k = compare(stack, *(s + i));//与栈顶元素相比较,若优先级较小则为-1
if(k > -1) //优先级大
push(stack, s + i); //入栈
else
{ //优先级小
while(pop(stack, temp)) //不断出栈
exp->push_back(*temp);
push(stack, s + i); //将该操作符入栈
}
delete temp;
}
void solve_unique(char* s, int& i, vector<char>* exp, OperStack* stack)
{//遇到括号时,相当于在另一个表达式中
char* temp = new char;
while(*(s + i) != ')')
{//当没有碰到右括号
if((*(s + i) > 47 && *(s + i) < 59) || *(s + i) == '.')
exp->push_back(*(s + i));//若为数字则加入到表达式中
else if(*(s + i) == '(')
push(stack, s + i);
else if(*(s + i) == '+' || *(s + i) == '-'
|| *(s + i) == '*' || *(s + i) == '/')
{
//push(stack, s + i);//为操作符
solve_oper(s, i, exp, stack);
}
i++;
if(*(s + i) == '(')
{//若该字符为括号
solve_unique(s, i, exp, stack);//处理括号问题
i++;
}
}
while(pop(stack, temp))
{//碰到右括号时出栈并加入到表达式中
if(*temp == '(')
break;
exp->push_back(*temp);
}
delete temp;
}
void infix_postfix(char* s, int i, vector<char>* exp, OperStack* stack)
{//中缀表达式转后缀表达式
char* temp = new char;
for(; i < MAX;)
{//最多循环MAX次
if((*(s + i) > 47 && *(s + i) < 59) || *(s + i) == '.')
{//从左到右扫描每一个字符,若该字符为数字或为"."时
solve_num(s + i, exp);//处理数字
i++;
}
else if(*(s + i) == '+' || *(s + i) == '-'
|| *(s + i) == '*' || *(s + i) == '/')
{//若该字符为操作符
solve_oper(s, i, exp, stack);//处理操作符
i++;
}
else if(*(s + i) == '(')
{//若该字符为括号
solve_unique(s, i, exp, stack);//处理括号问题
i++;
}
else
{//扫描到字符串最后
while(pop(stack, temp))
{//将操作符栈中的元素全部出栈加入到表达式中然后返回
exp->push_back(*temp);
}
delete temp;
return;
}
}
}
void main()
{
char s[MAX]; //用户输入字符串
vector<char> exp; //后缀表达式
OperStack* stack; //操作符栈
init_stack(&stack);
std::cin>> s;
infix_postfix(s, 0, &exp, stack);
vector<char>::iterator it = exp.begin();
while(it != exp.end())
{ //输出结果
cout << *it;
it++;
}
system("pause");
}