java数据结构--双端队列

一.概念

  双端队列的意思是可以在头部和尾部添加和删除元素,更一般的单向链表队列比起来更加的灵活,下面我们用双向循环带哨兵链表和数组来分别实现

二.定义接口Dequeue

/*** 双端队列*/
public interface Dequeue<E> {//队头添加元素boolean offerTop(E e);//队尾添加元素boolean offerTail(E e);//队头取元素并删除该元素E pollTop();//队尾取元素并删除该元素E pollTail();//队头取元素E peekTop();//队尾取元素E peekTail();//是否为空boolean isEmpty();//是否为满boolean isFull();}

三.双向循环带哨兵链表链表实现

 1.图示

  

 

(1)向队头添加节点

(2)向队尾添加节点

 

 对于移除节点,和上面的类似,代码注释中也都做了解释,这里就不在展示了。

2.代码实现 

/*** 双向链表实现双端队列* @param <E>*/
public class LinkedDequeue<E> implements Dequeue<E> ,Iterable<E>{//内部节点类static class Node<E>{Node<E> pre;E value;Node<E> next;public Node(Node<E> pre,E value,Node<E> next){this.pre = pre;this.value = value;this.next = next;}}//容量int capacity;//队列中元素的个数int size;//哨兵Node<E> sentinel = new Node<>(null,null,null);//初始化public LinkedDequeue(int capacity){//初始化容量this.capacity = capacity;//开始时哨兵的下一个节点是本身sentinel.next = sentinel;//上一个节点也是本身sentinel.pre = sentinel;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {//获取第一个元素Node<E> p = sentinel.next;@Overridepublic boolean hasNext() {//如果p==sentinel就说明遍历完成了,没有下一个了return p != sentinel;}@Overridepublic E next() {E value = p.value;p = p.next;return value;}};}/*** 向头部添加节点*  a  -> added ->  b*     <-       <-*  a是哨兵, b是哨兵的下一个节点* @param e* @return*/@Overridepublic boolean offerTop(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.pre = added;size++;return true;}/*** 向尾部添加节点*a    -> added ->  b*       <-       <-* a是哨兵的上一个,b是哨兵** @param e* @return*/@Overridepublic boolean offerTail(E e) {if(isFull()){return false;}Node<E> b = sentinel;Node<E> a = sentinel.pre;Node<E> added = new Node<>(a,e,b);a.next = added;b.pre = added;size++;return true;}/*** 将头部节点移除* @return 头部元素的值** a removed b* a是哨兵,removed是哨兵的下一个,b是removed的下一个* a -> b*   <-*/@Overridepublic E pollTop() {if(isEmpty()){return null;}Node<E> a = sentinel;Node<E> removed = sentinel.next;Node<E> b = removed.next;a.next = b;b.pre = a;size--;return removed.value;}/*** 将尾部节点移除* @return 尾部元素的值** a removed b* b是哨兵,removed是b的上一个,a是removed的上一个* a -> b*   <-*/@Overridepublic E pollTail() {if(isEmpty()){return null;}Node<E> b = sentinel;Node<E> removed = sentinel.pre;Node<E> a = removed.pre;a.next = b;b.pre = a;size--;return removed.value;}/*** 获取第一个元素的值,但是不移除* @return*/@Overridepublic E peekTop() {if(isEmpty()){return null;}return sentinel.next.value;}/*** 获取最后一个元素的值,但是不移除* @return*/@Overridepublic E peekTail() {if(isEmpty()){return null;}return sentinel.pre.value;}@Overridepublic boolean isEmpty() {return  size == 0;}@Overridepublic boolean isFull() {return  size == capacity;}
}

四.数组带头尾指针实现

1.图示

(1)刚开始时head和tail都在同一位置,表示空

当在尾部tail添加元素时,先在tail处添加元素,然后让tail加一,

注意:这里的加一不是直接tail++,因为是循环队列,所以若到了array.length处,也就是末尾,下一次加一就要跑到索引0的位置了,一般我们之前是用的求余数运算来找到合法的索引位置,但是我们这里会用一个新的方式来运算索引

 (2)tail处添加元素

(3)head处添加元素

 我们在head处添加元素时,我们是让head先减一,然后再在head处添加,为啥呢?因为我们是循环数组,让head减一,相当于改变了头的位置,好像是在向左移动一样,向左扩展,

注意:这里的减一也是要算出合法的索引,而且如果head本来是在索引0处,那么head就要移动到array.length处,这样就好像是在向前移动

