栈学习笔记

什么是栈

栈是一种先进后出的数据结构, 就好比我们生活中的乒乓球桶, 只有一端开口。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。 我们学习递归的时候, 在计算机内部就是用栈实现的递归。在计算机中,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算,这一端被称为栈顶,相对地,把另一端称为栈底。
在这里插入图片描述

写一个栈

按照栈的基本定义,我们可以自己动手来写一个保存整数的栈。
在动手之前,先来规划需要实现哪些功能,简单总结如下:

操作函数解释
入栈push(x)将x元素入栈
出栈pop()弹出栈的第一个元素,返回值为栈顶元素值
元素个数size()获取栈中的元素个数,返回int
获取栈顶元素top() 获取栈顶元素的值

我们可以用一个数组 stackArray ,来记录栈的元素。
用一个下标 index ,记录当前栈顶的位置,有了这个位置,我们可以获取栈顶元素,也可以获取元素数量。
具体实现如下:

#include <bits/stdc++.h>
using namespace std;
int stackArray[1000], index = -1;
void push(int x) {
    index++;
    stackArray[index] = x;
}
int pop() {
    int value = stackArray[index];
    index--;
    return value;
}
int top() {
    return stackArray[index];
}
int size() {
    return index + 1;
}
int main() { 
    push(1);
    push(2);
    push(3);
    cout << "顶:" << top() << endl;
    cout << "大小:" << size() << endl;
    pop();
    cout << "顶:" << top() << endl;
    cout << "大小:" << size() << endl;
    pop();
    cout << "顶:" << top() << endl;
    cout << "大小:" << size() << endl;
    pop();
    return 0;
}

运行结果如下:

:3
大小:3:2
大小:2:1
大小:1

stack的基本操作

在 C++ 的标准库中, 有封装好的栈 stack , stack 是一个模板类,定义 stack 的示例代码如下:

stack<类型> 对象:
stack<int>  s;
操作代码解释
入栈s.push(x)将x元素入栈
出栈s.pop()弹出栈的第一个元素,并不会返回元素的值
栈顶元素s.top()获取栈的第一个元素
元素个数s.size()获取栈中的元素个数,返回int
判空s.empty()栈是否为空,返回bool,相当于s.size() == 0

在这里插入图片描述

stack的示例

#include <bits/stdc++.h>
using namespace std;
int main() { 
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    cout << "顶:" << s.top() << endl;
    cout << "大小:" << s.size() << endl;
    s.pop();
    cout << "顶:" << s.top() << endl;
    cout << "大小:" << s.size() << endl;
    s.pop();
    cout << "顶:" << s.top() << endl;
    cout << "大小:" << s.size() << endl;
    s.pop();
    return 0;
}

输出:

:3
大小:3:2
大小:2:1
大小:1

在这里插入图片描述

课堂练习:操作栈

有一个初始为空的栈,我们对这个栈进行n次操作,操作共分为2种:

  1. 1 x(将数字 x 放入栈)
  2. 2(将栈顶元素弹出)
    对于第2种操作,你需要把弹出的这个数字输出,如果进行操作2时,栈为空,则输出"empty"。
    例如:n = 5,对应的操作为:
    1 123 (操作后栈里面的元素为:123)
    1 234(操作后栈里面的元素为:123, 234)
    2(输出:234,操作后栈里面的元素为:123)
    2(输出:123,操作后栈里面的元素为:空)
    2(输出:empty)
    对应后面3个第2类操作,你的程序需要输出,
    234
    123
    empty

输入格式

第一行:1个数n(1 <= n <= 10000) 后面n行:每行1种操作,1 X或者2(0 <= x <= 10000)

输出格式

对应所有操作2,输出被弹出的数或者"empty"

输入样例

5
1 123
1 234
2
2
2

输出样例

234
123
empty

程序1答案

