数据结构 之 队列(Queue)

​​​​​​​

🎉欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨

🎉感谢各位读者在百忙之中抽出时间来垂阅我的文章,我会尽我所能向的大家分享我的知识和经验📖

🎉希望我们在一篇篇的文章中能够共同进步!!!

🌈个人主页:AUGENSTERN_dc

🔥个人专栏:C语言 | Java | 数据结构

⭐个人格言:

一重山有一重山的错落,我有我的平仄

一笔锋有一笔锋的着墨,我有我的舍得

目录

1. 定义:

2. 队列的常用方法和模拟实现:

2.1 常用方法:

2.2 模拟实现:

 3. 队列的模拟实现源码:

4. 循环队列

4.1 模拟实现:

5. 双端队列:


1. 定义:

队列和栈类似,是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表;

进入队列的一端称为队尾,离开队列的一端称为队头

队列这个结构遵循先进先出的原则;

 在日常生活中,例如:

多人在网上对老师提交任务时,会将我们所提交的任务存放到一个队列中,然后队列将这些任务按照先进先出的顺序进行出队和入队的操作,老师看到的任务,也就会按照提交时间的先后来排序;
 

由上图可以看出Queue是一个接口,底层是由链表(LinkedList)实现的;

2. 队列的常用方法和模拟实现:

2.1 常用方法:

方法 作用
offer(E e) 将e进行入队操作
E poll()

将e进行出队列操作,并且返回e的值

E peek() 获取队头元素
int size() 获取队列的长度
boolean isEmpty() 判断队列是否为空

(在队列的模拟实现中,我们并不使用泛型,而是使用整形来代替泛型) 

以上就是队列的常用方法,接下来我们进行模拟实现:

2.2 模拟实现:

队列的底层是由链表来实现的,我们先创建一个My_Queue类:

public class My_Queue {
    public static class ListNode {
        ListNode next;      //节点的后继
        ListNode prev;      //节点的前驱
        int value;          //节点的值

        public ListNode() {
            //不带参数的构造方法
        }
        public ListNode(int value){
            //带一个参数的构造方法,将节点的值赋为value
            this.value = value;
        }
    }

    ListNode first;         //队头节点
    ListNode last;          //队尾节点
    int size = 0;           //队列长度
}

< 1 > offer方法:

offer方法是将指定元素插入到队列的队尾:

与之前的栈和顺序表不同,由于队列的底层是用链表实现的,故不需要判断队列是否满了;

// 入队列---向双向链表位置插入新节点
    public void offer(int e){
        ListNode newNode = new ListNode(e);     //实例化一个节点
        if(first == null){                      //若该队列为空
            first = newNode;                    //将队头和队尾都更新为newNode
            last = newNode;
        }else{                                  //若队列不为空
            last.next = newNode;                //将newNode赋值给队尾.next
            newNode.prev = last;                //将newNode的pre赋值为队尾
            last = newNode;                     //将队尾更新为newNode
        }
        last = newNode;                         //更新队尾
        size++;                                 //队列长度 +1
}

< 2 > poll方法:

poll方法是将队头的元素进行出队操作,并返回队头元素的值:

在进行该操作之前,我们需要判断队列是否为空,若为空,则需抛出异常:

异常代码如下:

public class QueueEmptyException extends RuntimeException {
    public QueueEmptyException () {
        super();
    }

    public QueueEmptyException (String str) {
        super(str);
    }
}

poll方法如下:

public int poll(){
        // 1. 队列为空
        // 2. 队列中只有一个元素----链表中只有一个节点---直接删除
        // 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        int value = 0;
        if(first == null){      //若为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行poll操作!!!");
        }else if(first == last){        //若只有一个节点,则直接删除该节点
            last = null;
            first = null;
        }else{
            value = first.value;        //将队头的元素赋值给value
            first = first.next;         //将队头更新为队头的下一个节点
            first.prev.next = null;
            first.prev = null;
        }
        size--;                         //将队列长度 -1
        return value;                   //返回队头的值
}

< 3 > peek方法:

peek方法是返回队头的节点的值:

// 获取队头元素---获取链表中第一个节点的值域
    public int peek(){
        if(first == null){      //若队列为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行peek操作!!!");
        }
        return first.value;     //返回队头的值
}

< 4 > size方法:

size方法是返回队列的长度:

public int size() {
        return size;        //返回队列的长度
}

< 5 > isEmpty方法:

isEmpty是判断队列是否为空:

public boolean isEmpty(){
        return first == null;       //返回队头是否为空 的值
}

 3. 队列的模拟实现源码:

public class My_Queue {
    public static class ListNode {
        ListNode next;      //节点的后继
        ListNode prev;      //节点的前驱
        int value;          //节点的值

