数据结构(二)队列和栈

目录

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

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

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

相关推荐
CSharp精选营1 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假4 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠5 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦12 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠13 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾13 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82113 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q13 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒13 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记13 天前
单项不带头不循环链表
数据结构·链表