1. 栈(Stack)
1.1 文字讲解
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则(竖立的水杯模型)。其中一下两个操作是栈的主要操作:
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
1.2 图像分析
从上图中可以看到,Stack继承了Vector父类,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安全的。
下图图一和图二分别是入栈和出栈操作关于栈顶和栈底的图解:
2、自定义栈的实现
2.1 栈的实现方法和功能表达
详细方法和功能如下图:
2.2 自定义栈的代码实现
说明:本栈的实现主要 采用int型数组的结构;
2.2.1 栈的创建
思路:
1、创建一个MyStack类,其中定义两个成员变量,数组(用来存放底层数据)和长度(用来记录当前的栈里面存放数据的数量),实现3中定义的接口,重写其方法让栈的操作具体化;
2、构造方法,创建一个默认长度为10的数组;
public class MyStack implements IStack{private int[] data;private int usedLength;//实际已经占用的数组长度private static final int Default_Length = 10;public MyStack() {this.data = new int[Default_Length];}@Overridepublic void push(int x) {}@Overridepublic int pop() {return 0;}@Overridepublic int peek() {return 0;}@Overridepublic int size() {return 0;}@Overridepublic boolean empty() {return false;}@Overridepublic boolean full() {return false;}
}
3、定义一个接口,在里面创建栈一系列操作的抽象方法;
public interface IStack {void push(int x);int pop();int peek();int size();boolean empty();boolean full();
}
2.2.2 压栈方法的实现
1、首先对当前栈进行判断是否为满,若满则需要对当前栈进行二倍容量扩容
2、当栈的容量充足时,在栈顶进行入栈(底层数组尾部进行添加数据)
3、当前栈的数量长度加一;
@Overridepublic void push(int x) {if (full() == true){this.data = Arrays.copyOf(data,2*Default_Length);}data[usedLength] = x;usedLength++;}@Overridepublic boolean full() {if (usedLength == data.length){return true;}return false;}
2.2.3 栈是否为空操作
@Overridepublic boolean empty() {return usedLength == 0;}
2.2.4出栈的实现
思路:
1、首先得判断当前栈栈是否为空,若为空我们需要抛出栈为空自定义异常(自定义一个异常为EmptyException);
public class EmptyException extends RuntimeException{public EmptyException(String msg) {super(msg);}
}
2、将当前的栈顶的元素存储到容器中并返回
3、将栈的长度加一,之前栈顶的数据引用地址就会变成null(空指针),出栈的数据的地址就不会被引用而导致数据从栈里消失;
图解如下:
代码如下:
@Overridepublic int pop() {if (empty()){throw new EmptyException("当前这个栈是空的!!!");}int old = data[usedLength-1];usedLength--;//相当于是删除return old;}
2.2.5获取栈中数据元素个数
@Overridepublic int size() {return usedLength;}
2.2.6获取栈顶元素
思路类似于2.2.4;
@Overridepublic int pop() {if (empty()){throw new EmptyException("当前这个栈是空的!!!");}int old = data[usedLength-1];usedLength--;//相当于是删除return old;}
3.关于链表的栈使用
3.1单链表
从头部插入(入栈),从头部删除(出栈),时间复杂度为O(1);
从尾部插入(入栈),从尾部删除(出栈),时间复杂度为O(n);不建议使用
3.2双向链表:
从头部插入(入栈),从头部删除(出栈)
从尾部插入(入栈),从尾部删除(出栈),有last引用,直接到表尾部
二者时间复杂度皆为O(1);
3.3 LinkedList自带实现方法:
public static void main(String[] args) {LinkedList<Integer> linkedList = new LinkedList<>();linkedList.push(101);linkedList.push(102);linkedList.push(103);linkedList.push(104);System.out.println(linkedList.peek());System.out.println(linkedList.pop());System.out.println(linkedList.pop());}
测试结果:
4.Q&A
Q1:栈、虚拟机栈、栈帧有什么区别呢?
A1:
栈:是一种数据结构里面的概念,用来存放数据的一种模式;
虚拟机栈:jvm虚拟机划分的一块内存;
栈帧:调用方法的时候会在虚拟机中给这个方法开辟一个空间;
ps:本次内容就到这里了,如果喜欢的话就请一键三连哦!!!