栈
:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO
(
Last In First Out
)的原则。
压栈:栈的插入操作叫做进栈
/
压栈
/
入栈,
入数据在栈顶
。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
栈的方法
方法 功能 Stack() 构造一个空栈 E push(E e) 将e入栈,并返回e E pop()将栈顶元素出栈并返回
E peek() 获取栈顶元素 int size() 获取栈中有效元素的个数 boolean empty() 检测栈是否为空Stack():
private int[] elem;
private int usedSize;
public MyStack() {
this.elem = new int[5];
}
push(e):
public void push(int val) {
if(isFull()) {
elem = Arrays.copyOf(elem,2*elem.length);
}
elem[usedSize] = val;
usedSize++;
}
pop():
public int pop() {
if(empty()) {
//抛出异常
throw new StackEmptyException("栈为空!");
}
return elem[--usedSize];
}
peek():
public int peek() {
if(empty()) {
//抛出异常!!
throw new StackEmptyException("栈为空!");
}
return elem[usedSize-1];
}
size():
public int size(){
return usedSize;
}
empty():
public boolean empty() {
return usedSize == 0;
}
栈的经典题:
括号匹配问题:
class Solution {
public boolean isValid(String s) {
Stack<Character> 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()){
return false;
}else {
char tmp = stack.peek();
if(ch == ')' && tmp == '(' || ch == ']' && tmp == '[' || ch == '}' && tmp == '{'){
stack.pop();
}else {
return false;
}
}
}
}
if(!stack.empty()){
return false;
}
return true;
}
}
逆波兰表达式求值:
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for(String s : tokens) {
if(isNumber(s)){
stack.push(Integer.parseInt(s));
} else {
int num2 = stack.pop();
int num1 = stack.pop();
switch(s){
case"+":
stack.push(num1 + num2);
break;
case"-":
stack.push(num1 - num2);
break;
case"*":
stack.push(num1 * num2);
break;
case"/":
stack.push(num1 / num2);
break;
}
}
}
return stack.pop();
}
public boolean isNumber(String s){
if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
return false;
}
return true;
}
}
出栈和入栈的次序匹配:
import java.util.*;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
Stack<Integer> stack = new Stack<>();
int j = 0;
for(int x : pushA) {
stack.push(x);
while(!stack.empty() && j < pushA.length && stack.peek() == popA[j]) {
stack.pop();
j++;
}
}
return stack.empty();
}
}
最小栈:
class MinStack {
private Stack<Integer> stack;
private Stack<Integer> minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int val) {
stack.push(val);
if(minStack.empty()){
minStack.push(val);
} else {
if(val <= minStack.peek()) {
minStack.push(val);
}
}
}
public void pop() {
if(stack.empty()){
return;
}
int val = stack.pop();
if(val == minStack.peek()){
minStack.pop();
}
}
public int top() {
if(stack.empty()){
return -1;
}
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头 (Head/Front)
方法 | 功能 |
boolean offer(E e) | 入队列 |
E poll() | 出队列 |
peek() | 获取队头元素 |
int size() | 获取队列中有效元素个数 |
boolean isEmpty() | 检测队列是否为空 |
用链表模拟实现队列:
static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;
public ListNode last;
private int usedSize;
offer( ):
public void offer(int val) {
ListNode node = new ListNode(val);
if(head == null) {
head = node;
last = node;
}else {
last.next = node;
last = last.next;
}
usedSize++;
}
poll():
public int poll() {
if(head == null) {
return -1;
}
int val = -1;
if(head.next == null) {
val = head.val;
head = null;
last = null;
return val;
}
val = head.val;
head = head.next;
usedSize--;
return val;
}
peek():
public int peek() {
if(head == null) {
return -1;
}
return head.val;
}
size():
public int getUsedSize() {
return usedSize;
}
循环队列:
方法 | 功能 |
boolean enQueue() | 入队 |
boolean deQueue() | 出队 |
int Front() | 获得队头元素 |
int Rear() | 获得队尾元素 |
boolean isEmpty() | 判断循环队列为空 |
boolean isFull() | 判断循环队列为满 |
private int[] elem;
private int front;//队头下标
private int rear;//队尾下标
public MyCircularQueue(int k) {
this.elem = new int[k+1];
}
boolean enQueue():
public boolean enQueue(int value) {
if(isFull()) {
return false;
}
elem[rear] = value;
rear = (rear+1) % elem.length;
return true;
}
boolean deQueue():
public boolean deQueue() {
if(isEmpty()) {
return false;
}
front = (front+1) % elem.length;
return true;
}
int Front():
public int Front() {
if(isEmpty()) {
return -1;
}
return elem[front];
}
int Rear():
public int Rear() {
if(isEmpty()) {
return -1;
}
int index = (rear == 0) ? elem.length-1 : rear-1;
return elem[index];
}
boolean isEmpty():
public boolean isEmpty() {
return rear == front;
}
boolean isFull():
public boolean isFull() {
return (rear+1) % elem.length == front;
}