数据结构-循环队列和循环双端队列的多角度实现

2024-04-22 23:36

本文主要是介绍数据结构-循环队列和循环双端队列的多角度实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 1. 循环队列的数组形式实现
      • 2. 循环队列的链表实现
      • 3. 循环双端队列的数组形式实现
      • 4. 循环双端队列的链表实现

在力扣的题面如下
在这里插入图片描述
在这里插入图片描述

1. 循环队列的数组形式实现

其实循环队列的数组形式只有下面要注意的点,只要掌握了下面的这几点,代码层面上就没有什么问题了

用数组模拟的思路跟循环单向队列是完全一致的,要记住下面的几个点

  • 1 . first 指向的是头元素的下标 , last 指向的是尾元素的下一个位置的下标
  • 2 . 在申请数组空间的时候要多申请一个空间的目的是,讲判断空与判断满的条件区分开
  • 判断空就是 first == last 判断满就是 "first的下一个" == last;
    
  • 3 . 在循环队列里面,如何++,如何–?
  • ++ : (first + 1) % len  ;  (last + 1) % len;
    
  • -- : (first - 1 + len) % len  ;  (last - 1 + len) % len
    
  • 4 . 元素的个数 size == (last - fist + len) % len;

下面是数组形式的实现代码

class MyCircularQueue {int[] elementData;int first;int last;public MyCircularQueue(int k) {elementData = new int[k + 1];}public boolean enQueue(int value) {if(isFull()){return false;}elementData[last] = value;last = (last + 1)%  elementData.length;return true;}public boolean deQueue() {if(isEmpty()){return false;}first = (first + 1)%elementData.length;return true;}public int Front() {if(isEmpty()){return -1;}return elementData[first];}public int Rear() {if(isEmpty()){return  -1;}int index = last == 0 ? elementData.length - 1 : last -1;return elementData[index];}public boolean isEmpty() {return last == first;}public boolean isFull() {return first == (last + 1)  % elementData.length;}
}/*** Your MyCircularQueue object will be instantiated and called as such:* MyCircularQueue obj = new MyCircularQueue(k);* boolean param_1 = obj.enQueue(value);* boolean param_2 = obj.deQueue();* int param_3 = obj.Front();* int param_4 = obj.Rear();* boolean param_5 = obj.isEmpty();* boolean param_6 = obj.isFull();*/

2. 循环队列的链表实现

鉴于单链表的尾巴节点每次都要寻找,所以为了简便,我们采用双向链表进行模拟,注意,这里我们对于链表节点的定义就是我们LinkedList中的源码形式,有空可以去看看我们LinkedList的底层源码,这里其实就是多了个size来标记我们的链表节点数量
代码实现如下


/*** 尝试用双向链表来模拟循环队列*/
public class CircleQueue {/*** 下面是根据原代码模拟的定义的节点类* @param <T>*/static class Node<T> {public T item;public Node<T> prev;public Node<T> next;public Node (Node<T> prev,T item,Node<T> next) {this.prev = prev;this.item = item;this.next = next;}}/*** 下面是所需要的基本结构*/private Node first;private Node last;private int size;private int capacity;public CircleQueue(int k) {this.size = 0;first = last = null;capacity = k;}public boolean enQueue(int value) {if(isFull()){return false;}Node<Integer> node = new Node<>(null,value,null);if(first == null && last == null){first = node;last = node;}else{last.next = node;node.prev = last;last = node;}this.size++;return true;}public boolean deQueue() {if(isEmpty()){return false;}if(last == first){last = first = null;}else{first = first.next;first.prev.next = null;first.prev.item = null;}this.size--;return true;}public int Front() {if(isEmpty()){return -1;}return (int)first.item;}public int Rear() {if(isEmpty()){return -1;}return (int)last.item;}public boolean isEmpty() {return first == null && last == null;}public boolean isFull() {return this.size == this.capacity;}
}

3. 循环双端队列的数组形式实现

用数组实现队列源码层面是我们的ArrayDeque这个类完成的,这里不再多说了,和我们的1.用数组实现循环队列是一致的

/*** 首先尝试是数组来模拟循环双端队列* 其次我们再用双向链表来尝试模拟一下循环双端队列* 用数组模拟的思路跟循环单向队列是完全一致的,要记住下面的几个点* 1 . first 指向的是头元素的下标 , last 指向的是尾元素的下一个位置的下标* 2 . 在申请数组空间的时候要多申请一个空间的目的是,讲判断空与判断满的条件区分开*     判断空就是 first == last 判断满就是 "first的下一个" == last;* 3 . 在循环队列里面,如何++,如何--?*     ++ : (first + 1) % len  ;  (last + 1) % len;*     -- : (first - 1 + len) % len  ;  (last - 1 + len) % len* 4 . size == (last - fist + len) % len;*/
class MyCircularDeque {int[] elementData;int first;int last;public MyCircularDeque(int k) {elementData = new int[k + 1];first = last = 0;}public boolean insertFront(int value) {if(isFull()){return false;}first = (first - 1 + elementData.length) % elementData.length;elementData[first] = value;return true;}public boolean insertLast(int value) {if(isFull()){return false;}elementData[last] = value;last = (last + 1) % elementData.length;return true;}public boolean deleteFront() {if(isEmpty()){return false;}first = (first + 1) % elementData.length;return true;}public boolean deleteLast() {if(isEmpty()){return false;}last = (last - 1 + elementData.length) % elementData.length;return true;}public int getFront() {if(isEmpty()){return -1;}return elementData[first];}public int getRear() {if(isEmpty()){return -1;}return elementData[(last - 1 + elementData.length) % elementData.length];}public boolean isEmpty() {return first == last;}public boolean isFull() {return (last + 1) % elementData.length == first;}
}

4. 循环双端队列的链表实现

其实就是比2.多了一个addFirst,和 removeLast
代码实现如下


/*** 下面我们尝试使用双向链表来模拟我们的循环双端队列*/
class MyCircularDequeUseLinkedList {static class Node<T> {Node<T> prev;T item;Node<T> next;public Node(Node<T> prev,T item,Node<T> next){this.prev = prev;this.item = item;this.next = next;}}private int size;private int capacity;private Node first;private Node last;public MyCircularDequeUseLinkedList(int k) {this.size = 0;last = first = null;this.capacity = k;}public boolean insertFront(int value) {if(isFull()){return false;}Node<Integer> node = new Node<>(null,value,null);if(isEmpty()){first = last = node;}else{node.next = first;first.prev = node;first = node;}size++;return true;}public boolean insertLast(int value) {if(isFull()){return false;}Node<Integer> node = new Node<>(null,value,null);if(isEmpty()){first = last = node;}else{last.next = node;node.prev = last;last = node;}size++;return true;}public boolean deleteFront() {if(isEmpty()){return false;}if(first == last){last = first = null;}else{first = first.next;first.prev.next = null;first.prev.item = null;first.prev = null;}size--;return true;}public boolean deleteLast() {if(isEmpty()){return false;}if(last == first){first = last = null;}else{last = last.prev;last.next.prev = null;last.next.item = null;last.next = null;}size--;return true;}public int getFront() {if(isEmpty()){return -1;}return (int)first.item;}public int getRear() {if(isEmpty()){return -1;}return (int)last.item;}public boolean isEmpty() {return first == null && last == null;}public boolean isFull() {return this.size == this.capacity;}
}

为什么不用单链表实现的原因其实是单链表每次想尾插都要走到最后一个位置,时间复杂度太高,有兴趣的话也可以自己模拟一下试试

这篇关于数据结构-循环队列和循环双端队列的多角度实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/927176

相关文章

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4