栈实现四则运算-思想(10以下正整数)
- 实现四则运算求值,就是要求计算机像人一样按运算符优先级进行数值计算,如何实现这一过程,栈给我们提供了思路,及只需要将计算表达式转换为两个栈:一个是数值的栈,一个是运算符的栈,然后按照栈操作完成每一步计算。
一、栈结构特点
- 栈的最主要特点是后进先出。
- 栈是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。栈的所有插入和删除操作均在栈顶进行,而栈底不允许插入和删除。
- 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
图1 入栈过程
图2 出栈过程
二、实现四则运算基本思想
1.前中后缀表达式的转换(二叉树的应用)
-
自然表达式转换为前/中/后缀表达式,其实是很简单的。首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/中/后缀遍历,即得到前/中/后缀表达式。举例说明 将自然表达式转换成二叉树:a×(b+c)−d。
– a. 根据表达式的优先级顺序,首先计算(b+c),形成二叉树。
– b. 然后是a×(b+c),在写时注意左右的位置关系。
– c. 最后在右边加上 −d。
图3 表达式转换为二叉树 -
然后最这个构造好的二叉树进行遍历,三种遍历如下:
① 前序遍历:根-左-右
② 中序遍历:左-根-右
③ 后序遍历:左-右-根
2.中缀表达式转后缀表达式(栈的应用)
- 中缀表达式9+(3−1)∗3+9/2转化为后缀表达式为931−3∗+92/+.
- 规则:从左到右遍历中缀表达式的每一数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈 顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
a.初始化一空栈,用来对符号进出栈使用。
b.第一个字符是数字9,输出9,后面是符号“+”,进栈。
c.第三个字符是“(”,依然是符号,因其只是左括号,还没有配对,故进栈。
d.第四个字符是数字3,输出,总表达式为9 3,接着是“-”,进栈。
e.接下来是数字1,输出,总表达式为9 3 1,后面是符号“)”,此时,我们需要去匹配此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”,因此输出“-”。总的表达式为9 3 1 -。
f.接着是数字3,输出,总的表达式为9 3 1 - 3.紧接着是符号“*”,因为此时的栈顶符号为“+”号,优先级低于“*”,因此不输出,“*”进栈。
g.之后是符号“+”,此时当前栈顶元素“*”比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”更低的优先级,所以全部出栈),总输出表达式为9 3 1 - 3 * +。然后将当前这个符号“+”进栈。
h.紧接着数字9,输出,总表达式为9 3 1 - 3 * + 9。后是符号“/”,所以“/”进栈。
i.最后一个数字2,输出,总的表达式为9 3 1 - 3 * + 9 2。
j.因已经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为9 3 1 - 3 * + 9 2 / +。
3.后缀表达式计算结果(栈的应用)
- 后缀表达式为:931−3∗+92/+
- 规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
a.初始化一个空栈。此栈用来对要运算的数字进行进出使用。
b.后缀表达式中前三个是、都是数字,所以9 3 1 进栈。
c.接下来是“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再讲2进栈。
d.接着是数字3进栈。
e.后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。
f.下面是“+”,所以栈中6和9出栈,9和6相加,得到15,将15进栈。
g.接着是9和2两数字进栈。
h.接下来是符号“/”,因此,栈顶的2与9出栈,9与2相除,得到4,将4进栈。
i.最后一个是符号“+”,所以15与4出栈并相加,得到19,将19进栈。
j.结果是19出栈,栈变为空。
4.代码(C++)
#include <stack>
#include <iostream>
#include <string>
/*
*比较两个操作符的优先级,op1比op2高返回1,一样返回0,低返回-1
*/
int compareOperatorPriority(char op1,char op2){
switch(op1){
case '+': case '-':
return (op2 == '*' || op2 == '/'? -1:0);
break;
case '*': case '/':
return (op2 == '-' || op2 == '+'? 1:0);
}
return -1;
}
/*
*判断是否为数字
*/
bool isDigit(char c){
int a = c - '0';
if(a >= 0 && a <= 9){
return true;
}else{
return false;
}
}
/*
*判断是否为操作符
*/
bool isOperator(char c){
if( c == '+' || c == '-' || c == '*' || c == '/'){
return true;
}else{
return false;
}
}
/*
*得到后缀表达式
*/
string getSuffixExpression(string str)
{
stack<char> numbersAndOperators;
stack<char> operators;
//开始遍历字符串
for(int i = 0;i<str.length();i++)
{
if(isDigit(str[i]))
{
numbersAndOperators.push(str[i]); //如果是数字,则直接进入栈numbersAndOperators
}
else if(isOperator(str[i]))
{
//如果是操作符
if(operators.empty() || operators.top() == '(')
{
//若栈空或栈顶为(
operators.push(str[i]);
}
else if(compareOperatorPriority(str[i], operators.top())>0)
{
//若操作符比栈顶操作符优先级高
operators.push(str[i]);
}
else
{
while(true)
{
numbersAndOperators.push(operators.top());
operators.pop();
if(operators.empty() || operators.top() == '(')
{
operators.push(str[i]);
break;
}
else if(compareOperatorPriority(str[i],operators.top())>0)
{
operators.push(str[i]);
break;
}
}
}
}
else if(str[i] == '(')
{
operators.push(str[i]);
}
else if(str[i] == ')')
{
while(operators.top() != '(')
{
numbersAndOperators.push(operators.top());
operators.pop();
}
operators.pop();//丢掉'('
}
else
{
cout<< "Bad Expression!" << endl;
exit(-1);
}
}
while(!operators.empty())
{
numbersAndOperators.push(operators.top());
operators.pop();
}
string suffix = string(numbersAndOperators.size(),'a');
int i = 0;
while(!numbersAndOperators.empty()){
suffix[i] = numbersAndOperators.top();
numbersAndOperators.pop();
i++;
}
reverse(begin(suffix), end(suffix));
return suffix;
}
/*
*根据后缀表达式计算
*/
int calculate(string str){
stack<int> numbers;
for(int i = 0;i < str.length();i++){
if(isDigit(str[i])){
numbers.push(str[i]-'0');
}
else if(isOperator(str[i]))
{
//遇到操作符,取出栈顶2个数字,并计算,计算结果压入栈
int a = numbers.top();
numbers.pop();
int b = numbers.top();
numbers.pop();
int tempResult;
if(str[i] == '+'){
tempResult = b + a;
}else if(str[i] == '-'){
tempResult = b - a; //这里注意被减数和减数的顺序,不要弄反
}else if(str[i] == '*'){
tempResult = b * a;
}else if(str[i] == '/'){
tempResult = b / a;
}
numbers.push(tempResult);
}
}
return numbers.top();
}
int main(int argc, char const *argv[])
{
/* code */
string input ;
cout<<"Please input a exoression: ";
cin>>input;
cout<<"The input is : "<<input<<endl;
input = getSuffixExpression(input);
cout<<"The suffix exoression is :" << input << endl;
int result = calculate(input);
cout<<"The result is "<<result << endl;
return 0;
}
三、总结
- 本例只是简单叙述利用栈简单实现四则运算,涉及10以上整数、小数和负数的四则运算,还需进一步进行优化;
- 数据结构对于程序员来说,是很重要的学习内容,在今后的的学习工作中,要保持不断学习和提高。