一、栈(Stack)的概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守先进后出的原则LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据存储在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
说这么多其实就是一个数组,只要用尾插和尾删操作进行增删
栈在现实生活中的例子:
弹夹也是先按进去的最后打出去
二、栈的使用
2.1 Stack
这个数据结构非常简单也就这几个方法:
方法的使用:
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
//分别压入5个数据
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(stack.size());//计算栈中有几个元素,返回5
System.out.println(stack.pop());//出栈,5
System.out.println(stack.pop());//出栈,4
System.out.println(stack.peek());//获取顶层元素3
System.out.println(stack.peek());//获取顶层元素3
//栈为空返回true,不为空返回false
System.out.println(stack.empty());//false
}
2.2 实现Stack
之前说了其实栈就是数组,所以我们用数组来维护。但并非说其他结构如链表不能实现
public class MyStack2<E> {
public Object[] elem;//泛型需要用Object创建数组
public int usedSize;//记录元素个数
public MyStack2() {
this.elem = new Object[10];
}
}
2.2.1 push
public void push(E e) {
//判断堆栈是否满了
if(isFull()) {
//利用此方法可以实现拷贝源数据同时扩容
elem = Arrays.copyOf(elem,usedSize * 2);
}
//useSize刚好可以做为尾插的下标,
//元素类型是Object所以存放元素的时候最好转一下型
elem[usedSize] = (E)e;
usedSize++;
}
//需要一个判断是否栈满的方法
public boolean isFull() {
return elem.length == usedSize;
}
2.2.2 pop
public E pop() {
//判断堆栈是否为空
try {
if(empty()) {
throw new MyStackEmptyException("堆栈为空");
}
}catch (MyStackEmptyException e) {
e.printStackTrace();
}
//注意:取元素就一定要强转了,不是 《最好强转》 了
E ret = (E)elem[usedSize-1];
usedSize--;
return ret;
}
当栈为空还要删除肯定是不行的,写一个异常来处理
public class MyStackEmptyException extends RuntimeException {
public MyStackEmptyException(String s) {
super(s);
}
public MyStackEmptyException() {
super();
}
}
2.2.3 peek
public E peek() {
//判断堆栈是否为空
try {
if(empty()) {
throw new MyStackEmptyException("堆栈为空");
}
}catch (MyStackEmptyException e) {
e.printStackTrace();
}
// int ret = elem[usedSize-1];
// usedSize--;
return (E)elem[usedSize-1];
}
这个不需要多久,不进行删除操作就行了
2.2.4 size
public int size() {
return usedSize;
}
2.2.5 empty
public boolean empty() {
if(usedSize == 0) {
return true;
}else {
return false;
}
}
从上图中可以看到,Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安 的。
Stack继承了Vector,但是Vector已经过时了,Stack用的也比较少了,但并非不能用。
那我们其实还可以用Deque做为栈使用
2.3 Deque
//用ArrayDeque实现的栈,背后是数组
Deque<Integer> stack1 = new ArrayDeque<>();
//用LinkdList实现的栈,背后是双向链表
Deque<Integer> stack2 = new LinkedList<>();
当然他们两不只可以用来实现栈,还可以实现队列……
使用方法基本都是一样的:
public static void main(String[] args) {
Deque<Integer> stack1 = new ArrayDeque<>();
stack1.push(1);
stack1.push(2);
stack1.push(3);
stack1.push(4);
stack1.push(5);
System.out.println(stack1.pop());//5
System.out.println(stack1.peek());//4
System.out.println(stack1.peek());//4
System.out.println(stack1.size());//4
//Stack中是empty效果是一样的
System.out.println(stack1.isEmpty());//false
Deque<Integer> stack2 = new LinkedList<>();
stack2.push(1);
stack2.push(2);
stack2.push(3);
stack2.push(4);
System.out.println(stack2.pop());//4
System.out.println(stack2.peek());//3
System.out.println(stack2.peek());//3
System.out.println(stack2.size());//3
//Stack中是empty效果是一样的
System.out.println(stack2.isEmpty());//false
}