栈(Stack):一种特殊的线性结构,其只允许固定的一段进行插入和删除元素操作。进行数据插入和删除的操作的一段称为栈顶,另一端称为栈底。栈中的元素遵守后进先出LIFO(Last In First Out)的原则。
【相关操作】
压栈:栈的插入操作叫做进栈、压栈、入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶
如现实中的例子,先装进弹夹的子弹是最后出弹夹的。
先被放的盘子是最后拿走的。
//栈的使用
public class Test {
public static void main(String[] args) {
//无参构造
Stack s = new Stack<>();
//入栈
System.out.println("=============入栈操作=================");
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s);
System.out.println("=============出栈操作==================");
int a = s.pop();
System.out.println(a);
System.out.println(s);//出栈后元素将不存在
System.out.println("=============窥探操作==================");
int b = s.peek();
System.out.println(b);
System.out.println(s);//如果只是简单窥探,不会让元素消失
System.out.println("============获取元素个数================");
System.out.println(s.size());
System.out.println("============清空栈=====================");
s.clear();
System.out.println(s);
}
}
这就是栈的常用的操作,基本就是入栈和出栈。
我们要明白Stack继承Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安全的。
package Demo1;
import java.util.Arrays;
/**
* Describe:
* User:lenovo
* Date:2023-01-09
* Time:16:30
*/
//栈的模拟实现
public class MyStack {
int[] array;
int size;
//无参构造
public MyStack() {
array = new int[3];
}
//入栈
public int push(int e) {
ensureCapacity();
array[size] = e;
size++;
return e;
}
//确定空间
private void ensureCapacity() {
if(!isFull()) {
return;
}
grow();
}
//判断空间是否满了
private boolean isFull() {
if(size == array.length) {
return true;
}
return false;
}
//扩大空间
private void grow() {
int newlength = (int)(array.length * 1.5);
if(newlength > 10000) {
newlength = 10000;
}
int[] newArray = new int[newlength];
array = Arrays.copyOf(array, newlength);
}
//出栈
public int pop(){
if(size <= 0) {
throw new RuntimeException("栈为空,无法进行出栈操作");
}
int e = peek();
size--;
return e;
}
//窥探
public int peek() {
if(size <= 0) {
throw new RuntimeException("栈为空,无法进行peek()操作");
}
int e = array[size - 1];
return e;
}
//获取栈的长度
public int size() {
return size;
}
//判断栈是否为空
public boolean empty() {
return size == 0;
}
//清空栈
public void clear() {
size = 0;
}
//检测
public static void main(String[] args) {
MyStack s = new MyStack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
s.push(6);
System.out.println(s.peek());
System.out.println(s.pop());
System.out.println(s.size());
}
}
1.若进栈的序列为1,2,3,4,进栈的时候可以出栈,下列不可能的出栈顺序是()
A.1,4,3,2 B.2,3,4,1 C.3,1,4,2 D.3,4,2,1
2.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后依次出栈,则元素出栈的顺序是()
比如逆序打印单向链表
//逆序打印单向链表
class Node {
int val;
Node next;
public Node() {
}
public Node(int val) {
this.val = val;
}
}
public class Test {
//递归
void printList(Node head) {
if(head == null) {
return;
}
printList(head.next);
System.out.print(head.val + " ");
}
//循环
void printList1(Node head) {
Stack s = new Stack<>();
Node cur = head;
while(cur != null) {
s.push(cur.val);//入栈
cur = cur.next;
}
int size = s.size();
for (int i = 0; i < size; i++) {
System.out.print(s.pop() + " ");
}
System.out.println();
}
}
class Solution {
public boolean isValid(String s) {
Stack stack = new Stack<>();
//我们将左括号放进栈中,遇到右括号,将栈中元素弹出,进行匹配
int i = 0;
int length = s.length();
for (i = 0; i < length; i++) {
char tmp = s.charAt(i);
if(tmp == '(' || tmp == '[' || tmp == '{') {
stack.push(tmp);
}else {
if(stack.empty()) {
return false;
}
char tmp1 = stack.pop();
if(!(tmp == ')' && tmp1 == '(' ||
tmp == ']' && tmp1 == '[' ||
tmp == '}' && tmp1 == '{')) {
return false;
}
}
}
if(i == length && stack.empty()) {
return true;
}
return false;
}
}
首先我们要解释一下什么是逆波兰表达式。
如:1+(12+2)*1-5求出它的逆波兰表达式。
最后我们得到这样的表达式,如果遇到数组,我们把数字放到栈中,如果遇到符号,我们弹出两个元素进行操作,得到的结果放入栈中,直到最后所有元素走完。
我们看我们要写的题:逆波兰表达式求值。
class Solution {
public int evalRPN(String[] tokens) {
int length = tokens.length;
Stack stack = new Stack<>();
for (int i = 0; i < length; i++) {
String key = tokens[i];
if(key.equals("+") || key.equals("-")
|| key.equals("*") || key.equals("/")) {
int num2 = stack.pop();//我们先弹出来的数字是操作符右边的数字
int num1 = stack.pop();
int ret = 0;
if(key.equals("+")) {
ret = num1 + num2;
}else if(key.equals("-")) {
ret = num1 - num2;
}else if(key.equals("*")) {
ret = num1 * num2;
}else if(key.equals("/")) {
ret = num1 / num2;
}
stack.push(ret);
}else {
int val = Integer.valueOf(key);
stack.push(val);
}
}
return stack.pop();
}
}
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等,数组长度相同。判断第二个序列是否是弹出的顺序。
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
int length = pushA.length;
int i = 0;
int j = 0;
Stack stack = new Stack<>();
while (i < length) {
if(!stack.empty() && stack.peek() == popA[j]) {
stack.pop();
j++;
}else {
stack.push(pushA[i]);
i++;
}
}
if(stack.empty()) {
return true;
}else {
while(j < length) {
if(stack.pop() != popA[j]) {
return false;
}
j++;
}
}
return true;
}
}
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
//设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
class MinStack {
private int[] data;
private int size;
private int[] minNum;
public MinStack() {
data = new int[10];
minNum = new int[10];
}
public void push(int val) {
if(size == data.length) {
data = Arrays.copyOf(data, 2*data.length);
minNum = Arrays.copyOf(minNum, 2*minNum.length);
}
data[size] = val;
if(size == 0) {
minNum[size] = val;
}else if(minNum[size - 1] < val) {
minNum[size] = minNum[size - 1];
}else {
minNum[size] = val;
}
size++;
}
public void pop() {
size--;
}
public int top() {
return data[size - 1];
}
public int getMin() {
return minNum[size - 1];
}
}