队列(Queue)与双端队列 (Deque)

时间:2021-08-05 01:20:01

目录

1.队列(Queue)

1.1 概念

1.2 队列的使用 

1.3 队列模拟实现

 1.4 循环队列

 2. 双端队列 (Deque)


1.队列(Queue)

1.1 概念

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

1.2 队列的使用 

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

队列(Queue)与双端队列 (Deque)

队列(Queue)与双端队列 (Deque) 

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

 

public static void main(String[] args) {
    Queue<Integer> q = new LinkedList<>();
    q.offer(1);
    q.offer(2);
    q.offer(3);
    q.offer(4);
    q.offer(5); // 从队尾入队列
    System.out.println(q.size());
    System.out.println(q.peek()); // 获取队头元素
    q.poll();
    System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
    if(q.isEmpty()){
        System.out.println("队列空");
    }else{
        System.out.println(q.size());
    }
}

1.3 队列模拟实现

队列中既然可以存储元素,那底层肯定要有能够保存元素的空间,通过前面线性表的学习了解到常见的空间类型有两种:顺序结构 和 链式结构

队列(Queue)与双端队列 (Deque)

public class Queue {
    // 双向链表节点
    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){
            return null;
        }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){
            return null;
        }
        return first.value;
    }
    public int size() {
        return size;
    }
    public boolean isEmpty(){
        return first == null;
    }
}

 1.4 循环队列

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

队列(Queue)与双端队列 (Deque)

 

数组下标循环的小技巧
        1. 下标最后再往后 (offffset 小于 array.length): index = (index + offffset) % array.length

队列(Queue)与双端队列 (Deque)

        2. 下标最前再往前(offffset 小于 array.length): index = (index + array.length - offffset) % array.length 

队列(Queue)与双端队列 (Deque)

如何区分空与满

1. 通过添加 size 属性记录
2. 保留一个位置
3. 使用标记
队列(Queue)与双端队列 (Deque)

 2. 双端队列 (Deque)

 

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

队列(Queue)与双端队列 (Deque)

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

队列(Queue)与双端队列 (Deque)

 

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

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