栈在计算机学习中是一种重要的数据结构,拥有先进后出, 只在固定的的一端进行插入和删除操作, 插入数据在栈顶, 删除数据也在栈顶 的特性, 有非常多的应用:

栈的主要方法是:
import java.util.Arrays;
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-07-31
* Time: 20:24
*/
public class MyStack<T> {
private Object[] stack;
private int size;
public MyStack(int init) {
if (init <= 0) {
stack = new Object[100];
}else {
stack = new Object[init];
}
}
public MyStack() {
stack = new Object[100];
}
// 入栈
public T push(T e){
}
// 出栈
public T pop() {
}
// 查看栈顶元素
public T peek(){
}
// 查看当前栈的元素个数
public int size(){
}
// 查看栈是否为空
public boolean isEmpty(){
}
// 栈的扩容
private void ensureCapacity(){
}
}入栈操作, 重点是要从栈顶入栈
// 入栈
public T push(T e){
ensureCapacity();
stack[size++] = e;
return e;
}出栈, 也是在栈顶
// 出栈
public T pop() {
if (isEmpty()) {
throw new RuntimeException("栈为空,⽆法删除元素");
}
return (T) stack[--size];
}查看栈顶元素
// 查看栈顶元素
public T peek(){
if(isEmpty()){
throw new RuntimeException("栈为空,⽆法获取栈顶元素");
}
return (T)stack[size - 1];
}获取栈中有效元素个数
// 查看当前栈的元素个数
public int size(){
return size;
}查看栈是否为空
// 查看栈是否为空
public boolean isEmpty(){
return 0 == size;
}栈的扩容
// 栈的扩容
private void ensureCapacity(){
if(size == stack.length){
stack = Arrays.copyOf(stack, size*2);
}
}
import java.util.Queue;
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-07-31
* Time: 16:14
*/
public class Test {
public static void main(String[] args) {
MyStack<Integer> stack = new MyStack<>(10);
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println("获取MyStack<Integer>的栈顶: " + stack.peek());
System.out.println("删除MyStack<Integer>的栈顶: " + stack.pop());
System.out.println("查看MyStack<Integer>是否空: " +stack.isEmpty());
System.out.println("查看MyStack<Integer>栈的长度: " +stack.size());
System.out.println("------------");
MyStack<String> stringMyStack = new MyStack<>();
stringMyStack.push("hello");
stringMyStack.push("我");
stringMyStack.push("是");
stringMyStack.push("❀");
System.out.println("获取MyStack<String>的栈顶: " + stringMyStack.peek());
System.out.println("删除MyStack<String>的栈顶: " + stringMyStack.pop());
System.out.println("查看MyStack<String>是否空: " +stringMyStack.isEmpty());
System.out.println("查看MyStack<String>栈的长度: " +stringMyStack.size());
}
}
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-07-31
* Time: 21:42
*/
public class MyQueue<T> {
private Object[] queue;
private int front;
private int rear;
public MyQueue() {
queue = new Object[100];
}
// 入队列
public T offer(T e) {
}
// 出队列
public T poll() {
}
// 获取队头元素
public T peek() {
}
// 获取队列有效元素个数
public int size() {
}
// 检测队列是否为空
public boolean isEmpty() {
}
}入队列, 只能从队尾入队列, 入队列之前要判断队列是否满
// 入队列
public T offer(T e) {
grow();
queue[rear++] = e;
return e;
}出队列, 只能从队头出队, 出之前要判断队列是否空
// 出队列
public T poll() {
if (isEmpty()) {
throw new RuntimeException("队列没有元素!");
}
return (T) queue[front++];
}获取队头元素, 获取之前要判断队列是否空
// 获取队头元素
public T peek() {
if (isEmpty()) {
throw new RuntimeException("队列没有元素!");
}
return (T) queue[front];
}获取队列有效元素个数, 直接返回rear - font
// 获取队列有效元素个数
public int size() {
int size = rear - front;
return size >= 0 ? size : -1;
}检测队列是否为空, 判断rear是否等于front
// 检测队列是否为空
public boolean isEmpty() {
return rear == front;
}队列扩容之前要判断是否已满
private void grow() {
if (rear == queue.length) {
queue = Arrays.copyOf(queue,size *2);
}
}
public static void main(String[] args) {
MyQueue<Integer> queue = new MyQueue<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println("获取 MyQueue<Integer>的队头: " + queue.peek());
System.out.println("删除 MyQueue<Integer>的队头: " + queue.poll());
System.out.println("查看 MyQueue<Integer>是否空: " +queue.isEmpty());
System.out.println("查看 MyQueue<Integer>队列的长度: " +queue.size());
System.out.println("------------");
MyQueue<String> stringMyQueue = new MyQueue<>();
stringMyQueue.offer("hello");
stringMyQueue.offer("我");
stringMyQueue.offer("是");
stringMyQueue.offer("❀");
System.out.println("获取 MyQueue<String>的队头: " + stringMyQueue.peek());
System.out.println("删除 MyQueue<String>的队头: " + stringMyQueue.poll());
System.out.println("查看 MyQueue<String>是否空: " +stringMyQueue.isEmpty());
System.out.println("查看 MyQueue<String>队列的长度: " +stringMyQueue.size());
}观察上面的队列实现我们可以发现, 基于数组实现的普通队列空间利用率很低, 于是一种新的队列模型->循环队列诞生了, 通常我们去一个固定大小的数组, 队列满了则不能进队, 队列空了不能出队, 不再像之前扩容, 循环往复利用队列的空间

