数据结构(二)队列和栈

目录

[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 双端队列

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

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

相关推荐
j_xxx404_1 天前
C++算法:一维/二维前缀和算法模板题
开发语言·数据结构·c++·算法
Book思议-1 天前
顺序表和链表核心差异与优缺点详解
java·数据结构·链表
whn19771 天前
在sqllog中排查达梦阻塞会话
数据结构
01二进制代码漫游日记1 天前
C/C++中的内存区域划分
c语言·jvm·数据结构·学习
xiaoye-duck1 天前
《算法题讲解指南:优选算法-链表》--51.两数相加,52.两两交换链表中的节点
数据结构·算法·链表
代码改善世界1 天前
【数据结构】八大排序算法详解(C语言实现)|插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、计数排序
c语言·数据结构·排序算法
2501_940315261 天前
98验证二叉搜索树
java·数据结构·算法
仰泳的熊猫1 天前
题目2266:蓝桥杯2015年第六届真题-打印大X
数据结构·c++·算法·蓝桥杯
cui_ruicheng1 天前
C++ 数据结构:AVL树原理与实现
数据结构·c++
小龙报1 天前
【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现
c语言·数据结构·c++·物联网·算法·链表·visualstudio