逆波兰表达式
所谓逆波兰表达式是指先操作数后操作符的后缀表达式,比如中缀表达式3X4的逆波兰为3 4 X,这是简单的逆波兰表达式,稍微复杂一点的比如3X(5+4)-6的逆波兰表达式为3 5 4 + X 6 -,任何算术表达式都可以转换为逆波兰表达式,在这里为了方便就用简单的表达式来举例了。我们可以用程序来完成中缀表达式到逆波兰表达式的转换。
中缀到逆波兰表达式的转换
给出如下程序来完成转换:
int Icp(char ch)
{
if (ch == '(')
return 4;
else if (ch == '*' || ch == '/' || ch == '%')
return 3;
else if (ch == '+' || ch == '-')
return 2;
else
return 1;
}
bool Judge(char ch)
{
if ((ch >= '0'&&ch <= '9') || ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == '%' || ch == '(' || ch == ')')
return true;
return false;
}
void ChangeNibolan(const char *crt)
{
assert(crt != NULL);
int len = strlen(crt);
Stack<char> stack_ch;
for (int i = 0; i < len; i++)
{
if (Judge(crt[i]))
{
if (crt[i] >= '0' && crt[i] <= '9')
cout << crt[i] << " ";
else
{
if (stack_ch.Empty() || (Icp(stack_ch.Top()) < Icp(crt[i])) ||
((Icp(stack_ch.Top()) > Icp(crt[i]))&&(stack_ch.Top() == '(')))
stack_ch.Push(crt[i]);
else if (Icp(stack_ch.Top()) >= Icp(crt[i]) && crt[i] != ')')
{
while ( (!stack_ch.Empty()) && ((Icp(stack_ch.Top() >= Icp(crt[i]))) && stack_ch.Top() != '(' ))
{
cout << stack_ch.Top() << " ";
stack_ch.Pop();
}
stack_ch.Push(crt[i]);
}
else if (crt[i] == ')')
{
cout << stack_ch.Top() << " ";
stack_ch.Pop();
stack_ch.Pop();
}
}
}
else
return;
}
while (!stack_ch.Empty())
{
cout << stack_ch.Top() << " ";
stack_ch.Pop();
}
cout << endl;
}
代码中Icp函数用于判断运算符的优先级,Judge函数用于判断字符是否是运算符或者括号,最后一个函数则是程序的主题。我们用一个简单的表达式来测试一下:
void test3()
{
char array[] = "3*(4*(5+6*2-7)-8)+9-8/2"; //逆波兰表达式为:3 4 5 6 2 * + 7 - * 8 - * 9 + 8 2 / -
ChangeNibolan(array);
}
看看结果:
显然成功转换。
表达式求值
用程序来进行表达式求值有多种方法其中用栈进行求值常用有两种,一种用两个栈,分别存储运算数和运算符,这种比较简单,在此不作实现。另一种用一个栈,结合逆波兰表达式进行求值,这种方法原理也简单,但是要用到逆波兰表达式,因此这里就用这种方法来实现。
先给出如下结构:
enum OPERATOR
{
DEFAULT,
ADD,
SUB,
MUL,
DIV
};
struct Cell
{
int data;
OPERATOR OP;
};
枚举结构中给出四则运算和一个默认值,结构体中存储运算数或者运算符,再给出这样一个数组:
//"5*(3+4)-6+8/2"
Cell PRN[] = { {5,DEFAULT},{3,DEFAULT},{4,DEFAULT},{0,ADD}
,{0,MUL},{6,DEFAULT},{0,SUB},{8,DEFAULT},{2,DEFAULT},{0,DIV},{0,ADD} };
这个数组就是我们要进行运算的表达式,这样看起来比较麻烦,但其实我们用上面实现的逆波兰表达式转换程序可以很容易就将一个中缀表达式转换为这样的一个逆波兰表达式数组,下面给出运算程序:
int CalcRPN(Cell* RPN, int size)
{
assert(RPN != NULL);
Stack<int> stack_cell;
for (int i = 0; i < size; i++)
{
if (RPN[i].OP == DEFAULT)
{
stack_cell.Push(RPN[i].data);
}
else
{
assert(stack_cell.Size() > 1);
int right = stack_cell.Top();
stack_cell.Pop();
int left = stack_cell.Top();
stack_cell.Pop();
switch (RPN[i].OP)
{
case ADD:
stack_cell.Push(left + right);
break;
case SUB:
stack_cell.Push(left - right);
break;
case MUL:
stack_cell.Push(left*right);
break;
case DIV:
assert(right != 0);
stack_cell.Push(left / right);
break;
default :
break;
}
}
}
return stack_cell.Top();
}
测试代码:
void test2()
{
Cell PRN[] = { {5,DEFAULT},{3,DEFAULT},{4,DEFAULT},{0,ADD}
,{0,MUL},{6,DEFAULT},{0,SUB},{8,DEFAULT},{2,DEFAULT},{0,DIV},{0,ADD} };
int sz = sizeof(PRN) / sizeof(PRN[0]);
cout << CalcRPN(PRN, sz) << endl;
}
运行看看求值是否正确:
结果正确!
程序还可以改进,欢迎各位高手斧正!