在实现之前我们要用到头指针front 和 尾指针rear 以及标志位size, 分别用来表示头尾位置与有效元素个数 方法模版放在下方
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-08-01
* Time: 9:50
*/
public class MyCycleQueue<T> {
private Object[] deque;
private int front;
private int rear;
private int size;
public MyCycleQueue() {
queue = new Object[5];
}
// 入队列
public boolean enQueue(T e) {
}
// 出队列
public boolean deQueue() {
}
// 获取队头元素
public T peek() {
}
// 获取队列有效元素个数
public int size() {
}
// 检测队列是否为空
public boolean isEmpty() {
}
}入队列,先要判断队列是否已满, 注意: front 的移动方式是从0到尾再到0, 所以可以将front=front%length, 确保front可以回归0位置, 并且不越界
// 入队列
public boolean enQueue(T e) {
if (size() == queue.length) {
return false;
}
queue[rear++] = e;
rear = rear % queue.length;
size++;
return true;
}出队列前先判断队列是否是空的, rear的移动方式和dront相同
// 出队列
public boolean deQueue() {
if (isEmpty()) {
return false;
}
front++;
front = front % queue.length;
size--;
return true;
}获取队头元素之前先判断队列是否为空
// 获取队头元素
public T peek() {
if (isEmpty()) {
throw new RuntimeException("队列是空的!!!");
}
return (T) queue[front];
}获取队列有效元素个数, 返回size
// 获取队列有效元素个数
public int size() {
return size;
}判断队列是否为空, 判断size是否为0
// 检测队列是否为空
public boolean isEmpty() {
return size == 0;
}
public static void main(String[] args) {
MyCycleQueue<Integer> queue = new MyCycleQueue<>();
System.out.println("是否加入成功12: " +queue.enQueue(12));
System.out.println("是否加入成功23: " +queue.enQueue(23));
System.out.println("是否加入成功34: " +queue.enQueue(34));
System.out.println("是否加入成功45: " +queue.enQueue(45));
System.out.println("是否加入成功56: " +queue.enQueue(56));
System.out.println("是否加入成功66: " +queue.enQueue(66));
System.out.println("获取 MyCycleQueue<Integer>的队头: " + queue.peek());
System.out.println("是否删除成功12: " +queue.deQueue());
System.out.println("获取 MyCycleQueue<Integer>的队头: " + queue.peek());
System.out.println("----------------------");
MyCycleQueue<String> stringMyCycleQueue = new MyCycleQueue<>();
System.out.println("是否加入成功h: " + stringMyCycleQueue.enQueue("h"));
System.out.println("是否加入成功e: " + stringMyCycleQueue.enQueue("e"));
System.out.println("是否加入成功l: " + stringMyCycleQueue.enQueue("l"));
System.out.println("是否加入成功l: " + stringMyCycleQueue.enQueue("l"));
System.out.println("是否加入成功o: " + stringMyCycleQueue.enQueue("o"));
System.out.println("是否加入成功ran: " + stringMyCycleQueue.enQueue("ran"));
System.out.println("获取 MyCycleQueue<String>的队头: " + stringMyCycleQueue.peek());
System.out.println("是否删除成功h: " + stringMyCycleQueue.deQueue());
System.out.println("获取 MyCycleQueue<String>的队头: " + stringMyCycleQueue.peek());
}
需要三个属性, 头尾指针以及size 模版放在下方
import java.util.Deque;
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-08-01
* Time: 11:05
*/
public class MyDque<T> {
private Object[] deque;
private int front;
private int rear;
private int size;
public MyDque() {
deque = new Object[5];
}
// 头插入队列
public void offerFirst(T e) {
}
// 尾差入队列
public void offerLast(T e) {
}
// 队头出队列
public boolean pollFirst() {
}
// 队尾出队列
public boolean pollLast() {
}
// 是否为空
public boolean isEmpty() {
}
// 获取队头元素
public T peekFirst() {
}
// 获取队尾元素
public T peekLast() {
}
// 获取队列有效元素个数
public int size() {
}
}我们这里双端队列头插时可以采用类似于循环队列的方式, 即front可以左移, 充分利用空间
// 头插入队列
public void offerFirst(T e) {
grow();
if (front > 0) {
deque[--front] = e;
size++;
return;
}
if (front == 0 ) {
for (int i = rear - 1; i >= 0; i--) {
deque[i + 1] = deque[i];
}
}
deque[0] = e;
rear++;
size++;
}尾差法之前要判断是否满, 只需要移动rear即可
// 尾差入队列
public void offerLast(T e) {
grow();
deque[rear++] = e;
size++;
}头删法, 先判断队列是否为空, 将front移动和置为null
// 队头出队列
public boolean pollFirst() {
if (isEmpty()) {
return false;
}
deque[front++] = null;
size--;
return true;
}尾删法, 先判断队列是否为空, 移动rear和置为null
// 队尾出队列
public boolean pollLast() {
if (isEmpty()) {
return false;
}
deque[--rear] = null;
size--;
return true;
}判断对了是否为空, 判断size
// 是否为空
public boolean isEmpty() {
return size == 0;
}获取队头元素, 先判断是否为空
// 获取队头元素
public T peekFirst() {
if (isEmpty()) {
return null;
}
return (T) deque[front];
}获取队尾元素, 先判断队列空不空
// 获取队尾元素
public T peekLast() {
if (isEmpty()) {
return null;
}
return (T) deque[rear - 1];
}获取队列有效元素个数, 直接返回size即可
// 获取队列有效元素个数
public int size() {
return size;
}队列满了就扩容
private void grow() {
if (size == deque.length) {
deque = Arrays.copyOf(deque, size * 2);
}
}
public static void main(String[] args) {
MyDque<Integer> deque = new MyDque<>();
deque.offerFirst(1);
deque.offerFirst(3);
deque.offerFirst(2);
deque.offerLast(0);
deque.offerLast(9);
System.out.println( "删除前: "+deque);
System.out.println("删除头元素" +deque.pollFirst());
System.out.println("删除尾元素" + deque.pollLast());
System.out.println( "删除后: "+deque);
System.out.println("------------------------");
MyDque<String> stringMyDque = new MyDque<>();
stringMyDque.offerFirst("h");
stringMyDque.offerFirst("e");
stringMyDque.offerFirst("l");
stringMyDque.offerFirst("l");
stringMyDque.offerFirst("0");
stringMyDque.offerFirst("ran");
System.out.println("删除前: " +stringMyDque);
System.out.println("删除头元素" +stringMyDque.pollFirst());
System.out.println("删除尾元素" +stringMyDque.pollLast());
System.out.println("删除后: " +stringMyDque);
}
要知道向上调整 siftUp与向下调整 siftDown的概念, 以及应用场景 这里以大根堆为例, 采用int类型的数组实现, 不再用泛型(泛型难度有点大) 模版放在下方

