栈与队列
先用数组手搓一遍吧,直接用STL库就不用学了
栈
先进后出,水桶加料
//模板
// tt表示栈顶
int stk[N], tt = 0;
// 向栈顶插入一个数
stk[ ++ tt] = x;
// 从栈顶弹出一个数
tt -- ;
// 栈顶的值
stk[tt];
// 判断栈是否为空,如果 tt > 0,则表示不为空
if (tt > 0)
{
}
//实测练习
#include<iostream>
using namespace std;
const int N = 1e5+10;
int q[N];
int tt=0;
int main(){
int num,n;
string s;
cin>>num;
while(num--){
cin>>s;
if(s=="push") {
cin>>n;
q[++tt]=n;
}
if(s=="pop") tt--;
if(s=="empty"){
if(tt>0) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
if(s=="query") {
cout<<q[tt]<<endl;
}
}
return 0;
}
//经典题型,表达式求值,构建数值栈和操作符栈
#include<iostream>
#include <string>
#include<unordered_map>
using namespace std;
const int N = 1e5+10;
int a[N],tt1=0,tt2=0;
char b[N];
unordered_map<char, int> h{ {'+', 1}, {'-', 1}, {'*',2}, {'/', 2} };
void eval(){
int x = a[--tt1];
int y = a[--tt1];
char p = b[--tt2];
int r=0;
if (p == '+') r = y + x;
if (p == '-') r = y - x;
if (p == '*') r = y * x;
if (p == '/') r = y / x;
a[tt1++] = r;
//cout<<r<<endl;
}
int main(){
string s;
cin>>s;
//cout<<s;
for(int i = 0;i<s.size();i++){
if(isdigit(s[i])){
int x=0,j=i;
while(j<s.size()&&isdigit(s[j])){
x = x*10+(s[j]-'0');
j++;
}
a[tt1++]=x;
//cout<<x;
i=j-1;
}
else if(s[i]=='('){
b[tt2++]='(';
}
else if(s[i]==')'){
while(tt2>0&&b[tt2-1]!='(') eval();
tt2--;
}
else{
while(tt2> 0 && h[b[tt2-1]]>=h[s[i]]) eval();
b[tt2++]=s[i];
//cout<<s[i];
}
}
while(tt2>0) eval();
cout<<a[tt1-1]<<endl;
return 0;
}
队列
先进先出,没底的桶
// hh 表示队头,tt表示队尾
int q[N], hh = 0, tt = -1;
// 向队尾插入一个数
q[ ++ tt] = x;
// 从队头弹出一个数
hh ++ ;
// 队头的值
q[hh];
// 判断队列是否为空,如果 hh <= tt,则表示不为空
if (hh <= tt)
{
}
//实例测试
#include<iostream>
using namespace std;
const int N = 1e5+10;
int q[N],hh,tt=-1;
int main(){
int num,n;
string s;
cin>>num;
while(num--){
cin>>s;
if(s=="push"){
cin>>n;
q[++tt]=n;
}
if(s=="pop"){
hh++;
}
if(s=="empty"){
if(hh<=tt) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
if(s=="query"){
cout<<q[hh]<<endl;
}
}
return 0;
}
单调栈
感觉很详细的介绍:[数据结构]——单调栈-CSDN博客
//常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
//测试实例输出每个数左边第一个比它小的数,如果不存在则输出 −1
#include<iostream>
using namespace std;
const int N = 1e5+10;
int a[N],tt;
int main(){
int num,n;
scanf("%d",&num);
for(int i = 0;i<num;i++){
scanf("%d",&n);
while(tt&&a[tt]>=n) tt--;
if(tt) printf("%d ",a[tt]);
else printf("-1 ");
a[++tt] = n;
}
return 0;
}
单调队列
主要解决滑动窗口的问题
//常见模型:找出滑动窗口中的最大值/最小值
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
while (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗口
while (hh <= tt && check(q[tt], i)) tt -- ;
q[ ++ tt] = i;
}
//滑动窗口经典例题
#include<iostream>
using namespace std;
const int N = 1e6+10;
int a[N],q[N];
int main(){
int num,k;
scanf("%d%d",&num,&k);
for(int i = 0;i<num;i++) scanf("%d",&a[i]);
int hh=0,tt=-1;
for(int i = 0;i<num;i++){
if(hh<=tt&&i-k+1>q[hh]) hh++;
while(hh<=tt&&a[q[tt]]>=a[i]) tt--;
q[++tt]=i;
if(i>=k-1) printf("%d ",a[q[hh]]);
}
printf("\n");
hh=0,tt=-1;
for(int i = 0;i<num;i++){
if(hh<=tt&&i-k+1>q[hh]) hh++;
while(hh<=tt&&a[q[tt]]<=a[i]) tt--;
q[++tt]=i;
if(i>=k-1) printf("%d ",a[q[hh]]);
}
return 0;
}