C语言 逆波兰算法实现计算器
一、逆波兰表达式介绍
概念:
1.前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。如 - × + 3 4 5 6
2.中缀表达式就是常见的运算表达式,如 (3+4)×5-6
3.后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后。如 3 4 + 5 × 6 -
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。
二、逆波兰表达式的转换和计算
1.运算表达式转换为逆波兰表达式
1、构造一个运算符栈和逆波兰表达式队列
2、读入运算表达式,从左至右依次扫描字符,如果是数字则写入队列,如果是运算符则需要与栈顶运算符进行比较
3、运算符比较规则:
(1)如果运算符栈内为空或者检测到栈顶运算符为 ‘(’ ,则扫描的运算符无条件入栈
(2)如果扫描的运算符优先级比栈顶运算符优先级高,则扫描运算符入栈;反之输出栈顶运算符至表达式队列,再次执行对比操作,直至扫描运算符优先级比栈顶运算符优先级高或者满足第一条规则
(3)如果扫描到运算符为 ‘)’ ,抛弃 ‘)’ 并从栈顶依次输入运算符至队列,直到遇见 ‘(’ ,抛弃 ‘(’ 。
4、最后将栈内剩余运算符输入到队列。
5、逆波兰表达式转换完成。
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a=1,3 +
例图
2.逆波兰表达式的计算
1、构造一个操作数栈
2、从逆波兰表达式队列中依次读入字符,如果是操作数,则输入到操作数栈。如果是运算符,则对栈顶操作数和次栈顶操作数进行相应的运算并且清除,最后将运算结果入栈。
3、队列扫描并计算结束后,操作数栈内最终数据即运算结果。
三、逆波兰算法的C语言实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
union counter//定义new_res共同体存储波兰表达式
{
char ch;
float num;
}new_res[100] = {0};
char res[1000] = {0};//输入的中缀表达式
int flag[100] = {0};//与new_res一一对应的判断数组元素类型的flag数组
int n = 0;//flag下标
int i = 1;//循环判断标志
int element();//将中缀表达式转换为后缀表达式存储与new_res中
int count(union counter new_res[100], int flag[100]);//将波兰表达式计算并输出结果
int main()
{
while(i)
{
element();
count(new_res, flag);
printf("您还要继续嘛?继续请输入1,退出请输入0:");
scanf("%d",&i);
}
return 0;
}
int element()
{
char stack_op[50] = {0};//运算符栈
char temp[100] = {0};
int j = 0;
int m = 0;//运算符栈下标
n = 0;//循环后重置flag下标
printf("计算:");
scanf("%s", res);
for (int i = 0; i < strlen(res)+1; i++)//strlen(res)+1确保最后一位数据被写入
{
if (isdigit(res[i]) || res[i] == '.')
{
temp[j++] = res[i];
}
else if (!isdigit(res[i]) && (strcmp(temp,"")!=0))//将temp中存储的数据转换为float类型写给new_res
{
temp[j] = '\0';
new_res[n].num = atof(temp);
flag[n] = 0;
n++;
memset(temp,'\0',sizeof(temp));
j = 0;
}
switch (res[i])//判断运算符的优先级决定出栈入栈
{
case '(':
stack_op[m++] = res[i];
break;
case '+':
case '-':
if (m == 0 || stack_op[m-1] == '(')
{
stack_op[m++] = res[i];
}
else
{
m--;
new_res[n].ch = stack_op[m];
flag[n] = 1;
n++;
i--;
}
break;
case '*':
case '/':
if (m == 0 || stack_op[m-1] !='*' || stack_op[m-1] != '/')
{
stack_op[m++] = res[i];
}
else
{
m--;
new_res[n].ch = stack_op[m];
flag[n] = 1;
n++;
i--;
}
break;
case ')':
m--;
while(stack_op[m] != '(')
{
new_res[n].ch = stack_op[m];
flag[n] = 1;
n++;
m--;
}
stack_op[m] == 0;
break;
default:
break;
}
}
for (int k = m-1; k >= 0; k--)//将栈中剩余的运算符全部写入new_res
{
new_res[n].ch = stack_op[k];
flag[n] = 1;
n++;
}
return 0;
}
int count(union counter new_res[100], int flag[100])
{
int x = 0;//数据栈下标
float stack_num[100] = {0};//数据栈
for (int i = 0; i < n; i++)
{
switch (flag[i])//判断new_res中的数据类型
{
case 0://将数据写入到栈中
stack_num[x++] = new_res[i].num;
break;
case 1://运算
switch (new_res[i].ch)
{
case '+':
x --;
stack_num[x-1] += stack_num[x];
break;
case '-':
x --;
stack_num[x-1] -= stack_num[x];
break;
case '*':
x --;
stack_num[x-1] *= stack_num[x];
break;
case '/':
x --;
if (stack_num[x] != 0)
{
stack_num[x-1] /= stack_num[x];
}
else
{
printf("除零错误\n");
exit(0);
}
break;
default:
break;
}
default:
break;
}
}
printf("结果:%f\n", stack_num[0]);
return 0;
}
运行结果:
计算:3*8+2/4-(6+2/1)
结果:16.500000
您还要继续嘛?继续请输入1,退出请输入0:1
计算:9*9-(11-2)+(4/2+6)
结果:80.000000
您还要继续嘛?继续请输入1,退出请输入0:1
计算:3*3/6
结果:1.500000