栈以其先进先出的特性在算法中有很多的应用,其中顺序栈一般被使用的更多(不用写next指针直接用数组就可以定义),以下为顺序栈的存储结构
#define maxsize 100
typedef struct
{
int *base;
int *top;
int stacksize;
}sqstack;
借助top指针我们可以实现对栈中元素的增删查改等基本操作。
int pop(stack &s,int &e)//出栈
{
if(s.top==s.base)
{
cout<<"pop error!"<<endl;
return 0;
}
e=*--s.top;
return 1;
}
int push(stack &s,int e)//入栈
{
if(s.top-s.base==s.stacksize)
return 0;
/*cin>>e;*/
*s.top++=e;//加*改变s.top的值
return 1;
}
int gettop(stack &s)//取栈顶元素
{
if(s.top!=s.base)
return *(s.top-1);
}
int main()
{
int n,i,j,e=1;
cin>>n;
stack p;
initstack(p);
for(i=0;i<n;i++)
{
cin>>j;
if(j!=-1)
push(p,j);
else
{
pop(p,e);
cout<<e<<endl;
}
}
return 0;
}
以上为栈的构造和几种基本操作。我们也可以借助头文件直接调用已经写好的栈。
#include<stack>
using namespace std;
stack<int>q;
s.empty()//如果栈为空返回true,否则返回false
s.size()//返回栈中元素的个数
s.pop()//删除栈顶元素但不返回其值 访问空栈栈顶会直接跳出
s.top()//返回栈顶的元素,但不删除该元素
s.push(X)//在栈顶压入新元素 ,参数X为要压入的元素
借助栈我们可以解决几种类型的题目
1.数制转换
void conversion(int n)
{
int e;
//对于一个任意的非负十进制数,打印输出与其等值的八进制数
while(n)
{
q.push(n%8);
n/=8;
}
while(!q.empty())
{
e=q.top();
q.pop();
cout<<e;
}
}
当n非0时不断将n与8求余得到的数压入栈中,同时将n更新为n与8的商。最终将栈中元素依次输出即可。
2.表达式括号匹配
详见洛谷 P1739
#include<bits/stdc++.h>
using namespace std;
stack <char> q;
int main()
{
char a;
while(1)
{
cin>>a;
if(a=='@')
break;
if(a=='(')
q.push(a);
if(a==')'&&!q.empty())
{
if(q.top()=='(')
{
q.pop();
}
else
q.push(a);
}
else if(a==')'&&q.empty())
{
q.push(a);
}
}
/*while(!q.empty())
{
cout<<q.top()<<" ";
q.pop();
}*/
if(q.empty())
cout<<"YES";
else
cout<<"NO";
return 0;
}
借助栈可以很简单的解决这类题目。
3.利用单调栈寻找数组中元素其左或者右第一个大于或小于该元素的值
首先,如果要寻找其右侧,要从右向左遍历。反之,从左向右遍历。如果是寻找第一个大于该元素的值,则要在栈顶保存较小的值。即从栈底到栈顶是递减的(栈顶到栈底就是递增的)。如果寻找第一个小于该元素的值,则要在栈顶保存较大的值。从栈底到栈顶是递增的。
对于每一个点,弹出栈顶比它小(大)的元素,此时弹出的元素就是答案,再将这个点加入栈中即可。
借助洛谷模板题P5788进行进一步说明。
题解如下
#include<bits/stdc++.h>
using namespace std;
int n,a[3000001],b[3000001];
stack<int> q;//开一个STL的栈 栈里面存的是数的下标即位置
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];//输入
for(int i=n;i>=1;i--)
{
while(!q.empty() and a[q.top()]<=a[i])//查找第一个大于a[i]的数
q.pop();//否则就直接出栈
if(q.empty())//如果最后没有比a[i]大的数
b[i]=0;
else
b[i]=q.top();//否则就记录下来
q.push(i);//将i入栈
}
for(int i=1;i<=n;i++)
cout<<b[i]<<" ";//输出答案 结束
return 0;
}
4.表达式求值
以洛谷P1981为例,该题不涉及括号,所以比较简单,题目代码如下
#include <iostream>
#include <stack>
using namespace std;
stack <int> q;
int main()
{
long long a,s=0;
char b;
long long c;
cin>>a;
a%=10000;
q.push(a);
while(cin>>b>>c)
{
c%=10000;
if(b=='*')
{
a=q.top();
//cout<<a<<endl;
a*=c;
q.pop();
a%=10000;
q.push(a);
}
else if(b=='+')
q.push(c);
else
break;
}
while(!q.empty())
{
s+=q.top();
s%=10000;
q.pop();
}
cout<<s;
return 0;
}
将读入的符号进行判断,为+号即将数字入栈, 为*号即与栈顶元素相乘即可。