【数据结构】队列(Queue)

目录

队列概念

​方法

队列模拟实现

链表实现队列

入队列

出队列

获取队头元素

数组实现队列

入队列

出队列

返回头队列

返回尾队列

完整代码

双链表实现队列

数组实现队列(设计循环队列)


队列概念

队列:只允许在一段进行插入数据操作,在另一端进行删除数据操作的特殊线性表

队列具有先进先出的特点,就像是排队一样,先排队的先出去。

入队列:进行插入操作的一段称为队尾。

出队列:进行删除操作的一段称为队头。

方法

方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

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

队列模拟实现

队列可以通过链表和数组实现

链表实现队列

这里实现队列采用的双向链表,所以定义一些基本变量如下,useSize记录队列中数据个数。

public class MyQueue {
    //双向链表实现
    static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val){
            this.val = val;
        }
    }

    public ListNode first = null; //队头
    public ListNode last = null;  //队尾
    public int useSize = 0;
}
入队列

offer方法

在往链表中放数据时,要考虑链表是否为空,当链表为空,队头和队尾都等于这个数据。

这时可以写一个isEmpty方法来判断,对于判断是否为空的条件,可以看useSize是否为0,也可以时first是否为0。

    public boolean isEmpty(){
        return useSize == 0;
        //return first == 0;
    }

当链表不为空时,这时实现的是尾插,所以offer方法完整部分为:

    public void offer(int val){
        ListNode node = new ListNode(val);
        if(isEmpty()){
            first = last = node;
        }else{
            last.next = node;
            node.prev = last;
            last = last.next;
        }
        useSize++;
    }
出队列

poll方法
出队列时也要考虑是否为空,用链表实现出队列要做的是把头节点往后挪一个位置。

当链表中只有一个节点,就没有必要再空置前一个结点了。

    public int poll(){
        if(isEmpty()){
            return -1;
        }
        int val = first.val;
        first = first.next;
        //一个节点,就没必要再置空前一个节点
        if(first != null){
            first.prev = null;
        }
        useSize--;
        return val;
    }
获取队头元素

peek方法

获取队头元素思路很清晰,只要返回first对应的值即可。也要进行是否为空的判断。

    public int peek(){
        if(isEmpty()){
            return -1;
        }
        return first.val;
    }

数组实现队列

这里主要做得是:设计循环队列,我们可以把循环队列设想成一个环,在一个有限的环里实现队列。设定front为头位置,rear为尾位置。

 判断数组是否为满有三种方法:

  1. 定义size
  2. 添加标记 定义boolean类型
  3. 浪费一个空间,即:确保一个空间里面不放元素,判断:rear下一个是不是front

这里我们采用的是最后一种方法:浪费一个空间。

不过还要解决一个问题: rear或者front 下标如何从 7位置 到 0位置?

对应的解决方案为:(rear +1)% 数组长度,front同理。

因为采用数组来实现循环队列,所以第一步是定义基础变量。

class MyCircularQueue {

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

因为需要浪费一个位置,所以申请 k+1个位置。 

入队列

enQueue方法

主要的思路是把数据放到rear位置,然后rear后移一个位置。

不过要考虑数组是否为满,这是可以写一个isFull方法。

判断的条件是:rear 的下一个位置 是否是 front

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

enQueue方法完整为下:

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

注意:rear后移一个位置不是rear++,而是(rear+1) % elem.length

出队列

deQueue方法

出队列的主要思路是:把front后移一个位置,前面的数据会被后面逐渐放进去的rear覆盖。

此时还要考虑数组是否为空,写一个isEmpty方法。判断条件是:front和rear是否相等。

    public boolean isEmpty() {
        return front == rear;
    }
    

出队列的完整代码为:

    //出队列
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front = (front+1) % elem.length;
        return true;
    }
返回头队列

Front方法

  • 判断是否为空
  • 返回front位置的数据
    //返回头队列
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return elem[front];
    }
    
返回尾队列

Rear方法

  • 判断是否为空
  • 判断rear 是否为 0

之所以要判断rear == 0,是因为当rear == 0时,返回的是elem.length - 1,而rear != 0时,返回rear - 1;

完整代码为:

    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        int index = (rear == 0) ? elem.length - 1 : rear-1;
        return elem[index];
    }

完整代码

双链表实现队列

public class MyQueue {
    //双向链表实现
    static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val){
            this.val = val;
        }
    }
    public ListNode first = null;
    public ListNode last = null;
    public int useSize = 0;

    public void offer(int val){
        ListNode node = new ListNode(val);
        if(isEmpty()){
            first = last = node;
        }else{
            last.next = node;
            node.prev = last;
            last = last.next;
        }
        useSize++;
    }

    public int poll(){
        if(isEmpty()){
            return -1;
        }
        int val = first.val;
        first = first.next;
        //一个节点,就没必要再置空前一个节点
        if(first != null){
            first.prev = null;
        }
        useSize--;
        return val;
    }

    public int peek(){
        if(isEmpty()){
            return -1;
        }
        return first.val;
    }

    public boolean isEmpty(){
        return useSize == 0;
        //return first == 0;
    }
}

数组实现队列(设计循环队列)

class MyCircularQueue {

    public int front;
    public int rear;
    public int[] elem;
    
    
    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;
    }
    
    //返回头队列
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return elem[front];
    }
    
    //返回尾队列
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        int index = (rear == 0) ? elem.length - 1 : rear-1;
        return elem[index];
    }
    
    public boolean isEmpty() {
        return front == rear;
    }
    
    public boolean isFull() {
        return (rear+1) % elem.length == front;
    }
}

评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值