        public ListNode() {
            //不带参数的构造方法
        }
        public ListNode(int value){
            //带一个参数的构造方法,将节点的值赋为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;                    //将队头和队尾都更新为newNode
            last = newNode;
        }else{                                  //若队列不为空
            last.next = newNode;                //将newNode赋值给队尾.next
            newNode.prev = last;                //将newNode的pre赋值为队尾
            last = newNode;                     //将队尾更新为newNode
        }
        last = newNode;                         //更新队尾
        size++;                                 //队列长度 +1
    }

    // 出队列---将双向链表第一个节点删除掉
    public int poll(){
        // 1. 队列为空
        // 2. 队列中只有一个元素----链表中只有一个节点---直接删除
        // 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        int value = 0;
        if(first == null){      //若为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行poll操作!!!");
        }else if(first == last){        //若只有一个节点,则直接删除该节点
            last = null;
            first = null;
        }else{
            value = first.value;        //将队头的元素赋值给value
            first = first.next;         //将队头更新为队头的下一个节点
            first.prev.next = null;
            first.prev = null;
        }
        size--;                         //将队列长度 -1
        return value;                   //返回队头的值
    }

    // 获取队头元素---获取链表中第一个节点的值域
    public int peek(){
        if(first == null){      //若队列为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行peek操作!!!");
        }
        return first.value;     //返回队头的值
    }

    public int size() {
        return size;        //返回队列的长度
    }

    public boolean isEmpty(){
        return first == null;       //返回队头是否为空 的值
    }
}

4. 循环队列

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。

4.1 模拟实现:

/*
    解题思路:
    1. 注意,循环队列底层空间大小是固定的
    2. 采用计数方式实现队列空或者满的判断
    3. 入队列时:队列可能满,往队尾插入,注意back在末尾特殊情况
    4. 出队列时:队列可能空,删除队头元素,注意front可能在队尾
    5. 获取队头注意空队列时返回-1
    6. 获取队尾时,注意back-1可能为负数,队尾元素下标:
       (back-1+array.length)%array.length
*/
class MyCircularQueue {
    int[] array;
    int front;   // 队头
    int back;    // 队尾
    int count;   // 队列中有效元素个数
    public MyCircularQueue(int k) {
        array = new int[k];
    }
    
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }

        // 在队尾插入一个元素,然后back往后移动
        array[back] = value;
        back++;

        // back往后移动之后,可能会来到空间末尾
        // 此时将back挪到空间起始位置
        if(back == array.length){
            back = 0;
        }

        count++;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }

        // 出队列,队头往后移动
        ++front;

        // 队头往后移动之后也可能会来到空间末尾
        // 此时需要挪到空间起始位置
        front %= array.length;
        --count;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }

        // 如果队列不空,说明队列中有元素,队头元素直接返回front即可
        return array[front];
    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }

        // 如果队列不空,说明队列中有元素
        // 队尾元素即:back-1,
        // 如果back不在0号位置,back-1就是队尾元素下标
        // 如果back在0号位置,-1之后就是负数,因此需要+数组长度
        // 两个结合起来:
        return array[(back - 1 + array.length)%array.length];
    }
    
    public boolean isEmpty() {
        return 0 == count;
    }
    
    public boolean isFull() {
        return count == array.length;
    }
}

5. 双端队列:

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

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

以上就是队列的全部内容:感谢观看!!!!

制作不易,三连支持

谢谢!!!

以上的模拟实现代码未必是最优解,仅代表本人的思路,望多多理解,谢谢!!

最后送给大家一句话,同时也是对我自己的勉励:

知不足而奋进,望远山而前行!!!!

相关推荐

  1. C++数据结构——队列queue

    2024-03-16 05:46:06       9 阅读
  2. 【Golang】实现简单队列(Queue)数据结构

    2024-03-16 05:46:06       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-16 05:46:06       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-16 05:46:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-16 05:46:06       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-16 05:46:06       20 阅读

热门阅读

  1. 13 list的实现

    2024-03-16 05:46:06       20 阅读
  2. 海外十大海外视频媒体推广网站-大舍传媒

    2024-03-16 05:46:06       16 阅读
  3. 如何高效使用ChatGPT技巧

    2024-03-16 05:46:06       19 阅读
  4. 视频和图像编码标准或格式的发展关系

    2024-03-16 05:46:06       19 阅读
  5. SpringMVC基础之简单程序应用

    2024-03-16 05:46:06       19 阅读
  6. 消费结构:倡导绿色低碳生活

    2024-03-16 05:46:06       23 阅读
  7. C语言经典面试题目(六)

    2024-03-16 05:46:06       21 阅读