基础数据结构----栈

栈的特点是“先进后出”。栈在生活中的原型有:坐电梯,先进电梯的被挤到最里面,只能最后出来;一管泡腾片,最先放入管子的药片位于最底层,最后被拿出来。栈只有唯一的出入口,从这个口进入,也从这个口弹出,这是它与队列的最大的区别。

编程中常用的递归就是用栈来实现的,栈需要用空间存储,如果栈的深度太大,或者存进数组的栈太大,那么总会超过系统为栈分配的空间。就会爆栈导致栈溢出。这是递归的主要问题,递归深度需要注意。

编码时通常直接用STL stack,或者自己手写栈。为了避免爆栈,需要控制栈的大小。

STL stack

STL stack的有关操作如下所示:

操作 说明
stacks 定义栈,type为数据类型,如int、float、char等
s.push( it ) 把 it 压入栈
s.top() 返回栈顶元素,但不会删除
s.pop() 删除栈顶元素,但不会返回。在出栈时需要执行两步操作,先使用top()获得栈顶元素,再使用pop()删除栈顶元素
s.size() 返回栈中元素的个数
s.empty() 检查栈是否为空,如果为空则返回true,否则返回false

下面我们以hdu 1062为例子:

Text Reverse

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 74209    Accepted Submission(s): 28702


 
Problem Description
Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them.
 
 
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single line with several words. There will be at most 1000 characters in a line.
 
 
Output
For each test case, you should output the text which is processed.
 
 
Sample Input
3
olleh !dlrow
m'I morf .udh
I ekil .mca
 
 
Sample Output
hello world!
I'm from hdu. I like acm.
 
 
Hint

Remember to use getchar() to read '\n' after the interger T, then you may use gets() to read a line and process it.
 
 
Author
Ignatius.L
简单来说就是要我们翻转字符串,如输入olleh !dlrow,则输出hello world!,有n组数据,题目建议我们用getchar()或者gets,以下是利用STL stack实现:
#include
using namespace std;

int main()
{
	int n;
	cin >> n;//输入n组数据
	getchar();//注意这里是读取输入数据n后的回车'\n'
	
	while(n--)
	{
		stack s;
		while(true)
		{//因为不知道具体长度,我们用EOF来判断一行是否输入结束
		 //关于EOF可以参考我的另一篇博客"scanf()的返回值"
		 char ch = getchar();
		 if(ch == ' ' || ch == '\n' || ch == EOF)
		 {
		 	while(!s.empty())
			{
			 	printf("%c",s.top());
			 	s.pop();
			}
			if(ch == '\n' || ch == EOF)
			{//回车或EOF表示当前测试结束 
				break;	
			}
			printf(" ");//输出一个空格 
				
		 }
		 else
		 {
		 	s.push(ch);	
		 } 	
		}
		printf("\n");	
	}
	 
	return 0;
}

记住这个运行时间31ms,下面我们用手写栈来提交

手写栈

手写栈代码简单且节省空间。对于上面的题目,下面我们用手写栈来解决:

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

int main()
{
	int n;
	cin >> n;//输入n组数据
	getchar();//注意这里是读取输入数据n后的回车'\n'
	
	while(n--)
	{
		while(true)
		{//因为不知道具体长度,我们用EOF来判断一行是否输入结束
		 //关于EOF可以参考我的另一篇博客"scanf()的返回值"
		 char ch = getchar();
		 if(ch == ' ' || ch == '\n' || ch == EOF)
		 {
		 	while(!s.empty())
			{
			 	printf("%c",s.top());
			 	s.pop();
			}
			if(ch == '\n' || ch == EOF)
			{//回车或EOF表示当前测试结束 
				break;	
			}
			printf(" ");//输出一个空格 
				
		 }
		 else
		 {
		 	s.push(ch);	
		 } 	
		}
		printf("\n");	
	}
	 
	return 0;
}

可以看到,运行时间相比使用STL几乎砍半,若对时间复杂度有较高的要求,建议使用手写栈

单调栈

单调栈不是一种新的栈结构,它在结构上仍然是一个普通的栈,它是栈的一种使用方式。

单调栈内的元素是单调递增或者递减的,有单调递增栈、单调递减栈。单调栈可以用来处理比较问题。

具体的操作方法是当一个数入栈时,与栈顶比价,若比栈顶小,则入栈;若比栈顶大,则弹出栈顶,直到这个数能入栈为止。注意,每个数一定能入栈

我们以洛谷P2947为例子:

题目描述

Farmer John's N (1 <= N <= 100,000) cows, conveniently numbered 1..N, are once again standing in a row. Cow i has height H_i (1 <= H_i <= 1,000,000).

Each cow is looking to her left toward those with higher index numbers. We say that cow i 'looks up' to cow j if i < j and H_i < H_j. For each cow i, FJ would like to know the index of the first cow in line looked up to by cow i.

Note: about 50% of the test data will have N <= 1,000.

约翰的  N (1 ≤ N ≤ 10^5) 头奶牛站成一排,奶牛 i 的身高是   Hi​(1 ≤ Hi​ ≤ 10^6)。现在,每只奶牛都在向右看齐。对于奶牛 i,如果奶牛 j 满足 i < j 且 Hi ​< Hj​,我们可以说奶牛 i 可以仰望奶牛 j。 求出每只奶牛离她最近的仰望对象。

输入格式

第 1 行输入 N,之后每行输入一个身高 Hi​。

输出格式

共 N 行,按顺序每行输出一只奶牛的最近仰望对象,如果没有仰望对象,输出 0。

输入输出样例

输入 #1

6 
3 
2 
6 
1 
1 
2 

输出 #1

3 
3 
0 
6 
6 
0 

说明/提示

【输入说明】6 头奶牛的身高分别为 3,2,6,1,1,2。

【输出说明】奶牛 #1, #2 仰望奶牛 #3,奶牛 #4, #5 仰望奶牛 #6,奶牛 #3 和 #6 没有仰望对象。

【数据规模】

对于 20% 的数据:1 ≤ N ≤ 10;

对于 50% 的数据:1 ≤ N ≤ 10^3;

对于 100% 的数据:1≤ N ≤ 10^5, 1 ≤ Hi ​≤ 10^6。

我们的思路是:从后往前遍历奶牛(因为奶牛是向右看齐),并用一个栈保存从低到高的奶牛,栈顶的奶牛最矮,栈底的奶牛最高。具体操作:遍历到奶牛 i 时,将栈顶的奶牛与其进行比较,如果没有奶牛 i 高,就弹出栈顶,直到栈顶的奶牛比奶牛 i 高,这就是奶牛的仰望对象;然后把 i 放进栈顶,栈中的奶牛仍然保持从低到高。

每头奶牛只进出栈一次,所以复杂度为O(n)。

首先我们用STL stack代码:

#include
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 s;
	for(int i = n; i >= 1; i--)
	{//注意我们还是存入下标 
		while(!s.empty() && h[s.top()] <= h[i])
		{//栈顶奶牛没有 i 高,弹出它,直到栈顶奶牛更高为止 
			s.pop();
		}
		if(s.empty())
		{//栈空,没有仰望对象 
			ans[i] = 0;	
		}
		else
		{//栈顶奶牛更高,是仰望对象 
			ans[i] = s.top();	
		}
		s.push(i);	
	}
	
	for(int i = 1; i <= n; i++)
	{
		cout << ans[i] << endl;	
	}	
	
	return 0;
} 

基础数据结构----栈_第1张图片

手写栈代码几乎差不多,这里就不给出了,可以参考hdu 1062那个例子

你可能感兴趣的:(算法竞赛--初级,数据结构,c++,算法,stl)