1.什么是栈?
栈是一个有序的线性表,只能在栈顶进行操作插入和删除操作。所以也叫先进后出表。
2.栈的应用场景
- 符号匹配
- 中缀表达式转换为后缀表达式
- 计算后缀表达式
- 实现函数调用
- 求范围误差
- 网页浏览器中已访问页面的历史纪录
- 文本编辑器中的撤销序列
- 作为算法辅助数据结构(二叉树的非递归遍历)
3.栈的具体实现
3.1 基于简单数组的实现
顾名思义,就是用数组实现栈的应用
性能表:
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
push() | O(1) | O(n) |
pop() | O(1) | O(1) |
size() | O(1) | O(1) |
isEmpty() | O(1) | O(1) |
isFull() | O(1) | O(1) |
deleteStack() | O(1) | O(1) |
3.2 动态数组的实现
它其实就是在简单数组基础上实现重复倍增来实现的:
以上面的简单数组实现为基础,增加一个倍增方法:
/**
* 栈空间扩增方法
*/
private void doubleStack() {
int[] newArray = new int[capacity*2];
System.arraycopy(array,0,newArray,0,capacity);
capacity = capacity*2;
array = newArray;
}
性能表:
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
push() | O(1) | O(n) |
pop() | O(1) | O(1) |
size() | O(1) | O(1) |
isEmpty() | O(1) | O(1) |
isFull() | O(1) | O(1) |
deleteStack() | O(1) | O(1) |
3.3 链表的实现
使用链表实现栈,通过在链表的表头插入元素的方式实现push,删除链表的表头节点实现pop.
但,使用它还需要实现节点的构造,相比数组麻烦些,而且链表不太符合栈的顺序特性,
且它的性能表如下:
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
push() | O(1) | O(n) |
pop() | O(1) | O(1) |
size() | O(1) | O(1) |
isEmpty() | O(1) | O(1) |
isFull() | O(1) | O(1) |
deleteStack() | O(n) | O(1) |
相比之下它的deleteStack复杂度比动态数组大。所以推荐使用动态数组实现栈。
3.4 Java动态数组实现栈结构
package course.p5_stack;
/**
* 栈的基础实现
* 栈比较适合使用数组实现,因为使用数组实现栈的push,pop的时间复杂度都为O(1),且操作简单
*/
public class ArrayStack {
/**
* 存储栈顶元素的索引
*/
private int top;
/**
* 栈的空间大小,默认起始为10
*/
private int capacity = 10;
/**
* 存储栈元素的数组
*/
private int[] array;
/**
* 无参构造方法
*/
public ArrayStack() {
array = new int[capacity];
top = -1;
}
/**
* 定义大小构造方法
* @param a 定义栈的大小
*/
public ArrayStack(int a) {
capacity = a;
array = new int[a];
top = -1;
}
/**
* 判断此栈是否为空
* @return true--空 false--不空
*/
public boolean isEmpty() {
return top == -1;
}
/**
* 判断栈是否已满
* @return
*/
public boolean isStackFull() {
return top == capacity-1;
}
/**
* 将数据压入栈中
* @param data
*/
public void push(int data) {
if(isStackFull()) {
doubleStack();
}
array[++top] = data;
}
/**
* 弹出栈顶元素
* @return
*/
public int pop() {
if(isEmpty()) {
System.out.println("Stack is Empty!");
return -1;
}
else{
return array[top--];
}
}
/**
* 删除栈
*/
public void deleteStack() {
top = -1;
array = null;
capacity = 0;
}
/**
* 栈空间扩增方法
*/
private void doubleStack() {
int[] newArray = new int[capacity*2];
System.arraycopy(array,0,newArray,0,capacity);
capacity = capacity*2;
array = newArray;
}
}
测试方法编写:
package course.p5_stack;
import org.junit.Assert;
import org.junit.Test;
import java.util.Optional;
import java.util.Random;
import java.util.Stack;
public class StackTest {
private final Stack<Integer> stackRight = new Stack<>();
@Test
public void stackTest(){
ArrayStack stack = new ArrayStack();
for (int i=0;i<1000;i++){
boolean active = new Random().nextBoolean();
if(active){
stack.push(i);
stackRight.push(i);
}else {
Assert.assertEquals(stackRight.isEmpty(),stack.isEmpty());
if(!stackRight.isEmpty()){
Assert.assertEquals(Optional.ofNullable(stackRight.pop()),Optional.ofNullable(stack.pop()));
}
}
}
}
}
运行结果:(没有任何报错,测试通过)
Process finished with exit code 0