import java.util.Arrays;
import java.util.PriorityQueue;
/**
* Created with IntelliJ IDEA.
* Description:
* User: ran
* Date: 2025-08-01
* Time: 12:33
*/
public class MyPriorityQueue{
int[] priorityQueue;
int size;
public MyPriorityQueue() {
priorityQueue = new int[10];
}
// 入队列
public void offer(int e) {
}
// 扩容
private void grow() {
}
// 向上调整
public void siftUp(int child) {
}
// 向下调整
private void siftDown(int parent, int k) {
}
// 交换元素
private void swap(int parent, int child) {
}
// 删除优先级最高的元素
public int poll() {
}
// 获取优先级最高的元素
public int peek() {
}
}向上调整, 已知子节点来求父节点
// 向上调整
public void siftUp(int child) {
int parent = (child - 1) / 2;
while (parent >= 0) {
if (priorityQueue[child] > priorityQueue[parent]) {
swap(parent, child);
child = parent;
parent = (child - 1) / 2;
}else {
break;
}
}
}向下调整, 知道父节点后来求子节点, 并且有限制条件 k
// 向下调整
private void siftDown(int parent, int k) {
int child = parent * 2 + 1;
while (child < k) {
if (child + 1 < k && priorityQueue[child + 1] > priorityQueue[child]) {
child++;
}
if (priorityQueue[child] > priorityQueue[parent]) {
swap(parent,child);
parent = child;
child = parent * 2 + 1;
}else {
break;
}
}
}删除优先级最高的元素, 先判断是否为空, 交换收尾元素位置后向下调整
// 删除优先级最高的元素
public int poll() {
if (size == 0) {
throw new RuntimeException("空队列!!!");
}
int ret = priorityQueue[0];
swap(0, size - 1);
size--;
siftDown(0, size);
return ret;
}入队列, 从末尾入队列, 先判断队列是否, 后采用向上调整
// 入队列
public void offer(int e) {
grow();
priorityQueue[size] = e;
siftUp(size - 1);
}获取优先级最高的元素, 就是获取0下标的元素, 先判断是否为空
// 获取优先级最高的元素
public int peek() {
if (size == 0) {
throw new RuntimeException("空队列!!!");
}
return priorityQueue[0];
}
public static void main(String[] args) {
MyPriorityQueue priorityQueue = new MyPriorityQueue();
priorityQueue.offer(27);
priorityQueue.offer(15);
priorityQueue.offer(19);
priorityQueue.offer(18);
priorityQueue.offer(28);
priorityQueue.offer(34);
priorityQueue.offer(65);
priorityQueue.offer(49);
priorityQueue.offer(25);
priorityQueue.offer(37);
System.out.println("删除前: ");
priorityQueue.display();
System.out.println( "删除最大元素: " + priorityQueue.poll());
System.out.println( "删除最大元素: " + priorityQueue.poll());
System.out.println("删除后: ");
priorityQueue.display();
}希望本篇博客能对你有所帮助, 喜欢的话不妨互三一下☺