 对于头部尾部移除元素,都是类似的,在此不过多描述。

(4)代码实现

/*** 数组实现双端队列* @param <E>*/
public class ArrayDequeue<E> implements Dequeue<E>,Iterable<E>{E array[];//头指针int head;//尾指针int tail;@SuppressWarnings("all")public ArrayDequeue(int capacity){//实际容量要多空出一个来判断空满array = (E[]) new Object[capacity+1];}//加一方法public static int inc(int i,int length){if(i + 1 >= length){return 0;}return i + 1;}//减一方法public static int dec(int i,int length){if(i - 1 < 0){return  length - 1;}return i - 1;}/*** 头部添加元素** 先让head--,然后再在head处添加元素** @param e* @return*/@Overridepublic boolean offerTop(E e) {if(isFull()){return false;}head = dec(head,array.length);array[head] = e;return true;}/*** 在尾部添加依赖** 先在tail处添加元素,然后让tail++* @param e* @return*/@Overridepublic boolean offerTail(E e) {if(isFull()){return false;}array[tail] = e;tail = inc(tail,array.length);return true;}/*** 移除队头元素** 先获取head处元素,然后让head++** @return*/@Overridepublic E pollTop() {if(isEmpty()){return null;}E  e  =  array[head];array[head] = null; //help GChead = inc(head,array.length);return e;}/*** 移除队尾元素** 先让tail--,然后返回tail处的值** @return*/@Overridepublic E pollTail() {if(isEmpty()){return null;}tail = dec(tail,array.length);E e = array[tail];array[tail] = null; //help GCreturn e;}@Overridepublic E peekTop() {if(isEmpty()){return null;}return array[head];}@Overridepublic E peekTail() {if(isEmpty()){return null;}return array[dec(tail, array.length)];}/*** 判断是否为空* @return*/@Overridepublic boolean isEmpty() {return  head == tail;}/*** 判断是否为满* @return*/@Overridepublic boolean isFull() {//当 head > tail 时,/*** 需要判断 head - tail == 1*//*** 当 tail > head 时* 需要判断 tail - head == array.length - 1;*/if(head > tail){return head - tail == 1;}else if( head < tail){return  tail - head == array.length - 1;}else{return false;}}/*** 遍历* @return*/@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {int p = head;@Overridepublic boolean hasNext() {return p != tail;}@Overridepublic E next() {E e = array[p];p = inc(p,array.length);return e;}};}
}

五.及时释放元素

我们在之前的队列和栈的移除元素操作时,每次都是直接跳过元素,相当于移除了该元素,其实这里有误区:

1.如果元素类型为基本类型,比如Int类型,那么一个数字占四个字节,直接跳过和设置为0都占用内存空间,设置为0意义不大,所以直接跳过就可以了。

2.如果元素类型为引用类型,比如Student学生对象,那么如果你直接跳过该元素,其实他并没有被释放,也就是不能被GC回收,这时需要我们手动释放元素,我们可以让array[x]=null;来释放内存空间

另外说一点,在jdk中有一个类LinkedList,这个类可用当栈,也可以当队列,也实现了双端队列的功能

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT QStackedWidget

QStackedWidget是一个特殊的布局容器&#xff0c;它可以管理多个页面&#xff0c;并且只能显示其中一个页面。这些页面是QWidget或其派生类的实例&#xff0c;并通过调用addWidget()函数添加到堆栈中。 例如&#xff1a; #include <QWidgets> #include <QStackedWid…

10.(vue3.x+vite)组件间通信方式之props与$emit

前端技术社区总目录(订阅之前请先查看该博客) 示例效果 父组件代码 <template><div><div>{{message }}</div><Child

Scala爬虫实战:采集网易云音乐热门歌单数据

导言 网易云音乐是一个备受欢迎的音乐平台&#xff0c;汇集了丰富的音乐资源和热门歌单。这些歌单涵盖了各种音乐风格和主题&#xff0c;为音乐爱好者提供了一个探索和分享音乐的平台。然而&#xff0c;有时我们可能需要从网易云音乐上获取歌单数据&#xff0c;以进行音乐推荐…

【Azure 架构师学习笔记】-Azure Storage Account(5)- Data Lake layers

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Storage Account】系列。 接上文 【Azure 架构师学习笔记】-Azure Storage Account&#xff08;4&#xff09;- ADF 读取Queue Storage 前言 不管在云还是非云环境中&#xff0c; 存储是IT 系统的其中一个核心组件。在…

远程运维用什么软件?可以保障更安全?

远程运维顾名思义就是通过远程的方式IT设备等运行、维护。远程运维适用场景包含因疫情居家办公&#xff0c;包含放假期间出现运维故障远程解决&#xff0c;包含项目太远需要远程操作等等。但远程运维过程存在一定风险&#xff0c;安全性无法保障&#xff0c;所以一定要选择靠谱…

【紫光同创国产FPGA教程】——PDS安装教程

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 一&#xff1a;软件简介 PangoDesign Suite是紫光同创基于多年FPGA开发软件技术攻关与工程实践经验而研发的一款拥有国产自主知识产权的大规模FPGA开…

chinese-stable-diffusion中文场景文生图prompt测评集合

我在git上新建了一个仓库&#xff0c;主要是总结一波了chainese-stable-diffusion的模型算法&#xff0c;非常欢迎关注&#xff1a; GitHub - leeguandong/Awesome-Chinese-Stable-Diffusion: 中文文生图stable diffsion模型集合中文文生图stable diffsion模型集合. Contribute…

C语言:深入浅出qsort方法,编写自己的qsort完成冒泡排序

目录 什么是qsort&#xff1f; 函数原型 比较函数 compar 排序整型数组 排序结构体数组 根据成员字符排序 strcmp函数 根据成员整型排序 自定义qsort实现冒泡排序 qsort的实现原理 具体步骤 快速排序示例代码&#xff1a; 什么是qsort&#xff1f; qsort是 C …

[AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]

场景 在使用Android Studio的虚拟设备运行App时&#xff0c;需要创建很大镜像文件。这些镜像文件一般都在系统盘&#xff0c;导致系统盘占用增大。怎么把这些镜像的存放路径设置在其他盘&#xff1f; 说明 虚拟设备的和它的镜像默认是放在用户目录\.android\avd位置。如果是在…

深入OpenCV Android应用开发

前言 OpenCV是Open Source Computer Vision library(开源的计算机视觉库)的缩写。它是使用最广泛的计算机视觉库。Opencv是计算机视觉领域常用的操作函数的集合&#xff0c;其自身由C/C编写而成&#xff0c;同时也提供了对Python、Java以及任意JVM语言的封装。考虑到大部分And…

统信UOS_麒麟KYLINOS创建网页桌面快捷方式

原文链接&#xff1a;统信UOS/麒麟KYLINOS创建网页桌面快捷方式 hello&#xff0c;大家好啊&#xff0c;今天给大家带来一篇使用命令行在统信UOS/麒麟KYLINOS创建网页桌面快捷方式的文章&#xff0c;主要用于构建云桌面模板及镜像模板的时候使用&#xff0c;欢迎大家浏览分享转…

数据库数据恢复—无备份,未开启binlog的MySQL误删除怎么恢复数据

数据库数据恢复环境&#xff1a; 一台本地windows sever操作系统服务器&#xff0c;服务器上部署mysql数据库单实例&#xff0c;引擎类型为innodb&#xff0c;表内数据存储所使用表空间类型为独立表空间。无数据库备份&#xff0c;未开启binlog。 数据库故障&分析&#xf…

05预测识别-依托YOLO V8进行训练模型的识别——对视频中的目标进行跟踪统计

上文中详细介绍了如何对视频进行抽帧,并对帧的图像进行目标识别。但在日常工作中,我们也会遇到需要对目标进行跟踪统计的情况,比如我们需要连续统计某一类目标有多少个的时候,如果单纯从帧中抽取图像的话,系统将无法判断是否为同一目标,从而造成目标数量统计的重复,导致…

SpringBoot整合Swagger3,赶紧整起来!

文章目录 一、Swagger是什么&#xff1f;二、使用步骤1.引入swagger3依赖2.添加swagger.conf配置类3.添加application.yml配置4.查看是否整合成功5.常用注解6.swagger美化 总结 一、Swagger是什么&#xff1f; Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用…

12 tcp协议详解

1、tcp的本性 tcp是一个悲观者&#xff0c;生下来就不信任网络&#xff0c;任务会发生丢包等&#xff0c;所以要从算法层面来保证可靠性。 2、TCP 包头格式 tcp的包头格式比UDP要复杂的多。 1.源端口号和目标端口号是不可少的&#xff0c;这一点和 UDP 是一样的。如果没有…

图形界面应用案例——关灯游戏(以及扩展)(python)

7.8 图形界面应用案例——关灯游戏 题目: [案例]游戏初步——关灯游戏。 关灯游戏是很有意思的益智游戏,玩家通过单击关掉(或打开)一盏灯。如果关(掉(或打开)一个电灯,其周围(上下左右)的电灯也会触及开关,成功地关掉所有电灯即可过关。 图7-43 关灯游戏运行效…

安防监控系统视频融合平台EasyCVR页面地图功能细节详解

安防监控视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&#xff…

62、使用python进行rk3588开发板进行推流亚马逊云服务上,进行实时播放

基本思想:之前写了一套c++的推理和视频编解码,使用rk3588的mpp硬件进行编码和解码,然后使用RTSPServer进行推流,总是有问题,虽然可以使用ffplay和vlc进行拉取和播放,但是就是无法使用gstreamer推流到亚马逊云服务上,因为项目需求的紧急,所以先用python把流程跑同,后续…

linux基础指令【上篇】

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 引用 01. ls 指令2. pwd命…

FPGA的元素组件

注意&#xff1a;关于FPGA的元素这一块儿内容&#xff0c;稍有出入。例如&#xff1a;吉姆莱丁 著&#xff0c;陈会翔 译&#xff0c;由清华大学出版社出版的《构建高性能嵌入式系统》中提到&#xff1a;FPGA通常由查找表、触发器、块RAM、DSP切片、及其他功能元件等元素组成。…