栈:是一种特殊的线性表,只允许在固定的一端插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈(push):栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈(pop):栈的删除操作叫做出栈。出数据在栈顶。
public static void main(String[] args) {
Stack<Integer> s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else {
System.out.println(s.size());
}
}
栈的底层是一个非常简单的数组,所以可以使用数组来模拟实现栈。类里面成员变量有数组elem,数组大小usedSize,默认容量DEFAULT_CAPCITY 。
public class MyStack {
public int[] elem;
public int usedSize;
public static final int DEFAULT_CAPCITY = 10;
public MyStack() {
this.elem = new int[DEFAULT_CAPCITY];
}
}
直接返回大小是否等于数组长度。
public boolean isFull() {
return usedSize == elem.length;
}
判断数组是否满了,满了使用copyOf()进行扩容,通过直接在数组0下标开始存放元素,存一个used Size++接着往后存。
public void push(int val) {
if(isFull()) {
this.elem = Arrays.copyOf(elem,2*elem.length);
}
elem[usedSize++] = val;
}
通过从数组usedSize-1拿到元素实现出栈,然后usedSize–(不会删除元素,但下次push压栈时直接覆盖此数据),
public int pop()throws EmptyStackException{
if (isEmpty()){
throw new EmptyStackException("栈为空");
}
int oldVal = elem[usedSize-1];
usedSize--; // 不会删除元素,但下次push压栈时直接覆盖此数据
//elem[usedSize] = null; 如果是引用类型
return oldVal;
}
public boolean isEmpty() {
return usedSize == 0;
}
public int peek() {
if (isEmpty()) {
throw new EmptyStackException("栈为空");
}
return elem[usedSize-1];
}
如果是单链表没有last引用,假设从头入栈时间复杂度O(1),从头出:删除头节点O(1),假设从尾巴入那么时间复杂度就为O(n),从尾巴出:O(n)。而双向链表,均为O(1),实现栈又称链式栈
import java.util.Iterator;
public class MyStack2<E> implements StackInterface<E>,Iterable<E>{
static class Node<E> {
public E value;
Node<E> next;
public Node() {
}
public Node(E value, Node<E> next) {
this.value = value;
this.next = next;
}
}
private int size;
private final int capacity;
private final Node<E> sentry;
public MyStack2(int capacity) {
this.capacity = capacity;
this.sentry = new Node<>(null,null);
}
}
通过在链表中进行头插节点实现入栈。
@Override
public boolean push(E value) {
if (isFull()) {
System.out.println("栈满");
return false;
}
sentry.next = new Node<>(value,sentry.next);
size++;
return true;
}
通过头删节点来实现出栈,先找到头节点,让sentry节点的后节点指向头节点的后节点。
@Override
public E pop() {
if (isEmpty()) {
return null;
}
Node<E> first = sentry.next;
sentry.next = first.next;
size--;
return first.value;
}
@Override
public E peek() {
if (isEmpty()) {
return null;
}
Node<E> first = sentry.next;
return first.value;
}
@Override
public boolean isEmpty() {
return size == 0;
//return sentry.next == null;
}
@Override
public boolean isFull() {
return size == capacity;
}