#include<bits/stdc++.h>
using namespace std;
int n,p,x;
stack<int> k;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>p;
		if(p==1){
			cin>>x;
			k.push(x);
		}
		else{
			if(k.empty())
				cout<<"empty"<<endl;
			else{
				cout<<k.top()<<endl;
				k.pop();
			}
		}
	}
}

题解:定义一个栈,按照题目要求操作,遇到 1 则入栈,遇到 2 则先输出栈顶元素,再让元素出栈。如果空了就输出“empty”。

课后作业:数字游戏

现在有n个数字依次进入一个栈,每个数字a进入栈的时候,如果栈顶元素小于a,则会将栈顶元素弹出,新的栈顶元素如果仍然小于a,则会将新的栈顶元素继续弹出,直到栈顶元素大于等于a为止,a才会加入栈。问n个数字依次进入后,最后栈里的数字依次是?

输入格式

输入第一行一个整数n(n<=100000),表示有n个数字依次进入栈。 接下来n行,每行一个整数,表示第i个数字。

输出格式

若干行,表示最后栈中的数字。

输入样例

5
5
3
2 
4
1

输出样例

5
4
1

程序2答案

#include <bits/stdc++.h>
using namespace std;
int n;
stack<int> a;
int m;
int s[100000];
int j;
int main(){
	scanf("%d",&n);
	while(n--){
		cin>>m;
		if(a.empty()){
			a.push(m);
		}
		else{
			while(!a.empty()&&a.top()<m){
				a.pop();
			}
			a.push(m);
		}
	}
	while(!a.empty()){
		s[j]=a.top();
		a.pop();
		j++;
	}
	for(int i=j-1;i>=0;i--){
		cout<<s[i]<<endl;
	}
}

题解:本题描述的这种栈,有专门的命名叫做单调栈。因为栈中的元素是递减的,所有本题只需按照题目要求,处理栈的 push 和 pop 即可。但需要特别注意栈为空时,要将下一个push。

进阶习题:合法括号序列 V1

有一个括号序列,现在要检测一下它是否是合法的括号序列
合法括号序列的定义是:
1.空序列是合法括号序列。
2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。

输入格式

输入一行,长度为N的括号序列S(0<=N<=50000,S只包括()这2种字符)

输出格式

输出一行,1表示括号序列合法,0表示括号序列不合法

输入样例

(())(

输出样例

0

程序3答案

#include<bits/stdc++.h>
using namespace std;
stack <char> s;
string x;
int main(){
	cin>>x;
	int len=x.size();
	for(int i=0;i<len;i++){
		if(x[i]=='('){
			s.push(x[i]);	
		}
		else{
			if(s.empty()){
			cout<<"0"<<endl;
			return 0;
			}
			if(s.top()=='('){
				s.pop();
			}	
			else{
				cout<<"0"<<endl;
				return 0;
			}	
		}
	}
	if(s.empty()){
		cout<<"1"<<endl;
	}else{
		cout<<"0"<<endl;
	}
}
/*
#include<bits/stdc++.h>
using namespace std;
int cnt=0;
string x;
int main(){
	cin>>x;
	int len=x.size();
	for(int i=0;i<len;i++){
		if(x[i]=='('){
			cnt++;	
		}
		else{
			
			if(x[i]=='('){
				cnt--;
			}	
		}
	}
	if(cnt==0){
		cout<<"1"<<endl;
	}
	else{
		cout<<"0"<<endl;
	}
}

题解:本题由于只需要处理一种括号(如果题目同时需要处理多种括号则不能采用本方法),因此栈中只可能出现“(” 和“) ”,因此我们甚至可以不用栈,只用一个数字来记录 没有被“)” 消掉的 “( ”​ 的数量即可。方法可以简化为,逐个读取符号,遇到“( ”则计数加一,遇到 “) ” 则计数减一,如果中间出现计数小于 0 的情况,则是不合法的。再读取完整个字符后,还需要判断计数是否为 0 ,不等于 0 则是不合法的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值