题目:
设计一个算法,将一般算术表达式转化为逆波兰表达式,并求逆波兰表达式的值。
分析:
(1)一般算术表达(中缀表达),如#3*(4+2)/2-5#,#为表达式界定符,逆波兰 表达式(后缀表达式),如前述表达的后缀表达式为:3 4 2 + * 2 / 5 -。
(2)设中缀表达式
的运算符有+、-、*、/、#五种,运算符的优先级别从高到低为()、*、/、+、-、#;有
括号先算括号内,再算括号外的,多层括号由内向外进行。
(3)中缀表达式转换为后缀表达式需要用到一个临时栈 optr 暂存运算符。
伪代码实现
一、中缀表达式转化为后缀表达式
1.将栈 optr 初始化为#;
2.从左至右依次扫描表达式的每个字符,执行下述操作
2.1 若当前字符是 运算对象,则输出该字符,处理下一个字符;
2.2 若当前字符是 运算符 且优先级别比栈 optr 的栈顶运算符的优先级高,
则将该字符入栈 optr,处理下一个字符;
2.3 若当前字符是 运算符 且优先级别比栈 optr 的栈顶运算符优先级别低,
则将栈 optr 的栈顶元素弹出并输出,将当前字符入栈optr,处理下一个字符;
2.4 若当前字符是 运算符 且优先级别与栈optr的栈顶运算符的优先级相等,
则将栈 optr 的栈顶元素弹出,将当前字符入栈optr,处理下一个字符。
二、表达式的计算
1.初始化栈 opnd 为空;
2.从左到右依次扫描后缀表达式(逆波兰表达式)的每一个字符,执行下述操作;
2.1 若当前是运算对象,则入栈 opnd,处理下一个字符;
2.2 若当前字符是运算符,则从栈 opnd 出栈两个运算对象,执行运算并
将结果入栈 opnd,处理下一个字符;
3.输出栈 opnd 的栈顶元素,即表达式的运算结果。
代码实现
一、中缀表达式转化为后缀表达式
//将中缀表达式转化为后缀表达式(逆波兰式)
void NifixPost(char *nifix, char *postfix){
int i = 0, j = 0;
Sqstack *optr;
optr = InitStack();
Push(optr, '#');
while (nifix[i] != '#') {
if(nifix[i] == '(')
{
Push(optr, '(');
}
else if (nifix[i] == ')')
{
while (GetTop(optr) != '('){
postfix[j++] = Pop(optr);
}
Pop(optr);
}
else if ((nifix[i] >= '0' && nifix[i] <='9') || nifix[i] == '.'){
while ((nifix[i] >= '0' && nifix[i] <='9') || nifix[i] == '.') {
postfix[j++] = nifix[i++];
}
postfix[j++] = ' ';
i--;
}
else {
char s1, optrtop;
s1 = nifix[i];
optrtop = GetTop(optr);
if (CtoRank(s1) <= CtoRank(optrtop)) {
postfix[j++] = Pop(optr);
i--;
}
else {
Push(optr, s1);
}
}
i++;
}
while (IsEmpty(optr) != -1){
postfix[j++] = Pop(optr);
}
postfix[j] = '\0';
printf("\n");
}
二、表达式计算
// 将字符串转化为浮点数
double Myatof(char *str){
double m=0,n=0,x=1;
int flag=1;
while(*str!='\0')
{
if(*str<'0'|| *str >'9' )
{
if(*str =='.') //判断小数点前后
{
flag=0;
str++;
continue;
}
return 0;
}
if(flag==1) //小数点前整数部分
{ m*=10;
m+=*str-'0';
}
else //小数部分
{
x*=0.1;
n+=x*(*str-'0');
}
str++;
}
return m+n;
}
//计算两个浮点数
double ComputeTwoNum (double a,double b,char c) {
double temp ;
switch(c)
{
case '+':
temp = a + b;
break;
case '-':
temp = a-b;
break;
case '*':
temp = a * b;
break;
case '/':
temp = a / b;
break;
case '^':
{
int i = 0;
temp = 1;
while (fabs(i-b) > 1e-6) {
temp *= a;
i++;
}
}
}
return temp;
}
//遍历后缀表达式,计算
double ComputeExpresion (char *postfix) {
int i = 0,j;
char currentExp[STACK_SIZE];
printf("\n");
while (postfix[i] != '#')
{
if(postfix[i] >= '0' && postfix[i] <= '9' || postfix[i] == '.')
{
j = 0;
while (postfix[i] >= '0' && postfix[i] <= '9' || postfix[i] == '.')
{
currentExp[j++] = postfix[i++];
}
currentExp[j] = '\0';
OPTD[++TopTd] = Myatof(currentExp);
} else if (postfix[i] == ' ') {
i++;
}
else // 当前字符是运算符
{
double a, b;
// b = Pop(optd);
// a = Pop(optd);
b = OPTD[TopTd--]; //这里使用的是一个全局定义的 double型数组和全局定义的int型TopTd作为指针,肯定是不好的的,现在不想改了
a = OPTD[TopTd];
OPTD[TopTd] = ComputeTwoNum(a, b, postfix[i]);
i++;
}
}
return OPTD[TopTd];
}