文章目录
1.概念
栈是一种操作受限的线性表,只允许在一端插入和删除数据. 先进后出 and 后进先出
个人感觉,栈可以使用 内部钱内部的场景,某个对象,在内部包含另一个完整的对象,比如 [()], 这对中括号,内部包含了一个完整的小括号对; 又如函数的层层调用,外部函数,包含了内部函数的全部过程。
2.分类
2.1顺序栈
用数组实现的栈叫顺序栈.
2.1.1 固定大小
package com.desmond.codebase.algorithm.stack;
import java.util.Stack;
/**
* @author presleyli
* @date 2018/12/24 12:57 PM
*/
public interface StackInterface<E> {
E push(E e);
E pop();
E peek();
}
package com.desmond.codebase.algorithm.stack;
/**
* 固定大小的顺序栈(数组栈).
* @author presleyli
* @date 2018/12/24 12:57 PM
*/
public class FixedSizeArrayStack implements StackInterface<String>{
private String[] arr;
private int size;
public FixedSizeArrayStack(int n) {
arr = new String[n];
}
/**
* O(1)
* @param s
* @return
*/
@Override
public String push(String s) {
if(size >= arr.length) {
throw new RuntimeException("stack is full");
}
arr[size++] = s; // 1
return s;
}
// O(1)
@Override
public String pop() {
if(size == 0) {
return null;
}
return arr[--size]; // 1
}
// O(1)
@Override
public String peek() {
if(size == 0) { // 1
return null;
}
int idx = size - 1; // 1
return arr[idx]; // 1
}
@Override
public String toString() {
if(size > 0) {
System.out.println("start___________");
for(int i=size-1;i>=0;i--) {
System.out.println(String.valueOf(arr[i]));
}
System.out.println("end______\n\n");
}
return "\n";
}
public static void main(String[] args) {
FixedSizeArrayStack stack = new FixedSizeArrayStack(2);
stack.push("a");
System.out.println(stack);
stack.push("b");
System.out.println(stack);
System.out.println("peek:" + stack.peek());
System.out.println("peek:" + stack.peek());
System.out.println(stack);
System.out.println("pop:" + stack.pop());
System.out.println(stack);
System.out.println("pop:" + stack.pop());
System.out.println(stack);
System.out.println("pop:" + stack.pop());
System.out.println(stack);
}
}
2.1.2 可扩容
利用数组的动态扩容。复杂度
-
最好:O(1)
-
最坏: O(n)
-
均摊:O(1)
package com.desmond.codebase.algorithm.stack; /** * 可自动扩容的顺序栈(数组栈). * @author presleyli * @date 2018/12/24 12:57 PM */ public class ChangeableSizeArrayStack implements StackInterface<String>{ private String[] arr; private int size; private final int SCALE = 2; public ChangeableSizeArrayStack(int n) { arr = new String[n]; } /** * 最好:O(1) * 最坏:2n+3 -> O(n) * 均摊(摊还):O(1) * @param s * @return */ @Override public String push(String s) { if(size >= arr.length) { // 1 // 数组已满,扩容 String[] newarr = new String[arr.length * SCALE]; // 1 for(int i=0; i<arr.length; i++) { // n newarr[i] = arr[i]; // n } arr = newarr; } arr[size++] = s; // 1 return s; } @Override public String pop() { if(size == 0) { return null; } return arr[--size]; } @Override public String peek() { if(size == 0) { return null; } int idx = size - 1; return arr[idx]; } @Override public String toString() { if(size > 0) { System.out.println("start___________"); for(int i=size-1;i>=0;i--) { System.out.println(String.valueOf(arr[i])); } System.out.println("end______\n\n"); } return "\n"; } public static void main(String[] args) { ChangeableSizeArrayStack stack = new ChangeableSizeArrayStack(2); stack.push("a"); System.out.println(stack); stack.push("b"); System.out.println(stack); stack.push("c"); System.out.println(stack); stack.push("d"); System.out.println(stack); stack.push("e"); System.out.println(stack); stack.push("f"); System.out.println(stack); stack.push("g"); System.out.println(stack); System.out.println("peek:" + stack.peek()); System.out.println("peek:" + stack.peek()); System.out.println(stack); System.out.println("pop:" + stack.pop()); System.out.println(stack); System.out.println("pop:" + stack.pop()); System.out.println(stack); System.out.println("pop:" + stack.pop()); System.out.println(stack); } }
2.2链式栈
用链表实现的栈叫顺序栈.
package com.desmond.codebase.algorithm.stack;
import com.desmond.codebase.algorithm.link.Link;
/**
* 链式栈.
* @author presleyli
* @date 2019/1/5 10:53 AM
*/
public class LinkStack implements StackInterface<String>{
private Link<String> link = new Link<>();
@Override
public String push(String s) {
link.add(s);
return s;
}
@Override
public String pop() {
return link.remove(link.size() - 1);
}
@Override
public String peek() {
return link.index(link.size() - 1).getE();
}
}
3.应用
3.1函数调用
3.2表达式中的应用
3.2.1 背景
求四则运算 3+5*8-6 的值:取两个栈,一个放操作数,一个放运算符合。当放入运算符号时,判断如果之前的运算符的优先级大于当前时,先从操作数栈出栈两个操作数,并运用运算符进行运算,结果压入栈中,一直往复至最后一个元素
3.2.1 示意图
3.2.2 代码
package com.desmond.codebase.algorithm.stack;
import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;
import java.util.stream.Stream;
/**
* 利用栈实现 四则运算符,
* 3+5*8-6
* @author presleyli
* @date 2019/1/5 11:03 AM
*/
public class Operation {
public static void main(String[] args) {
System.out.println(op("3+5*8-6") + "-->" + "37");
System.out.println(op("3+5") + "-->" + "8");
System.out.println(op("5*8") + "-->" + "40");
System.out.println(op("5*8-6") + "-->" + "34");
}
/**
* O(1).
* @param express
* @return
*/
public static Integer op(String express) {
FixedSizeArrayStack eleStack = new FixedSizeArrayStack(5 );
FixedSizeArrayStack opStack = new FixedSizeArrayStack(5);
int result = 0;
char[] arr = express.toCharArray();
for(int i = 0; i < arr.length; i++) {
char c = arr[i]; // 1
OpEnum opEnum = OpEnum.getOp(c); // 1
if(opEnum != null) {
operations(eleStack, opEnum, opStack); // 1
opStack.push(c + "");
} else {
eleStack.push(c + "");
}
if(i == arr.length - 1) {
opEnum = OpEnum.getOp(opStack.pop().charAt(0));
result = cal(opEnum, eleStack);
}
}
return result;
}
/**
* O(1).
* @param eleStack
* @param curr
* @param opStack
*/
private static void operations(FixedSizeArrayStack eleStack, OpEnum curr, FixedSizeArrayStack opStack) {
if(eleStack.size() > 1 && opStack.size() > 0) {
OpEnum existing = OpEnum.getOp(opStack.peek().charAt(0)); // 1
if(existing.getPriority() >= curr.getPriority()) { // 1
existing = OpEnum.getOp(opStack.pop().charAt(0));
int result = cal(existing, eleStack);
eleStack.push(result + "");
operations(eleStack, curr, opStack);
}
}
}
/**
* O(1)
* @param oe
* @param eleStack
* @return
*/
private static Integer cal(OpEnum oe, FixedSizeArrayStack eleStack) {
int result = 0;
int top1 = Integer.parseInt(eleStack.pop());
int top2 = Integer.parseInt(eleStack.pop());
switch (oe) {
case ADD:
result = top2 + top1;
break;
case SUBSTRACT:
result = top2 - top1;
break;
case MULTIPLE:
result = top2 * top1;
break;
case DIVIION:
result = top2 / top1;
break;
}
return result;
}
private static enum OpEnum {
ADD('+', 1),
SUBSTRACT('-', 1),
MULTIPLE('*', 2),
DIVIION('/', 2),
;
private char op;
private int priority;
OpEnum(char op, int priority) {
this.op = op;
this.priority = priority;
}
public static OpEnum getOp(char c) {
return Stream.of(OpEnum.values())
.filter(o -> o.getOp() == c)
.findFirst()
.orElse(null);
}
public char getOp() {
return op;
}
public void setOp(char op) {
this.op = op;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
}
}
3.3 括号匹配
判断表达中括号()/[]/{}是否一一匹配.
代码:
package com.desmond.codebase.algorithm.stack;
import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;
/**
* @author presleyli
* @date 2019/1/5 11:59 AM
*/
public class BracketMatch {
public static void main(String[] args) {
System.out.println(isValid("a(([{}]))"));
System.out.println(isValid("a(b[c{d}]}"));
System.out.println(isValid("a(b[(c{d}]]}"));
System.out.println(isValid("a(b{[c{d}]}"));
}
/**
* O(1).
* @param express
* @return
*/
public static boolean isValid(String express) {
FixedSizeArrayStack stack = new FixedSizeArrayStack(10);
for(int i = 0; i < express.length(); i++) {
char c = express.charAt(i);
if(c == '(' || c == '[' || c == '{') {
stack.push(c + "");
}
if(c == ')' || c == ']' || c == '}') {
char b = stack.pop().charAt(0);
if(c == ')') {
if(b != '(') {
return false;
}
}
if(c == ']') {
if(b != '[') {
return false;
}
}
if(c == '}') {
if(b != '{') {
return false;
}
}
}
}
return stack.size() == 0;
}
}
3.4 浏览器前进、后退
流程:
代码:
package com.desmond.codebase.algorithm.stack;
import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;
import com.desmond.codebase.algorithm.stack.base.StackInterface;
/**
* 浏览器前进或者后推.
* @author presleyli
* @date 2019/1/5 12:38 PM
*/
public class BrowserAheadOrBack {
static StackInterface<String> ahead = new FixedSizeArrayStack(5),
back = new FixedSizeArrayStack(5);
public static void main(String[] args) {
init();
ahead();
ahead();
back();
back();
back();
back();
}
public static void init() {
ahead.push("a");
ahead.push("b");
back.push("c");
}
public static void ahead() {
if(back.size() > 0) {
ahead.push(back.pop());
}
if(back.size() == 0) {
System.out.println("last page!");
}
System.out.println("current: " + ahead.peek());
}
public static void back() {
if(ahead.size() > 0) {
back.push(ahead.pop());
}
if(ahead.size() == 0) {
System.out.println("first page!");
}
System.out.println("current: " + ahead.peek());
}
}
4. Jvm中的栈
桢栈,包括局部变量表,操作数栈(存放操作数用于操作),动态链接,方法出口灯信息