队列(Queue)的顶级理解

目录

[1.队列(Queue) 的概念](#1.队列(Queue) 的概念)

2.单链表模拟实现队列

2.1创建队列

2.2入队列

2.3判断是否为空

2.4出队列

2.5获取队头元素

2.6完整代码:

2.7双向链表模拟实现队列代码

3.数组模拟实现队列代码

3.1创建队列

3.2判断是否为满

3.3检查是否为空

3.4插入元素

3.5删除元素

3.6从队首获取元素

[3.7 从队尾获取元素](#3.7 从队尾获取元素)

4.双端队列 (Deque)


1.队列**(Queue)的概念**

队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表, 队列具有先进先出 FIFO(First In First Out)
入队列:进行插入操作的一端称为 队尾( Tail/Rear )
出队列:进行删除操作的一端称为队头( Head/Front )

在Java中,Queue是个接口,底层是通过链表实现的。

队列在使用时有以下方法:

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

Queue<Integer> q = new LinkedList<>();


2.单链表模拟实现队列

2.1创建队列

代码:

java 复制代码
public class Myqueue {
    class Node{
        public int val;
        public Node next;
        public Node(int val){
            this.val=val;
        }
    }

    public Node head;
    public Node last;
    public int size;
}

2.2入队列

(1)创建一个节点node。

(2)判断该head是否为null,若为null,则该node就是head和last。

(3)若不为null,则 last.next=node, last=node;

(4)size++。

代码:

java 复制代码
    public void offer(int val){
        Node node = new Node(val);
        if(head==null){
            head=node;
            last=node;
        }else{
            last.next=node;
            last=node;
        }
        size++;
    }

2.3判断是否为空

java 复制代码
 public boolean empty(){
        return size==0;
    }

2.4出队列

(1)队列为空,则直接返回队列为空的异常。

自定义异常如下:

java 复制代码
public class EmptyException extends RuntimeException{
    public EmptyException(String message) {
        super(message);
    }
}

(2)队列为空不为,先ret=head.val,后删除头结点。

(3)size--;

代码:

java 复制代码
public int poll(){
        if(empty()){
            throw new EmptyException("队列为空");
        }
        int ret=head.val;
        head=head.next;
        size--;
        return ret;
    }

2.5获取队头元素

代码:

java 复制代码
public int peek(){
        if(empty()){
            throw new EmptyException("队列为空");
        }
        int ret=head.val;
        return ret;
    }

2.6完整代码:

java 复制代码
public class Myqueue {
    class Node{
        public int val;
        public Node next;
        public Node(int val){
            this.val=val;
        }
    }

    public Node head;
    public Node last;
    public int size;

    public void offer(int val){
        Node node = new Node(val);
        if(head==null){
            head=node;
            last=node;
        }else{
            last.next=node;
            last=node;
        }
        size++;
    }
    public int poll(){
        if(empty()){
            throw new EmptyException("队列为空");
        }
        int ret=head.val;
        head=head.next;
        size--;
        return ret;
    }
    public boolean empty(){
        return size==0;
    }
    public int peek(){
        if(empty()){
            throw new EmptyException("队列为空");
        }
        int ret=head.val;
        return ret;
    }
}

2.7双向链表模拟实现队列代码

java 复制代码
public class MyQueue {
    // 双向链表节点
    public static class ListNode {
        ListNode next;
        ListNode prev;
        int value;

        ListNode(int value) {
            this.value = value;
        }
    }

    ListNode first; // 队头
    ListNode last; // 队尾
    int size = 0;

    // 入队列---向双向链表位置插入新节点
    public void offer(int e) {
        ListNode newNode = new ListNode(e);
        if (first == null) {
            first = newNode;
// last = newNode;
        } else {
            last.next = newNode;
            newNode.prev = last;
// last = newNode;
        }
        last = newNode;
        size++;
    }

    // 出队列---将双向链表第一个节点删除掉
    public int poll() {
// 1. 队列为空
// 2. 队列中只有一个元素----链表中只有一个节点---直接删除
// 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        int value = 0;
        if (first == null) {
            throw new EmptyException("队列为空");
        } else if (first == last) {
            last = null;
            first = null;
        } else {
            value = first.value;
            first = first.next;
            first.prev.next = null;
            first.prev = null;
        }
        --size;
        return value;
    }

    // 获取队头元素---获取链表中第一个节点的值域
    public int peek() {
        if (first == null) {
            throw new EmptyException("队列为空");
        }
        return first.value;
    }
    public int size() {
        return size;
    }
    public boolean isEmpty(){
        return first == null;
    }
}

3.数组模拟实现队列代码

实际中我们有时还会使用一种队列叫循环队列,环形队列通常使用数组实现。

循环队列https://leetcode.cn/problems/design-circular-queue/description/描述:

要解决循环队列的有如下几个难题:

(1)数组的下标如何实现循环

rear=(rear+1)%elem.length

front=(front+1)%elem.length

(2)区分空与满

有三个方法:

  1. 通过添加 size 属性记录

  2. 保留一个位置

  3. 使用标记

本博主采用第二个方法,如下图所示:

3.1创建队列

由于我们需要浪费一个空间来判断是否为满,在构造方法时多构造一个空间。

java 复制代码
class MyCircularQueue {
    private int[] elem;
    private int front;//表示队列的头
    private int rear;//表示队列的尾

    public MyCircularQueue(int k) {
     this.elem=new int[k+1];
    }
}

3.2判断是否为满

java 复制代码
 public boolean isFull() {
        return (rear+1)%elem.length==front;
    }

3.3检查是否为空

java 复制代码
public boolean isEmpty() {
        return rear == front;
    }

3.4插入元素

(1)判断是否为满,若为满。返回false

(2)若不为满,则在elem下标为rear处插入该元素

(3)队尾向后走一步rear=(rear+1)%elem.length,返回true;

java 复制代码
public boolean enQueue(int value) {
     if(isFull()){
         return false;
     }
     elem[rear]=value;
     rear=(rear+1)%elem.length;
     return true;
    }

3.5删除元素

判断是否为null

(1)若为null。返回false

(2)若不为null,队首向后走一步 front = (front+1)%elem.length;,返回true;

java 复制代码
    public boolean deQueue() {
        if (isEmpty()){
            return false;
        }
        front = (front+1)%elem.length;
        return true;
    }

3.6从队首获取元素

java 复制代码
   public int Front(){
        if(isEmpty()){
            return -1;
        }
        return elem[front];
    }

3.7 从队尾获取元素

(1)如果队列为空,返回-1

(2)不为空,如果为队尾下标为0,返回下elemelem.length-1的值

(3)下标不为0,返回数组下标为rear-1的值

java 复制代码
  public int Rear() {
        if(isEmpty() ) {
            return -1;
        }
        if(rear == 0) {
            return elem[elem.length-1];
        }
        return elem[rear-1];
    }

3.8完整代码

java 复制代码
class MyCircularQueue {
    private int[] elem;
    private int front;//表示队列的头
    private int rear;//表示队列的尾

    public MyCircularQueue(int k) {
        this.elem = new int[k + 1];
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        elem[rear] = value;
        rear = (rear + 1) % elem.length;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()){
            return false;
        }
        front = (front+1)%elem.length;
        return true;
    }

    //从队首获取元素。如果队列为空,返回 -1 。
    public int Front() {
        if(isEmpty() ) {
            return -1;
        }
        return elem[front];
    }


    //从队尾获取元素。如果队列为空,返回 -1 。
    public int Rear() {
        if(isEmpty() ) {
            return -1;
        }
        if(rear == 0) {
            return elem[elem.length-1];
        }
        return elem[rear-1];
    }


    //检查循环队列是否为空。
    public boolean isEmpty() {
        return rear == front;
    }


    public boolean isFull() {
        return (rear + 1) % elem.length == front;
    }
}

4.双端队列 (Deque)

双端队列( deque )是 指允许两端都可以进行入队和出队操作的队列 , deque 是 "double ended queue" 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

Deque是一个接口,使用时必须创建LinkedList的对象。

在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口

java 复制代码
Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

以上为我个人的小分享,如有问题,欢迎讨论!!!

都看到这了,不如关注一下,给个免费的赞

相关推荐
中云DDoS CC防护蔡蔡6 小时前
DDOS和CC攻击谁更可怕
运维·服务器·经验分享·网络安全·ddos
2301_780789666 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
第九序言T6 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
m0_639906946 小时前
Redis入门|五种数据结构、使用场景、持久化RDB&AOF
数据结构·数据库·redis
学长毕设7 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
上海广测检测科技有限公司7 小时前
蓝牙音箱的 BQB 认证:音频服务层组合、引用链判定与测试状态设定
经验分享
步行cgn7 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川8 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵8 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
程序喵大人8 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型