您的位置:首页 > 理论基础 > 数据结构算法

数据结构之栈(中缀转后缀计算四则运算)

2018-01-26 12:02 465 查看
前面转载了一篇有关栈的基础讲解的文章,所以这篇文章就不再说有关栈的概念性内容了。
这篇文章主要的内容,就是用学到的栈的基础操作,来实现一个输入中缀四则运算表达式(+ - * /),转换成后缀表达式,然后计算结果并输出的小程序。表达式中可以有括号,操作数可以是多位整数(不支持小数,不过要修改也很容易)。

中缀转后缀方法:

1.遇到操作数,直接输出;
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
经过上面的步骤,得到的输出既是转换得到的后缀表达式。
举例:a+b*c+(d*e+f)g ———> abc+de*f+g*+

具体步骤:

1.首先自定义一个栈结构

(这里用的是之前第一次写的时候,在网上找的代码,希望作者莫见怪)
const int maxlen = 100;//栈的最大存储量
template <typename T>
class stack
{
public:
stack(); //构造函数,用于初始化(C++11新特性可以在类的声明中初始化变量)
bool empty(); //判断栈是否为空
bool full(); //判断栈是否为满
T gettop(); //取栈顶元素
bool push(T x); //元素入栈
T pop(); // 弹出栈顶
private:
int count; //元素的计数器
T data[maxlen]; //顺序存储结构
};

template <typename T>
stack<T>::stack()
{
count = 0;
};

template <typename T>
bool stack<T>::empty()
{
if (count == 0)
return true;
return false;
};

template <typename T>
bool stack<T>::full()
{
if (count == maxlen)
return true;
return false;
};

template <typename T>
T stack<T>::gettop()
{
T x;
x = data[count - 1];
return x;

};

template <typename T>
bool stack<T>::push(T x)
{
if (!full())
{
data[count++] = x;
return true;
}
return false;
};

template <typename T>
T stack<T>::pop()
{
T x;
count--;
x = data[count];
return x;
};要自定义栈结构的话,最好也是用C++的模板,因为最少会用到两个类型的栈。

2.然后是定义一个计算用的类

(类中封装了要使用的栈,以及进行相应的操作函数)
class calculator
{
private:
stack<char> scMidToPost; //用于中缀转后缀
stack<float> sfCalculate; //用于计算后缀表达式
public:
string strInput; //输入的中缀表达式
string strPost; //得到的后缀表达式
void Input(string strTemp); //得到输入的中缀表达式
void Change(); //中缀转后缀
float Calculate(); //计算
};

3.输入并实现中缀转后缀

void calculator::Input(string strTemp)
{
strInput = strTemp; //输入
}

void calculator::Change()
{
int length = strInput.length(); //表达式长度
char cJudge;
for (int i = 0; i < length; i++)
{
char cTemp; //临时变量
cJudge = strInput[i]; //当前字符
switch (cJudge)
{
case '(':
scMidToPost.push(cJudge);
break;
case ')':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop(); //相当于查看栈顶
if (cTemp != '(') //把直到左括号位置的全部弹出
strPost = strPost + cTemp;
else
break;
}
break;
case '+':
case '-':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '(') //只有左括号的优先级小于+、-
{
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp; //其他全是优先级大于等于,全部弹出
}
}
scMidToPost.push(cJudge);
break;
case '*':
case '/':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '+' || cTemp == '-' || cTemp == '(')
{ //*、/除了它们自己,其他的优先级全部小于它们
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp;
}
}
scMidToPost.push(cJudge);
break;
default:
if (cJudge >= '0'&& cJudge <= '9') //如果是操作数,就在两端加上‘#’
{
strPost = strPost + '#';
while (strInput[i] >= '0'&&strInput[i] <= '9')
{
strPost = strPost + strInput[i];
i++;
}
i--; //要回退一位
strPost = strPost + '#';
}
break;
}
}
while (!scMidToPost.empty())
{
strPost = strPost + scMidToPost.pop();
}
cout << strPost << endl; //输出后缀表达式
}

4.计算后缀表达式得到结果

float calculator::Calculate()
{
char cJudge;
int length = strPost.length();
float fResult; //保存结果
float fTemp; //临时变量
for (int i = 0; i < length; i++)
{
cJudge = strPost[i];
if (cJudge == '+' || cJudge == '-' || cJudge == '*' || cJudge == '/')
{ //如果是操作符,那么就进行相应计算
float right = sfCalculate.pop(); //右操作数,后进先出
float left = sfCalculate.pop(); //左操作数,先进后出
switch (cJudge)
{
case '+':
fTemp = right + left;
sfCalculate.push(fTemp);
break;
case '-':
fTemp = left-right;
sfCalculate.push(fTemp);
break;
case '*':
fTemp = left*right;
sfCalculate.push(fTemp);
break;
case '/':
fTemp = left/right;
sfCalculate.push(fTemp);
break;
default:
break;
}
}
else if (cJudge == '#') //遇到'#'号则说明是操作数
{
i++;
fResult = 0;
while (strPost[i] != '#')
{
fTemp = strPost[i] - '0';
fResult = fResult * 10 + fTemp; //把字符形式的操作数变为浮点型
i++;
}
sfCalculate.push(fResult); //操作数入栈
}
}
fResult = sfCalculate.gettop();
return fResult;

}

总结:

栈可以说是最最基础,同时也是最最重要的数据结构了,许多底层的实现都利用了栈结构。个人认为,它的先进后出的特点,可以很方便的实现保存某些数据或者某种状态的效果,就像一个桶一样。可以说是妙用无穷.....
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