目录
我的GitHub:Powerveil · GitHub
我的Gitee:Powercs12 (powercs12) - Gitee.com
皮卡丘每天学Java
栈
概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
栈的使用
方法 | 功能 |
---|---|
Stack() | 构造一个空的栈 |
E push(E e) | 将e入栈,并返回e |
E pop() | 将栈顶元素出栈并返回 |
E peek() | 获取栈顶元素 |
int size() | 获取栈中有效元素个数 |
boolean empty() | 检测栈是否为空 |
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());
}
}
栈的模拟实现
public class MyStack {
public int[] elem;
//当前栈 当中 存储的有效的数据个数 也可以当中 当前可以存放数据元素的下标
public int usedSize;
public static final int DEFAULT_CAPACITY = 10;
public MyStack() {
elem = new int[DEFAULT_CAPACITY];
}
/**
* 压栈
*/
public void push(int val) {
//1、判断栈是否是满的
if(isFull()) {
elem = Arrays.copyOf(elem,2*elem.length);
}
//存放到当前的下标,同时usedSize需要自增
elem[usedSize] = val;
usedSize++;
}
/**
* 判断 当前栈是否是满的
* @return
*/
public boolean isFull() {
if(usedSize == elem.length) {
return true;
}
return false;
}
/**
* 删除栈顶元素
* @return
*/
public int pop(){
if(isEmpty()) {
throw new EmptyStackException("栈为空了!");
}
int oldVal = elem[usedSize-1];
usedSize--;
return oldVal;
}
/**
* 是否为空
* @return
*/
public boolean isEmpty() {
return usedSize == 0;
}
/**
* 获取栈顶元素 但是不删除
* @return
*/
public int peek() {
if(isEmpty()) {
throw new EmptyStackException("栈为空了!");
}
return elem[usedSize-1];
}
public int getUsedSize() {
return usedSize;
}
}
概念区分
栈、虚拟机栈、栈帧有什么区别呢?
堆叠(英语:stack)又称为栈或堆叠,是计算机科学中的一种抽象资料型别,只允许在有序的线性资料集合的一端(称为堆叠顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运作,堆叠常用一维数组或连结串列来实现。常与另一种有序的线性资料集合伫列相提并论。
Java虚拟机(英语:Java Virtual Machine,缩写为JVM),一种能够执行Java bytecode的虚拟机,以堆栈结构机器来进行实做。最早由Sun微系统所研发并实现第一个实现版本,是Java平台的一部分,能够执行以Java语言写作的软件程序。
栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。简言之,栈帧就是利用EBP
(栈帧指针,请注意不是ESP)寄存器访问局部变量、参数、函数返回地址等的手
队列
概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)
队列的使用
在Java中,Queue是个接口,底层是通过链表实现的。
方法 | 使用 |
---|---|
boolean offer(E e) | 入队列 |
E poll() | 出队列 |
E peek() | 获取队头元素 |
int size() | 获取队列中有效元素个数 |
boolean isEmpty() | boolean isEmpty() |
注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。
public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
q.offer(5); // 从队尾入队列
System.out.println(q.size());
System.out.println(q.peek()); // 获取队头元素
q.poll();
System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
if(q.isEmpty()){
System.out.println("队列空");
}else{
System.out.println(q.size());
}
}
队列的模拟
顺序结构模拟队列
class MyQueue {
private int[] elements; // 元素数组
private int front; // 队列尾部下标
private int rear; // 队列头部的下一个下标
private static final int DEFAULT_CAPACITY = 10; // 默认扩容数量 ArrayList
private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认加载因子 HashMap
// 无参构造
public MyQueue() {
elements = new int[DEFAULT_CAPACITY];
}
// 有参构造
public MyQueue(int capacity) {
elements = new int[capacity];
}
// 检查容量
private void checkCapacity() {
if (elementsTouchThreshold()) {
grow();
}
}
// 判断是否需要扩容
private boolean elementsTouchThreshold() {
int threshold = (int) (DEFAULT_LOAD_FACTOR * elements.length);
return rear >= threshold;
}
// 扩容
private void grow() {
int oldCapacity = elements.length;
int newCapacity = (oldCapacity + oldCapacity << 1);
elements = Arrays.copyOf(elements, newCapacity);
}
// 向队列头插入元素
public void push(int x) {
checkCapacity();
elements[rear++] = x;
}
// 弹出队列尾元素
public int pop() {
if (empty()) throw new OutOfTheRangeException("队列为空");//自定义异常
return elements[front++];
}
// 查看队列尾元素
public int peek() {
if (empty()) throw new OutOfTheRangeException("队列为空");//自定义异常
return elements[front];
}
// 判断队列是否为空
public boolean empty() {
return front == rear;
}
}
链式结构模拟队列
public class MyQueue {
static class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
public Node head;//队列的头
public Node tail;//队列的尾
/**
* 入队操作
* @param val
*/
public void offer(int val) {
Node node = new Node(val);
if(head == null) {
head = node;
tail = node;
}else {
tail.next = node;
tail = tail.next;
}
}
/**
* 出队
*/
public int poll() {
if(head == null) {
return -1;//或者抛异常
}
int oldVal = head.val;
if(head.next == null) {
head = tail = null;
}else {
head = head.next;
}
return oldVal;
}
//查看当前队头元素是几
public int peek() {
if(head == null) {
return -1;//或者抛异常
}
return head.val;
}
}
循环队列
力扣
空出一个位置
class MyCircularQueue {
int[] elements;
int front;
int rear;
public MyCircularQueue(int k) {
elements = new int[k + 1];
}
public boolean enQueue(int value) {
if (isFull()) return false;
elements[rear] = value;
rear = (rear + 1) % elements.length;
return true;
}
public boolean deQueue() {
if (isEmpty()) return false;
front = (front + 1) % elements.length;
return true;
}
public int Front() {
if (isEmpty()) return -1;
return elements[front];
}
public int Rear() {
if (isEmpty()) return -1;
return elements[(rear - 1 + elements.length) % elements.length];
}
public boolean isEmpty() {
return front == rear;
}
public boolean isFull() {
return (rear + 1) % elements.length == front;
}
}
使用usedSize计数
class MyCircularQueue {
int[] elements;
int front;
int rear;
int usedSize;
public MyCircularQueue(int k) {
elements = new int[k];
}
public boolean enQueue(int value) {
if (isFull()) return false;
elements[rear] = value;
usedSize++;
rear = (rear + 1) % elements.length;
return true;
}
public boolean deQueue() {
if (isEmpty()) return false;
front = (front + 1) % elements.length;
usedSize--;
return true;
}
public int Front() {
if (isEmpty()) return -1;
return elements[front];
}
public int Rear() {
if (isEmpty()) return -1;
return elements[(rear - 1 + elements.length) % elements.length];
}
public boolean isEmpty() {
return usedSize == 0;
}
public boolean isFull() {
return usedSize == elements.length;
}
}
双端队列
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Deque是一个接口,使用时必须创建LinkedList的对象。