首先,栈是什么?不就是削减了功能的容器,相比vector,栈只能对栈顶元素增删查,那么不就是一个弱化版的vector吗,很多原有的功能都不能用了,我刚开始就觉得,还不如直接用vector或list呢!
但,功能的简化反而使我们的思考聚焦于要解决问题的核心,听起来没什么道理,不是功能多才利于解决问题吗?功能多让我在解决问题时有更大的操作空间,相反不久自缚手脚了吗?
注意上面这句话重点在聚焦于解决问题的核心,还是于vector比较,如果频繁地插入和删除数据,这就让分散我们的精力去思考元素的位置或下标,更多时候是让麻烦加大到无法解决。
总结一下,stack抛弃了繁乱的功能,让我们不必操心定位元素的下标。下面,我们具体来看栈解决问题的算法,同时我也会不断地积累,学习这些精妙算法的闪光点。
一、四则运算
例如:3+2*(6-4)+8/2+2
首先将它转换成后缀表达式:3 2 6 4 - * +8 2 / + 2 +,然后计算得13
1.假设已经转换了,我们来看后缀表达式是怎么计算得到13的
将后缀表达式中的元素依此入栈,如果是数字就入栈,如果是符号就将栈顶的两个元素出栈,然后根据相应符号计算,将得到的结果入栈,不断进行,直到遍历完后缀表达式,最后栈顶元素就是计算结果。
如果,我们将stack换成vector,那么我们的精力会分散到定位元素位置。
inline void PopNumbers(stack &s, int &number1, int &number2)
{
number1 = s.top();
s.pop();
number2 = s.top();
s.pop();
}
void Calulation(queue &q)
{
stack s;
int number1 = 0;
int number2 = 0;
while(!q.empty())
{
if(q.front()>='0' && q.front()<='9')
{
s.push(int(q.front()-'0'));
}
else if(q.front()=='+')
{
PopNumbers(s, number1, number2);
s.push(number2+number1);
}
else if(q.front()=='-')
{
PopNumbers(s, number1, number2);
s.push(number2-number1);
}else if(q.front()=='*')
{
PopNumbers(s, number1, number2);
s.push(number2*number1);
}else
{
PopNumbers(s, number1, number2);
s.push(number2/number1);
}
q.pop();
}
cout<<s.top()<<endl;
}
2.中缀转后缀
将中缀的元素依此入栈,遇见数字就放到输出,即成为后缀的一部分,遇到符号,如果它的优先级大于栈顶的符号就直径入栈,反之先将栈顶的出栈,然后它再入栈。
如果,这个换成vector,就无法解决,因为我们无法定位到栈元素位置。
void InTransPost(char *p)
{
stack s;
queue q;
while(*p != '\0')
{
if(isdigit(*p))
{
q.push(*p);
}
else if(*p == '(')
{
s.push(*p);
}
else if(*p == ')')
{
while(s.top()!='(')
{
q.push(s.top());
s.pop();
}
s.pop();
}
else if(*p == '+' || *p == '-')
{
while((!s.empty()) && s.top()!='(')
{
q.push(s.top());
s.pop();
}
s.push(*p);
}
else
{
if(s.top()=='*' || s.top()=='/')
{
q.push(s.top());
s.pop();
}
s.push(*p);
}
p++;
}
while(!s.empty())
{
q.push(s.top());
s.pop();
}
}