数据结构(二)队列和栈

目录

[1 基本API](#1 基本API)

[2 实现栈(用标准库的链表)](#2 实现栈(用标准库的链表))

[3 实现队列(用标准库的链表)](#3 实现队列(用标准库的链表))

[4 实现栈(用标准库的数组)](#4 实现栈(用标准库的数组))

[5 实现队列(用之前实现的环形数组)](#5 实现队列(用之前实现的环形数组))

[6 双端队列](#6 双端队列)


队列(先进先出FIFO)和栈(后进先出LIFO)的原理非常简单,它们底层实现就是数组或链表,只不过仅仅提供在头尾操作元素的 API,所以我们常说它们是操作受限的数据结构。

队列只能在「队尾(Rear)」插入元素,「队头(Front)」删除元素;

栈只能在「栈顶(Top)」插入和删除元素。

1 基本API

java 复制代码
// 队列的基本 API
class MyQueue<E> {
    // 向队尾插入元素,时间复杂度 O(1)
    void push(E e);

    // 从队头删除元素,时间复杂度 O(1)
    E pop();

    // 查看队头元素,时间复杂度 O(1)
    E peek();

    // 返回队列中的元素个数,时间复杂度 O(1)
    int size();
}
java 复制代码
// 栈的基本 API
class MyStack<E> {
    // 向栈顶插入元素,时间复杂度 O(1)
    void push(E e);

    // 从栈顶删除元素,时间复杂度 O(1)
    E pop();

    // 查看栈顶元素,时间复杂度 O(1)
    E peek();

    // 返回栈中的元素个数,时间复杂度 O(1)
    int size();
}

2 实现栈(用标准库的链表)

把双链表的尾部作为栈顶,在双链表尾部增删元素的时间复杂度都是 O(1),符合要求。

java 复制代码
package Theoretical_foundation.stack;

import java.util.LinkedList;

public class MyLinkedStack<E> {
    //stack 是栈的底层容器,从创建栈开始,stack 就固定指向这个链表,全程不会、也不能换其他容器
    //很多人会误以为[加了final,stack 就不能 push、pop 了] ------ 这是完全错误的!
    //final 只限制「list 引用不能变」,不限制「list 内部的元素操作」
    private final LinkedList<E> stack = new LinkedList<>();

    public void push(E e) {
        stack.addLast(e);
    }

    public E pop() {
        return stack.removeLast();
    }

    public E peek() {
        return stack.getLast();
    }

    public int size() {
        return stack.size();
    }

    public static void main(String[] args) {
        MyLinkedStack<Integer> stack = new MyLinkedStack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);

        System.out.println(stack.peek()); // 3
        System.out.println(stack.pop()); // 3
        System.out.println(stack.peek()); // 2
    }
}

3 实现队列(用标准库的链表)

把双链表的尾部作为队尾,把双链表的头部作为队头,在双链表的头删、尾增元素的复杂度都是 O(1),符合队列 API 的要求。

java 复制代码
package Theoretical_foundation.queue;

import java.util.LinkedList;

public class MyLinkedQueue<E> {
    private final LinkedList<E> queue = new LinkedList<>();

    public void push(E e) {
        queue.addLast(e);
    }

    public E pop() {
        return queue.removeFirst();
    }

    public E peek() {
        return queue.getFirst();
    }

    public int size() {
        return queue.size();
    }

    public static void main(String[] args) {
        MyLinkedQueue<Integer> queue = new MyLinkedQueue<>();
        queue.push(1);
        queue.push(2);
        queue.push(3);

        System.out.println(queue.peek()); // 1
        System.out.println(queue.pop()); // 1
        System.out.println(queue.pop()); // 2
        System.out.println(queue.peek()); // 3
    }
}

4 实现栈(用标准库的数组)

数组尾部增删元素的时间复杂度都是 O(1),符合栈的要求。

java 复制代码
package Theoretical_foundation.stack;

import java.util.ArrayList;

public class MyArrayStack<E> {
    private ArrayList<E> stack = new ArrayList<>();

    public void push(E e) {
        stack.add(e);
    }

    public E pop() {
        return stack.remove(stack.size() - 1);
    }

    public E peek() {
        return stack.get(stack.size() - 1);
    }

    public int size() {
        return stack.size();
    }

    public static void main(String[] args) {
        MyArrayStack<Integer> stack = new MyArrayStack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);

        System.out.println(stack.peek()); // 3
        System.out.println(stack.pop()); // 3
        System.out.println(stack.peek()); // 2
    }
}

5 实现队列(用之前实现的环形数组)

有了前文环形数组中实现的类CycleArray,用CycleArray作为底层数据结构实现队列就不难了,在CycleArray的头删、尾增元素的复杂度都是 O(1),符合队列 API 的要求。

java 复制代码
package Theoretical_foundation.queue;

import Theoretical_foundation.array.CycleArray;

public class MyCycleArrayQueue<E> {
    private CycleArray<E> queue = new CycleArray<>();

    public void push(E e) {
        queue.addLast(e);
    }

    public void pop() {
        queue.removeFirst();
    }

    public E peek() {
        return queue.getFirst();
    }

    public int size() {
        return queue.size();
    }

    public static void main(String[] args) {
        MyLinkedQueue<Integer> queue = new MyLinkedQueue<>();
        queue.push(1);
        queue.push(2);
        queue.push(3);

        System.out.println(queue.peek()); // 1
        System.out.println(queue.pop()); // 1
        System.out.println(queue.pop()); // 2
        System.out.println(queue.peek()); // 3
    }
}

6 双端队列

标准队列只能在队尾插入元素,队头删除元素,而双端队列的队头和队尾都可以插入或删除元素。

可以用链表、循环数组实现。

相关推荐
hold?fish:palm9 小时前
24 回文链表
数据结构·c++·链表
qeen8713 小时前
【数据结构】自平衡二叉搜索树各种旋转算法原理解析及AVL树的C++实现
数据结构·c++·算法
冻柠檬飞冰走茶14 小时前
PTA基础编程题目集 7-35有理数均值(C++语言实现)
开发语言·数据结构·c++·算法·均值算法
Nil20815 小时前
leetcode 189轮转数组
数据结构·算法·leetcode
依然鸣16 小时前
PTA团体程序设计天梯赛L1真题讲解L1-085-088
数据结构·c++·经验分享·算法·深度优先·pat考试
Brilliantwxx17 小时前
【算法从零到千】【51-54】逆序对(分治+递归算法)
数据结构·算法·排序算法
小星星闪亮登场17 小时前
2026河南萌新联赛第四场--南阳理工学院
数据结构·算法·贪心算法·动态规划·哈希算法·广度优先
土司大王17 小时前
LeetCode hot100——两数之和
数据结构·算法·leetcode
wabs66618 小时前
关于字符串【力扣344.反转字符串的思考】
数据结构·算法·leetcode
LuminousCPP18 小时前
数据结构基础篇(二):顺序表与链表全方位对比|从内存布局到 CPU 缓存理解底层差异
c语言·数据结构·经验分享·链表·缓存