前言
中缀表达式就是生活中习惯看到的表达式,知道学习数据结构的时候我才知道原来还有前缀表达式和后缀表达式。因为这些表达式看着很奇怪。但是仔细跟着过一遍也是挺简单的。
后缀表达式就是将运算符号放在数字后面,比如说中缀表达式52+3-4的后缀表达式是5 2 3 + 4 - 。(这样看起来是不是感觉到很诡异。有时候自己分不清楚是5+2还是52。)
可以看出,中缀表达式转后缀表达式就是把需要运算的两个数符号后置,比如1+2就写成1 2 +,1*2写成 1 2 * 。
那么后缀表达式是如何处理优先级顺序的呢——就近原则。1 2 3 + *=1 *(2+3)。碰到第一个运算符就把前面两个数值进行计算结果当成一个数值,所以后缀表达式是不需要括号的。
需求分析
通过简单的分析,我们可以基本了解到中缀表达式转换成后缀表达式:
- 需要一个栈来存放运算符号,符号入栈需要判断优先级;
- 将字符串形式的表达式划分,数字转换为浮点型;
- 增加中缀表达式输入错误的报错提示;
程序功能
- 将中缀表达式转换成后缀表达式
- 计算后缀表达式。
主要函数
思想:函数一遍转换一遍计算。程序难点是将字符转换为数字,比如12.5要把字符转换成数字。小数点后面也需要保留。借助一个缓存数组,将数值保存进去最后转换。
转换函数zhuanhuan
.
// 优先级( + - * /)
void zhuanhuan(char str[], STACK s) {
float a[50];
char tem[30];
int j = 0,z=0;
//计算数组长度
while (str[length] != '\0') length++;
for (int i = 0; i <= length&&flag!=1; i++) {
//左括号入栈
if (str[i] == 40 ) Push(str[i], s);
//乘除
else if (str[i] == '*' || str[i] == '/') {
//优先级低入栈
if (Top(s) == '(' || Top(s) == '+' || Top(s) == '-' || Empty(s)) Push(str[i], s);
//优先级不高于,出栈计算
else{
while (!Empty(s) && (Top(s) == '*' || Top(s) == '/')) {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
Push(str[i], s);
}
}
//加减
else if (str[i] == '+' || str[i] == '-') {
if (Top(s) == '(' || Empty(s)) Push(str[i], s);
else
{
while (!Empty(s) && Top(s) != '(') {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
Push(str[i], s);
}
}
//符号出栈
else if (str[i] == ')' || str[i] == '\0') {
while (!Empty(s)&&z>=1) {
if (Top(s) != '(') {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
else { Pop(s); break; }
}
if (Empty(s) && str[i] == '\0'&&z==1&&flag!=1) {
printf("=%f\n", a[0]);
}
}
//转换数字
else if ((str[i] <= 57 && str[i] >= 48 || str[i] == 46) && z >= 0) {
tem[j] = str[i];
tem[j + 1] = '\0';
j++;
//数字段结束
if (str[i + 1] == 42 || str[i + 1] == 43 || str[i + 1] == 45 || str[i + 1] == 47 || str[i + 1] == ')' || str[i + 1] == '\0')
{
//强制转换
a[z] = atof(tem);
printf("%f ", a[z]);
//清空数组
memset(tem, 0, sizeof(tem));
j = 0;
z++;
}
}
//输入错误
else { printf("\n输入错误!"); break; }
}
}
源代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int length = 0;
int flag = 0;
typedef char elmenttype;
struct node{
elmenttype data;
node *next;
};
typedef node* STACK;
void jisuan(STACK s, float a[], int &z);
STACK MakeNull() {//创建空栈
STACK S;
S = new node;
S->data = '#';
S->next = NULL;
return S;
}
void Push(elmenttype x,STACK S) {//插入元素x到栈顶
STACK stk;
stk = new node;
stk->data = x;
stk->next = S->next;
S->next = stk;
}
void Pop(STACK S) {//删除栈顶元素
STACK stk;
if (S->next) {
stk = S->next;
S->next = stk->next;
delete stk;
}
}
elmenttype Top(STACK S) {//返回栈顶元素,不删
if (S->next)
return (S->next->data);
else
return NULL;
}
bool Empty(STACK S) {//栈空
if (S->next) return false;
else return true;
}
void zhuanhuan(char str[], STACK s) {
float a[50];
char tem[30];
int j = 0,z=0;
//数组长度
while (str[length] != '\0') length++;
for (int i = 0; i <= length&&flag!=1; i++) {
//符号入栈
if (str[i] == 40 ) Push(str[i], s);
//乘除
else if (str[i] == '*' || str[i] == '/') {
//优先级高
if (Top(s) == '(' || Top(s) == '+' || Top(s) == '-' || Empty(s)) Push(str[i], s);
//优先级不高于,出栈计算
else{
while (!Empty(s) && (Top(s) == '*' || Top(s) == '/')) {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
Push(str[i], s);
}
}
//加减
else if (str[i] == '+' || str[i] == '-') {
if (Top(s) == '(' || Empty(s)) Push(str[i], s);
else
{
while (!Empty(s) && Top(s) != '(') {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
Push(str[i], s);
}
}
//符号出栈
else if (str[i] == ')' || str[i] == '\0') {
while (!Empty(s)&&z>=1) {
if (Top(s) != '(') {
printf("%c ", Top(s));
jisuan(s, a, z);
Pop(s);
}
else { Pop(s); break; }
}
if (Empty(s) && str[i] == '\0'&&z==1&&flag!=1) {
printf("=%f\n", a[0]);
}
}
//转换数字
else if ((str[i] <= 57 && str[i] >= 48 || str[i] == 46) && z >= 0) {
tem[j] = str[i];
tem[j + 1] = '\0';
j++;
//数字段结束
if (str[i + 1] == 42 || str[i + 1] == 43 || str[i + 1] == 45 || str[i + 1] == 47 || str[i + 1] == ')' || str[i + 1] == '\0')
{
//强制转换
a[z] = atof(tem);
printf("%f ", a[z]);
//清空数组
memset(tem, 0, sizeof(tem));
j = 0;
z++;
}
}
//输入错误
else { printf("\n输入错误!"); break; }
}
}
void jisuan(STACK s,float a[],int &z){
if (z >= 2) {
switch (Top(s))
{
case'+': {a[z - 2] = a[z - 1] + a[z - 2]; a[z - 1] = 0; z--; break; }
case'-': {a[z - 2] = a[z - 2] - a[z - 1]; a[z - 1] = 0; z--; break; }
case'/': {a[z - 2] = a[z - 2] / a[z - 1]; a[z - 1] = 0; z--; break; }
case'*': {a[z - 2] = a[z - 1] * a[z - 2]; a[z - 1] = 0; z--; break; }
default: break;
}
}
else
{
printf("\n输入表达式有误!\n");
flag = 1;
}
}
void main()
{
STACK A;//符号栈
A=MakeNull();
char str[100];
printf("请输入中缀表达式:\n");
scanf("%s", str);
zhuanhuan(str,A);
system("pause");
}
结语
当时参考了很多CSDN的大佬的文章,数据结构老师说每个步骤都要自己实现,比如栈和栈的操作,输入的字符等。我也不知道是写转载还是原创了,知识还是需要输出的,不输出就相当于一滩死水了。