【数据结构-队列】双端队列

news2024/12/23 13:18:07

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

      • 1.概述
      • 2.方法比较
      • 3.接口定义
      • 4.链表实现
      • 5.数组实现
    • 二.题目练习
      • 1.二叉树的锯齿形层序遍历-力扣 103 题
      • 2.设计双端队列-力扣 641 题

1.概述

双端队列、队列、栈对比

定义特点
队列一端删除(头)另一端添加(尾)First In First Out
一端删除和添加(顶)Last In First Out
双端队列两端都可以删除、添加
优先级队列优先级高者先出队
延时队列根据延时时间确定优先级
并发非阻塞队列队列空或满时不阻塞
并发阻塞队列队列空时删除阻塞、队列满时添加阻塞

2.方法比较

注 1:

  • Java 中 LinkedList 即为典型双端队列实现,不过它同时实现了 Queue 接口,也提供了栈的 push pop 等方法

注 2:

  • 不同语言,操作双端队列的方法命名有所不同,参见下表

    操作JavaJavaScriptC++leetCode 641
    尾部插入offerLastpushpush_backinsertLast
    头部插入offerFirstunshiftpush_frontinsertFront
    尾部移除pollLastpoppop_backdeleteLast
    头部移除pollFirstshiftpop_frontdeleteFront
    尾部获取peekLastat(-1)backgetRear
    头部获取peekFirstat(0)frontgetFront
  • 吐槽一下 leetCode 命名比较 low

  • 常见的单词还有 enqueue 入队、dequeue 出队

3.接口定义

public interface Deque<E> {

    boolean offerFirst(E e);

    boolean offerLast(E e);

    E pollFirst();

    E pollLast();

    E peekFirst();

    E peekLast();

    boolean isEmpty();

    boolean isFull();
}

4.链表实现

/**
 * 基于环形链表的双端队列
 * @param <E> 元素类型
 */
public class LinkedListDeque<E> implements Deque<E>, Iterable<E> {

    @Override
    public boolean offerFirst(E e) {
        if (isFull()) {
            return false;
        }
        size++;
        Node<E> a = sentinel;
        Node<E> b = sentinel.next;
        Node<E> offered = new Node<>(a, e, b);
        a.next = offered;
        b.prev = offered;
        return true;
    }

    @Override
    public boolean offerLast(E e) {
        if (isFull()) {
            return false;
        }
        size++;
        Node<E> a = sentinel.prev;
        Node<E> b = sentinel;
        Node<E> offered = new Node<>(a, e, b);
        a.next = offered;
        b.prev = offered;
        return true;
    }

    @Override
    public E pollFirst() {
        if (isEmpty()) {
            return null;
        }
        Node<E> a = sentinel;
        Node<E> polled = sentinel.next;
        Node<E> b = polled.next;
        a.next = b;
        b.prev = a;
        size--;
        return polled.value;
    }

    @Override
    public E pollLast() {
        if (isEmpty()) {
            return null;
        }
        Node<E> polled = sentinel.prev;
        Node<E> a = polled.prev;
        Node<E> b = sentinel;
        a.next = b;
        b.prev = a;
        size--;
        return polled.value;
    }

    @Override
    public E peekFirst() {
        if (isEmpty()) {
            return null;
        }
        return sentinel.next.value;
    }

