数据结构-栈
导语
栈是一种“操作受限”的线性表,只允许在一端插入和删除数据。当某个数据集合只涉及到一端的插入删除操作,并且满足先进后出,后进先出的特性,我们就应该首选“栈”这种数据结构。
栈的分类及常用的操作方法
用数组实现的栈被称为顺序栈
,用链表实现的栈被称为链式栈
。常用的方法有压栈push()、弹栈pop()、是否为空isEmpty()、栈中数据大小size()、返回最近添加元素,不删除peek()
数组实现栈
public class StackOfArray<Integer> implements Iterable<Integer> {
int[] a = null;
int N = 0;
//构造器
public StackOfArray() {
N = 1;
a = new int[N];
}
//入栈
public void push(int value) {
if (N == a.length) reSize(2 * a.length);
a[++N] = value;
}
//弹栈
public int pop() {
int value = a[--N];
a[N] = 0;//这里需要特殊处理,暂时处理成0
if (N > 0 && N == a.length / 4) reSize(a.length / 2);
return value;
}
//动态数组
private void reSize(int length) {
int temp[] = new int[length];
for (int i = 0; i < N; i++) {
temp[i] = a[i];
}
a = temp;
}
// 返回栈中最近添加的元素,不删除
public int peek() {
return a[N - 1];
}
// 返回数组大小
public int size() {
return N;
}
//是否为空
public boolean isEmpty() {
return N == 0;
}
@Override
public Iterator<Integer> iterator() {
return new ArrayIterator();
}
class ArrayIterator implements Iterator {
int i = N;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Object next() {
return a[--i];
}
}
}
链表实现栈
public class StackOfLinked<T> implements Iterable<T> {
private ListNode first;
private int N;
private LinkedIterator linkedIterator;
//构造器
public StackOfLinked() {
}
//添加
public void push(int value) {
ListNode oldNode = first;
first = new ListNode(value);
first.next = oldNode;
N++;
}
//删除
public int pop() {
int value = first.data;
first = first.next;
--N;
return value;
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
public int peek() {
return first.data;
}
@Override
public Iterator<T> iterator() {
if (linkedIterator == null){
linkedIterator = new LinkedIterator();//迭代器初始化防止重复创建
}
return linkedIterator;
}
class LinkedIterator implements Iterator {
int i = N;
ListNode t = first;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Object next() {
int value = t.data;
t = t.next;
--i;
return value;
}
}
}
栈在JVM中的应用
每个JVM线程拥有一个私有的Java虚拟机栈,创建线程的同时栈也被创建。一个JVM栈由许多帧组成,称之为“栈帧”。JVM中的栈和C等常见语言中的栈比较类似,都是用于保存局部变量和部分计算结果,同时也参与方法调用和返回。
虚拟机栈用于存储当前线程正在运行方法数据、指令和返回地址。当线程请求的栈深度大于虚拟机运行最大深度,则会抛出StackOverflowError;虚拟机栈动态扩展时若无法申请到足够的的内存空间,则会抛出OutOfMemoryError