栈——后进先出的线性表

一.栈的定义

栈(stack)又叫堆栈,是一种运算受限的线性表,即只允许在表的一端进行插入和删除运算。一端称为栈顶,相对的,另一端称为栈底。向一个栈中插入新元素又称为进栈、入栈或压栈,即把新元素放到栈顶元素的上面,使之成为新的栈顶元素。从一个栈中删除元素又称为出栈或退栈、弹栈,即把栈顶元素删除掉,使其相邻元素成为新的栈顶元素。

由于栈的插入和删除运算仅在栈顶一端进行,后进栈的元素必定先被删除,因而又把栈称为后进先出表(Last In First Out,缩写为LIFO)。

 栈的示意图:

  • 栈顶(top):线性表允许插入和删除的那一端。值得注意的是,栈顶指针top的指向是有两种方式的,一种是指向栈顶当前元素,一种是指向栈顶的下一位置。两种指向方式对栈的操作影响不大,只是在判断栈顶位置的时候略有差异。
  • 栈底(bottom):固定的,不允许进行插入和删除的另一端。
  • 空栈:不含任何元素的空表。

 二.实现与基本操作

1、STL stack的相关操作

操作含义
stack<Type> sType为数据结构,s为栈名
s.push(item)把item放在栈顶
s.top()返回栈顶元素,但不删除
s.pop()删除栈顶元素
s.size()返回元素个数
s.empty()返回栈是否为空(true或false)

对比列表命令如下:

queue<Type> q//定义队列,Type为数据类型,如int,float,char等
q.push(i)
q.front()//队首
q.pop()
q.back()//队尾
q.size()
q.empty()

例题: 翻转字符串

输入样例:
        2
        hello world!
        r u okay?
输出样例:
        olleh !dlrow
        r u ?yako

#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(){
	stack<char> s;
	while(1){
		char ch=getchar();
		if(ch==EOF){
			while(!s.empty()){
				cout<<s.top();
				s.pop();
			}
			break; 
		}
		else
			s.push(ch);
	}
	return 0;
} 

2、手写栈

#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;
}

3、单调栈

定义:单调栈内的元素是单调递增或递减的。例如,单调递减栈从栈顶到栈底从小到大顺序,当一个元素入栈时,与栈顶比较,若比栈顶小,则入栈。若比栈顶大,则弹出栈顶,直到这个数能入栈为止。

例题:向右看齐 洛谷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{
	int a[N];
	int t=0;
	void push(int x){a[++t]=x;}
	int top(){return a[t];}
	void pop(){t--;	}
	int empty(){return t==0?1:0;}
}st;

int h[N],ans[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>h[i];
	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;
} 

  • 40
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值