    @Override
    public E peekLast() {
        if (isEmpty()) {
            return null;
        }
        return sentinel.prev.value;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == capacity;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> p = sentinel.next;
            @Override
            public boolean hasNext() {
                return p != sentinel;
            }

            @Override
            public E next() {
                E value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    static class Node<E> {
        Node<E> prev;
        E value;
        Node<E> next;

        public Node(Node<E> prev, E value, Node<E> next) {
            this.prev = prev;
            this.value = value;
            this.next = next;
        }
    }

    Node<E> sentinel = new Node<>(null, null, null);
    int capacity;
    int size;

    public LinkedListDeque(int capacity) {
        sentinel.next = sentinel;
        sentinel.prev = sentinel;
        this.capacity = capacity;
    }
}

5.数组实现

/**
 * 基于循环数组实现, 特点
 * <ul>
 *     <li>tail 停下来的位置不存储, 会浪费一个位置</li>
 * </ul>
 * @param <E>
 */
public class ArrayDeque1<E> implements Deque<E>, Iterable<E> {

    /*
                    h
            t
        0   1   2   3
        b           a
     */
    @Override
    public boolean offerFirst(E e) {
        if (isFull()) {
            return false;
        }
        head = dec(head, array.length);
        array[head] = e;
        return true;
    }

    @Override
    public boolean offerLast(E e) {
        if (isFull()) {
            return false;
        }
        array[tail] = e;
        tail = inc(tail, array.length);
        return true;
    }

    @Override
    public E pollFirst() {
        if (isEmpty()) {
            return null;
        }
        E e = array[head];
        array[head] = null;
        head = inc(head, array.length);
        return e;
    }

    @Override
    public E pollLast() {
        if (isEmpty()) {
            return null;
        }
        tail = dec(tail, array.length);
        E e = array[tail];
        array[tail] = null;
        return e;
    }

    @Override
    public E peekFirst() {
        if (isEmpty()) {
            return null;
        }
        return array[head];
    }

    @Override
    public E peekLast() {
        if (isEmpty()) {
            return null;
        }
        return array[dec(tail, array.length)];
    }

    @Override
    public boolean isEmpty() {
        return head == tail;
    }

    @Override
    public boolean isFull() {
        if (tail > head) {
            return tail - head == array.length - 1;
        } else if (tail < head) {
            return head - tail == 1;
        } else {
            return false;
        }
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = head;
            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public E next() {
                E e = array[p];
                p = inc(p, array.length);
                return e;
            }
        };
    }

    E[] array;
    int head;
    int tail;

    @SuppressWarnings("unchecked")
    public ArrayDeque1(int capacity) {
        array = (E[]) new Object[capacity + 1];
    }

    static int inc(int i, int length) {
        if (i + 1 >= length) {
            return 0;
        }
        return i + 1;
    }

    static int dec(int i, int length) {
        if (i - 1 < 0) {
            return length - 1;
        }
        return i - 1;
    }
}

数组实现中,如果存储的是基本类型,那么无需考虑内存释放,例如

image-20230110084245095

但如果存储的是引用类型,应当设置该位置的引用为 null,以便内存及时释放

image-20230110084632543

二.题目练习

1.二叉树的锯齿形层序遍历-力扣 103 题

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

image-20230908093831514

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]

题解:

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) {
        return result;
    }
    LinkedListQueue<TreeNode> queue = new LinkedListQueue<>();
    queue.offer(root);
    int c1 = 1; // 当前层节点数
    boolean odd = true; // 奇数层
    while (!queue.isEmpty()) {
        LinkedList<Integer> level = new LinkedList<>(); // 保存每一层结果
        int c2 = 0; // 下一层节点数
        for (int i = 0; i < c1; i++) {
            TreeNode n = queue.poll();
            if (odd) {
                level.offerLast(n.val);
            } else {
                level.offerFirst(n.val);
            }
            if (n.left != null) {
                queue.offer(n.left);
                c2++;
            }
            if (n.right != null) {
                queue.offer(n.right);
                c2++;
            }
        }
        odd = !odd;
        result.add(level);
        c1 = c2;
    }
    return result;
}

2.设计双端队列-力扣 641 题

public class LinkedListDeque<E> implements Deque<E>, Iterable<E> {

    @Override
    public boolean offerFirst(E e) {
        if (isFull()) {
            return false;
        }
        Node<E> a = sentinel;
        Node<E> b = sentinel.next;
        Node<E> added = new Node<>(a, e, b);
        a.next = added;
        b.prev = added;
        size++;
        return true;
    }

    @Override
    public boolean offerLast(E e) {
        if (isFull()) {
            return false;
        }
        Node<E> a = sentinel.prev;
        Node<E> b = sentinel;
        Node<E> added = new Node<>(a, e, b);
        a.next = added;
        b.prev = added;
        size++;
        return false;
    }

    // a  b
    @Override
    public E pollFirst() {
        if (isEmpty()) {
            return null;
        }
        Node<E> a = sentinel;
        Node<E> removed = sentinel.next;
        Node<E> b = removed.next;
        a.next = b;
        b.prev = a;
        size--;
        return removed.value;
    }

