一一后进先出的线性表
一.概念与定义
栈(stack)是一个先进先出的数据结构,又称为后进先出(L5IFO—last in first out)的线性表。联想一下链表,在单链表中,只能对表头进行插入和删除,这样强限制性的链表,就是所说的栈。也就是说,栈是限定在表的同一端进行插入和删除的数据结构。
栈顶(top):线性表允许插入和删除的那一段。值得注意的是,栈顶指针top的指向是有两种方式的,一种是指向栈顶当前元素,一种是指向栈顶的下一位置。两种指向方式对栈的操作影响不大,只是在判断栈顶位置的时候略有差异。
栈底(bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含有任何元素的空表。
二.实现与基本操作
1)STL系统栈
操作 | 含义 |
---|---|
stack<Type> s | Type为数据结构,s为栈名 |
s.push(item) | 把item放在栈顶 |
s.top() | 返回栈顶元素,但不删除 |
s.pop() | 删除栈顶元素 |
s.size() | 返回元素个数 |
s.empty() | 返回栈是否为空(true或false) |
例题: 反转字符串(单词翻转)
输入样例:
Hello world!
输出样例:
olleH !dlrow
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
getchar();
while(n--){
stack<char> s;
while(true){
char ch=getchar();
if(ch==' ' ||ch=='\n' ||ch==EOF){
while(!s.empty()){
cout<<s.top();
s.pop();
}
if(ch=='\n'||ch==EOF)
break;
cout<<' ';
}
else
s.push(ch);
}
cout<<'\n';
}
return 0;
}
如果是整行翻转呢?
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
getchar();
while(n--){
stack<char> s;
while(1){
char ch=getchar();
if(ch=='\n' ||ch==EOF){
while(!s.empty()){
cout<<s.top();
s.pop();
}
}
else
s.push(ch);
}
cout<<'\n';
}
return 0;
}
整篇文档呢?
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
getchar();
while(n--){
stack<char> s;
while(1){
char ch=getchar();
if(ch=='\n' ||ch==EOF){
while(!s.empty()){
cout<<s.top();
s.pop();
}
}
else
s.push(ch);
}
cout<<'\n';
}
return 0;
}
二)手写栈
步骤大差不差,以上题为例,代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
struct mystack{
char a[N];
int t=0;
void push(char x){a[++t]=x;}
char top(){return a[t];}
void pop(){t--;}
int empty(){return t==0?1:0;}
}st;
int main(){
int n;
cin>>n;getchar();
while(n--){
while(true){
char ch=getchar();
if(ch==' ' || ch=='\n' || ch==EOF){
while(!st.empty()){
cout<<st.top();
st.pop();
}
if(ch=='\n'||ch==EOF) break;
cout<<' ';
}else st.push(ch);
}
cout<<'\n';
}
return 0;
}
三)单调栈
定义:单调栈内的元素是单调递增或递减的。例如,单调递减栈从栈顶到栈底从小到大顺序,当一个元素入栈时,与栈顶比较,若比栈顶小,则入栈。若比栈顶大,则弹出栈顶,直到这个数能入栈为止。
例题:向右看齐 洛谷P2947
输入样例:
6 3 2 6 1 1 2
输出样例:
3 3 0 6 6 0
思路:先读入每个奶牛的身高,从后向前遍历奶牛,之后使用一个单调栈保存从低到高的奶牛身高,栈顶的最矮,栈底的最高。
具体操作:遍历到奶牛i时,将栈顶的奶牛与其进行比较,如果不比奶牛i高,则弹出栈顶,知道栈顶的奶牛比奶牛i高,这就是奶牛的仰望对象;然后把i放进栈顶,栈中的奶牛依然保持从低到高。
每头奶牛只进栈一次,所以时间复杂度为O(n)
STL stack:
#include<bits/stdc++.h>
using namespace std;
int h[100001],ans[100001];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>h[i];
stack<int> st;
for(int i=n;i>=1;i--){
while(!st.empty() && h[st.top()]<=h[i])
st.pop();//栈顶奶牛没有i高,弹出它,直到栈顶奶牛更高为止
if(st.empty())
ans[i]=0;
else
ans[i]=st.top();
st.push(i);
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<'\n';
return 0;
}
手写栈:
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
struct mystack{
char a[N];
int t=0;
void push(char x){a[++t]=x;}
char top(){return a[t];}
void pop(){t--;}
int empty(){return t==0?1:0;}
}st;
int main(){
int n;
cin>>n;getchar();
while(n--){
while(true){
char ch=getchar();
if(ch==' ' || ch=='\n' || ch==EOF){
while(!st.empty()){
cout<<st.top();
st.pop();
}
if(ch=='\n'||ch==EOF) break;
cout<<' ';
}else st.push(ch);
}
cout<<'\n';
}
return 0;
}
作业:洛谷P5788,P1449,P1175
加油,每天拼凑一点星火,组成绚烂的星河!