栈的一个常见应用,四则运算表达式求值。
主要有两个步骤:
1,中缀转后缀
2,后缀求值
实现起来比较简单,我通过c++的容器stack实现一遍。
结果
9+(3-1)*3+10/2=20
实现
step1 中缀转后缀
从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即称为后缀表达式的一部分,若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出。并将当前符号进栈,一直到最终输出后缀表达式为止
在程序中,中缀就是传进来的 data字符串,若为数字则直接输出到后缀中即stack_data中。stack_buf用来缓存符号,优先级低于栈顶则输出到后缀中。中缀遍历完后,就将缓存符号放入后缀中。
//将中缀转换为后缀
void step_1(const char * data)
{
std::stack<double> stack_buf;
int num = 0;
while (1)
{
char buf[20] = {0};
int buf_num = 0;
IF_NUM(*data)//如果是数字
{
do
{
buf[buf_num++] = *data++;
} while (IS_NUM(*data));
double t = atof(buf);
IF_SYMBOE(t)//如果是符号
{
printf("碰撞\n");
t += 0.000001;
}
stack_data.push(t);
}
IF_SYMBOE(*data)
{
double buf;
if (stack_buf.empty())//栈为空
{
stack_buf.push(*data);
}
else if (*data==')')//为右括号
{
do
{
buf = stack_buf.top();
stack_buf.pop();
if ((int)buf == '(')
{
break;
}
else
{
stack_data.push(buf);
}
} while (1);
}
else if (*data == '(')//为左括号
{
stack_buf.push(*data);
}
else//为字母,判断优先级
{
buf = stack_buf.top();
while (get_yxj(buf) >= get_yxj(*data))
{
stack_data.push(buf);
stack_buf.pop();
if (!stack_buf.empty())
buf = stack_buf.top();
else
break;
}
stack_buf.push(*data);
}
data++;
//stack_data.push(*data++);
}
else if (*data == NULL)
{
break;
}
else
{
printf("erro\n");
exit(0);
}
}
while (!stack_buf.empty())
{
stack_data.push(stack_buf.top());
stack_buf.pop();
}
//栈倒置
std::stack<double> b;
while (!stack_data.empty())
{
b.push(stack_data.top());
stack_data.pop();
}
stack_data.swap(b);
}
step2 后缀运算
从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到符号就将处于栈顶的两个符号出栈,进行
运算,运算结果进栈,一直到最终获得结果。
后缀即是stack_data,运算的结果在栈t中,最后将结果拷贝到stack_data中。
void step_2()
{
std::stack<double> t;
while (!stack_data.empty())
{
IF_SYMBOE((int)stack_data.top())
{
double num2 = t.top();
t.pop();
double num1 = t.top();
t.pop();
switch ((int)stack_data.top())
{
case '+':
t.push(num1 + num2);
break;
case '-':
t.push(num1 - num2);
break;
case '*':
t.push(num1 * num2);
break;
case '/':
t.push(num1 / num2);
break;
default:
exit(0);
break;
}
}
else
{
t.push(stack_data.top());
}
stack_data.pop();
}
stack_data.swap(t);
}
完整代码
#include<iostream>
#include<stack>
#define STR_LEN 100
#define GET_STR(a) scanf_s("%s", s,STR_LEN);
#define IF_NUM(a) if((a>='0'&& a<='9')|| a=='.')
#define IS_NUM(a) ((a>='0'&& a<='9')|| a=='.')
#define IF_SYMBOE(a) if((a=='+' || a=='-' || a=='*' ||a=='/'||a=='(' || a==')')&&a!=NULL)
#define IS_SYMBOE(a) (a=='+' || a=='-' || a=='*' ||a=='/'||a=='(' || a==')')
std::stack<double> stack_data;
int get_yxj(const char data)
{
switch (data)
{
case '(':
return 0;
case '+':
return 1;
case '-':
return 1;
case '*':
return 2;
case '/':
return 2;
default:
return -1;
break;
}
}
//将中缀转换为后缀
void step_1(const char * data)
{
std::stack<double> stack_buf;
int num = 0;
while (1)
{
char buf[20] = {0};
int buf_num = 0;
IF_NUM(*data)
{
do
{
buf[buf_num++] = *data++;
} while (IS_NUM(*data));
double t = atof(buf);
IF_SYMBOE(t)
{
printf("碰撞\n");
t += 0.000001;
}
stack_data.push(t);
}
IF_SYMBOE(*data)
{
double buf;
if (stack_buf.empty())//栈为空
{
stack_buf.push(*data);
}
else if (*data==')')//为右括号
{
do
{
buf = stack_buf.top();
stack_buf.pop();
if ((int)buf == '(')
{
break;
}
else
{
stack_data.push(buf);
}
} while (1);
}
else if (*data == '(')//为左括号
{
stack_buf.push(*data);
}
else//为字母,判断优先级
{
buf = stack_buf.top();
while (get_yxj(buf) >= get_yxj(*data))
{
stack_data.push(buf);
stack_buf.pop();
if (!stack_buf.empty())
buf = stack_buf.top();
else
break;
}
stack_buf.push(*data);
}
data++;
}
else if (*data == NULL)
{
break;
}
else
{
printf("erro\n");
exit(0);
}
}
while (!stack_buf.empty())
{
stack_data.push(stack_buf.top());
stack_buf.pop();
}
//栈倒置
std::stack<double> b;
while (!stack_data.empty())
{
b.push(stack_data.top());
stack_data.pop();
}
stack_data.swap(b);
}
//后缀运算
void step_2()
{
std::stack<double> t;
while (!stack_data.empty())
{
IF_SYMBOE((int)stack_data.top())
{
double num2 = t.top();
t.pop();
double num1 = t.top();
t.pop();
switch ((int)stack_data.top())
{
case '+':
t.push(num1 + num2);
break;
case '-':
t.push(num1 - num2);
break;
case '*':
t.push(num1 * num2);
break;
case '/':
t.push(num1 / num2);
break;
default:
exit(0);
break;
}
}
else
{
t.push(stack_data.top());
}
stack_data.pop();
}
stack_data.swap(t);
}
void printf_step_1()
{
std::stack<double> buf = stack_data;
printf("[step1:printf]\n");
while (!buf.empty())
{
if (IS_SYMBOE(buf.top()))
{
printf(" %c\n", (int)buf.top());
}
else
printf(" %f\n", buf.top());
buf.pop();
}
}
void printf_step_2()
{
printf("[step2:printf]\n");
printf(" %f\n", stack_data.top());
}
int main()
{
char s[STR_LEN];
GET_STR(s);
step_1(s);
printf_step_1();
step_2();
printf_step_2();
system("pause");
return 0;
}