✏️✏️✏️今天给大家分享一下栈的基本概念、线性栈的自定义实现,以及栈的应用题目。
清风的CSDN博客
希望我的文章能对你有所帮助,有不足的地方还请各位看官多多指教,大家一起学习交流!
动动你们发财的小手,点点关注点点赞!在此谢过啦!哈哈哈!
目录
一、关于栈(Stack)
1.1 栈的概念
1.2 栈的使用
1.3 栈的模拟实现
1.3.1 栈的类定义
1.3.2 判断栈空或栈满
1.3.3 出栈
1.3.4 入栈
1.3.5 获取栈顶元素
1.3.6 获取栈中当前元素个数
二、栈的应用
2.1 后缀表达式求值
2.2 括号匹配
2.3 最小栈
2.4 栈的压入、弹出序列
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
栈在现实生活中的例子:
上面的两个例子都遵循后进先出的原则。
栈可以在库函数中直接调用,比如下面的代码:
public static void main(String[] args) {
Stack s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());
}
}
所以,我们就可以利用顺序表来实现栈。
默认栈的大小为10,也可以通过构造函数自己定义栈的大小。
public class MyStack {
private final int DEFALUT_CAPACITY=10;
private int[] elem;
private int usedSize;
public MyStack(){
elem=new int[DEFALUT_CAPACITY];
}
public MyStack(int size){
int[] elem=new int[size];
}
}
栈空:在栈的类定义中,我们定义了一个usedSize来表示当前栈中的元素个数,因此,判断栈是否为空,只需要判断usedSize是否为0即可。
public boolean isEmpty(){
return usedSize==0;
}
栈满:如果当前栈中的元素个数和数组的长度相等,那么就判栈满。
public boolean isFull(){
return elem.length==usedSize;
}
数组的最后一个元素便是栈顶的元素,返回这个元素即可。
public int pop(){
if(isEmpty()){
System.out.println("栈空!");
return -1;
//或者抛自定义的异常
}
int old=elem[usedSize-1];
usedSize--;
//若是引用类型:>elem[usedSize]=null;
return old;
}
public void push(int data){
if(isFull()){
elem= Arrays.copyOf(elem,elem.length*2);
}
elem[usedSize]=data;
usedSize++;
}
public int peak(){
if(isEmpty()){
System.out.println("栈空!");
return -1;
}
return elem[usedSize-1];//获取栈顶元素
}
public int size(){
return usedSize;
}
后缀表达式求值的基本思路是:>当遇到的字符串是数字时,把它压入栈中,而当遇到的字符串是操作符时,从栈中弹出两个元素做对应的运算,再把运算结果压入栈中。字符串遍历完成后,栈顶元素就是计算的结果。这里需要注意,当遇到操作符要执行出栈操作是,第一次出栈的元素是计算时的右操作数,第二次出栈的元素是计算时的左操作数。
比如下面的题目:
给你一个字符串数组
tokens
,表示一个根据后缀表达式表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
根据上面的思路,我们写这个代码其实就非常简单了:>
public int evalRPN(String[] tokens) {
Stack stack=new Stack<>();
for (String x:tokens) {
if(!isOperation(x)){
//如果不是操作符,就把x转为数字并压栈
stack.push(Integer.parseInt(x));
}else{
//弹出两个操作数,并做相应的运算
int num2=stack.pop();
int num1=stack.pop();
switch (x){
case "+":
stack.push(num1+num2);
break;
case "-":
stack.push(num1-num2);
break;
case "*":
stack.push(num1*num2);
break;
case "/":
stack.push(num1/num2);
break;
}
}
}
int ret = stack.pop();
return ret;
}
private boolean isOperation(String s){
if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
return true;
}
return false;
}
给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
思路:>
下面是代码实现:>
public boolean isValid(String s) {
Stack stack=new Stack<>();
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
if((ch=='(') || (ch=='[') || (ch=='{')){
stack.push(ch);
}else{
if(!stack.empty()){
//如果栈不空
char ch2=stack.peek();//ch是右括号,ch2是左括号
if((ch2=='(' && ch==')') || (ch2=='{' && ch=='}') || (ch2=='[' && ch==']')){
//左括号出栈
stack.pop();
}else {
return false;
}
}else {
return false;
}
}
}
if(!stack.empty()){
//i已经遍历完成,栈还不为空,返回false
return false;
}
return true;
}
设计一个支持
push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。实现
MinStack
类:
MinStack()
初始化堆栈对象。void push(int val)
将元素val推入堆栈。void pop()
删除堆栈顶部的元素。(这里指普通栈)int top()
获取堆栈顶部的元素。(这里指普通栈)int getMin()
获取堆栈中的最小元素。
思路:>
利用两个栈来同时进行相关的操作,需要定义一个普通栈(Stack),还需要定义一个存放最小元素的栈(MinStack)。
关于入栈:>
关于出栈:>
下面的具体的代码实现:>
class MinStack {
private Stack stack;
private Stack MinStack;
public MinStack() {
stack=new Stack<>();
MinStack=new Stack<>();
}
public void push(int val) {
stack.push(val);
if(MinStack.empty()){
MinStack.push(val);
}else{
int peekVal=MinStack.peek();
if(val<=peekVal){
MinStack.push(val);
}
}
}
public void pop() {
/**
* pop的时候和stack的栈顶元素比较,如果相等,全部出栈
* 不一样,只出普通栈
*/
int val=stack.pop();
if(!MinStack.empty()){
if(val==MinStack.peek()){
MinStack.pop();
}
}
}
public int top() {
return stack.peek();
}
public int getMin() {
if(!MinStack.empty()){
return MinStack.peek();
}
return -1;
}
}
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
- 0<=pushV.length == popV.length <=1000
- -1000<=pushV[i]<=1000
- pushV 的所有数字均不相同
思路:>
下面是具体的实现代码:>
public boolean IsPopOrder (int[] pushV, int[] popV) {
// write code here
Stack stack = new Stack<>();
int j = 0;
for (int i = 0; i < pushV.length; i++) {
stack.push(pushV[i]);
while (!stack.empty() && j < popV.length && stack.peek() == popV[j]) {
stack.pop();
j++;
}
}
if (stack.empty()) {
return true;
}
return false;
}
✨希望各位看官读完文章后,能够有所提升。
好啦,今天的分享就到这里!!
✨创作不易,还希望各位大佬支持一下!
点赞,你的认可是我创作的动力!
⭐收藏,你的青睐是我努力的方向!
✏️评论:你的意见是我进步的财富!