    // a  b
    @Override
    public E pollLast() {
        if (isEmpty()) {
            return null;
        }
        Node<E> b = sentinel;
        Node<E> removed = sentinel.prev;
        Node<E> a = removed.prev;
        a.next = b;
        b.prev = a;
        size--;
        return removed.value;
    }

    @Override
    public E peekFirst() {
        if (isEmpty()) {
            return null;
        }
        return sentinel.next.value;
    }

    @Override
    public E peekLast() {
        if (isEmpty()) {
            return null;
        }
        return sentinel.prev.value;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == capacity;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> p = sentinel.next;

            @Override
            public boolean hasNext() {
                return p != sentinel;
            }

            @Override
            public E next() {
                E value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    static class Node<E> {
        Node<E> prev;
        E value;
        Node<E> next;

        public Node(Node<E> prev, E value, Node<E> next) {
            this.prev = prev;
            this.value = value;
            this.next = next;
        }
    }

    int capacity;
    int size;
    Node<E> sentinel = new Node<>(null, null, null);

    public LinkedListDeque(int capacity) {
        this.capacity = capacity;
        sentinel.next = sentinel;
        sentinel.prev = sentinel;
    }
}

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/987999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【多线程】阻塞队列实现原理代码实现

目录 一、概念 二、优势 三、原理&#xff08;代码逐步实现&#xff09; 四、BlockingQueue的使用 一、概念 阻塞队列是一种的特殊的队列&#xff0c;他是带有阻塞的线程安全的队列。当队列已满时入队操作就会进入阻塞&#xff0c;当队列不空时才能执行入队操作&#xff1b…

抓安卓日志命令

临时生成logcat文件 ctrl z 是停止 adb logcat -> /home/log/log.txt 导出全部日志 adb root adb remount 只抓安卓日志 logcat &#xff08;所有保存的日志&#xff0c;中途关机和开机都有&#xff09; adb pull log/android D:\73log\1android 抓全部日志&#x…

《DevOps实践指南》- 读书笔记(四)

DevOps实践指南 Part 3 第一步 &#xff1a;流动的技术实践11. 应用和实践持续集成11.1 小批量开发与大批量合并11.2 应用基于主干的开发实践11.3 小结 12. 自动化和低风险发布12.1 自动化部署流程12.1.1 应用自动化的自助式部署12.1.2 在部署流水线中集成代码部署 12.2 将部署…

从零开始,手把手教你视频直播app源码开发

在今天移动互联网时代&#xff0c;视频直播成为了人们沟通、互动和分享的重要方式。如果你梦想着拥有自己的视频直播应用程序&#xff0c;那么现在是时候开始学习开发视频直播app的源码了&#xff01;本文将带您从零开始&#xff0c;手把手教你如何开发视频直播app源码&#xf…

数据通信网络之IPv6基础

文章及资源归档至公众号【AIShareLab】&#xff0c;回复 通信系统与网络 可获取。 文章目录 一、目的二、环境及网络拓扑三、需求四、步骤及结果分析 一、目的 掌握网络设备静态IPv6 地址配置的方法。掌握IPv6 地址无状态自动配置的应用。掌握通过DHCPv6 部署IPv6 地址配置自动…

inappropriate address 127.0.0.1 for the fudge command, line ignored 时间同步的时候报错

1、安装ntp服务后&#xff0c;启动ntpd正常&#xff0c;但是在查看ntpd服务状态时&#xff0c;有一个红色的报错&#xff0c;报错信息如下&#xff1a; inappropriate address 127.0.0.1 for the fudge command, line ignored 2、解决方法&#xff1a;编辑ntp配置文件&#xf…

群晖NAS:通过Docker 部署宝塔面板【注册表:cyberbolt/baota】

群晖NAS&#xff1a;通过 Docker 部署宝塔面板【注册表&#xff1a;pch18/baota】 由于 docker 源地址被墙&#xff0c;在面板里面查询不到注册表&#xff0c;使用 ssh 命令行拉取 1、打开 SSH&#xff0c;链接后打开命令行 这里不赘述&#xff0c;具体自行百度 2、下载 镜像…

51单片机的简易篮球计分器倒计时仿真设计( proteus仿真+程序+原理图+报告+讲解视频)

51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 1.主要功能&#xff1a;2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接 51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频…

代码随想录第33天 | ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

509. 斐波那契数 //法一&#xff1a; /*** param {number} n* return {number}*/ var fib function(n) {let bpnew Array(n)bp[0]0bp[1]1for(let i2;i<n;i){bp[i]bp[i-1]bp[i-2]}return bp[n] };//法二&#xff0c;时间少&#xff0c;空间少&#xff0c;只需要维护两个数值…

宝宝餐椅上亚马逊要求的合规标准有哪些?

宝宝餐椅上架亚马逊需要做什么认证&#xff1f; 大家都知道儿童餐椅是宝宝饮食的重要伙伴。它们为宝宝提供了一个舒适的环境&#xff0c;让宝宝在吃饭的时候更愉快&#xff0c;更健康。然而&#xff0c;许多家长可能不知道&#xff0c;亚马逊美国站售卖的儿童餐椅需要进行一系…

2023国赛数学建模E题思路代码 - 黄河水沙监测数据分析

# 1 赛题 E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响&#xff0c; 以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位…

HGDB-修改分区表名称及键值

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台&#xff1a;N/A 版本&#xff1a;4.5.7 文档用途 使用存储过程拼接SQL&#xff0c;修改分区名称、分区键值、并重新加入主表&#xff0c;适用于分区表较多场景。 详细信息 说明&#xff1a;本文档为测试过程&#xff1…

15 轮转数组

轮转数组 题解1 环状替换&#xff08;学习思想&#xff09;&#xff08;空间O(1)&#xff09;题解2 翻转数组&#xff08;有意思好理解&#xff09;&#xff08;空间O(1)&#xff09;题解3 空间O(N)秒答 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&a…

护眼台灯A级好还是AA级好?盘点五款AA级台灯

台灯如何选择&#xff0c;随着人们生活水平的提高及科技的不断进步&#xff0c;台灯的品质也得到了极大的提高&#xff0c;在生活中很多时候都需要使用台灯&#xff0c;但是市面上的台灯那么多&#xff0c;台灯如何选择 国aa级是对台灯的照度进行的一个很重要的划分&#xff0…

【2023集创赛】安谋科技杯全国一等奖分享:基于安路PH1A60的3D图形体感游戏机

本文为2023年第七届全国大学生集成电路创新创业大赛&#xff08;“集创赛”&#xff09;安谋科技杯全国一等奖作品分享&#xff0c;参加极术社区的【有奖征集】分享你的2023集创赛作品&#xff0c;秀出作品风采&#xff0c;分享2023集创赛作品扩大影响力&#xff0c;更有丰富电…

leetcode 215.数组中第k大的元素

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;数组中第k大的元素 思路&#xff1a; 使用堆数据结构&#xff0c;大堆的堆顶是堆内最大的元素&#xff0c;也就是把当前堆 pop k - 1 次&#xff0c;第 k 次 top 出来的元素就是第 k 大的数。 代码&#xff1a; class …

Python中的Pathlib

迷途小书童 读完需要 4分钟 速读仅需 2 分钟 大家好&#xff0c;我是迷途小书童&#xff01; 今天给大家介绍 Python 中的内置库 Pathlib。 pathlib 模块是 Python 3.4 中新增的标准库&#xff0c;它提供了面向对象的文件系统路径处理方法。pathlib 致力于解决直接操作文件路径…

宝塔Linux面板的安装配置

一、 宝塔Linux面板的功能 宝塔面板是一款服务器管理软件&#xff0c;可以帮助用户建立网站&#xff0c;一键配置服务器环境&#xff0c;使得用户通过web界面就可以轻松的管理安装所用的服务器软件。 二、宝塔Linux面板的安装 宝塔官网地址&#xff1a;https://www.bt.cn/new…

【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; list模拟实现 1. 前言2. list类的大致框架与结构…

开源协议对比:局限性、应注意事项与详细对比

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…