一、什么是队列
普通队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(FirstIn First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)
 
 双端队列:可以在对头或者队尾进行插入或者删除操作。
 
 普通队列和双端队列
 
 从上面知道双向列表可以当普通队列使用,也可以当双端队列使用,也可以当栈使用。
二、队列常用的方法
2.1、Queue

 注意add函数和offer函数
 
public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(1);//添加元素
        queue.add(2);//添加元素
        queue.add(3);//添加元素
        queue.offer(4);//添加元素
        queue.offer(5);//添加元素
        queue.offer(6);//添加元素
        System.out.println(queue.peek());//获取对头元素,但是不删除
        System.out.println(queue.element());//获取对头元素,但是不删除
        System.out.println(queue.poll());//获取对头元素,并且删除对头元素
        System.out.println(queue.remove());//获取对头元素,并且删除对头元素
    }
2.2、Deque

public static void main(String[] args) {
        Deque<Integer> deque = new LinkedList<>();
        deque.add(1);//默认在队尾添加元素
        deque.addFirst(2);//在对头添加元素
        deque.addLast(3);//在队尾添加元素
        deque.offer(4);//在队尾添加元素
        deque.offerLast(5);//在队尾添加元素
        deque.offerFirst(6);//在队头添加元素
        System.out.println(deque);
        System.out.println(deque.peek());//获取元素,但是不删除
        System.out.println(deque.peekFirst());//获取队头元素,但是不删除
        System.out.println(deque.peekLast());//获取队尾元素,但是不删除
        System.out.println(deque.poll());//获取队头元素,并且删除
        System.out.println(deque.pollFirst());//获取队头元素,并且删除
        System.out.println(deque);
    }
三、单链表模拟实现队列

 单链表可以实现队列,那双向链表也可以实现队列
 使用单链表第三种方式实现队列
 offer()- 在队列里面添加元素
/**
     * 在队列里面添加元素,实际上就是尾插法
     * @param val
     */
    public void offer(int val){
        //要插入节点,那就要先创造一个节点
        Node node = new Node(val);
        //这时候就要分两种情况:1、如果是第一次插入 2、不是第一次插入
        if(head == null){
            //head == null说明是第一次插入
            head = node;
            last = node;
        }else {
            last.next = node;
            last = last.next;
        }
    }

poll() - 出队列
/**
     * 出队列,并且删除元素
     * @return
     */
    public int poll(){
        //出队列就是删除头结点,但是如果链表里面没有节点那就不能删除
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        int oldVal = head.val;
        head = head.next;
        return oldVal;
    }
    /**
     * 判断队列是否为空,如果队列为空那就返回true,否则返回FALSE
     * @return
     */
    public boolean isEmpty(){
        return this.head == null;
    }
使用的单链表实现简单的队列
//使用单链表实现队列,首先就要定义节点
class Node{
    //值域
    public int val;
    //指针域
    public Node next;
    public Node(int val){
        this.val = val ;
    }
}
public class MyQueue {
    //单链表实现队列,那就要加上一个尾指针
    public Node head;//头结点
    public Node last;//尾巴节点
    /**
     * 在队列里面添加元素,实际上就是尾插法
     * @param val
     */
    public void offer(int val){
        //要插入节点,那就要先创造一个节点
        Node node = new Node(val);
        //这时候就要分两种情况:1、如果是第一次插入 2、不是第一次插入
        if(head == null){
            //head == null说明是第一次插入
            head = node;
            last = node;
        }else {
            last.next = node;
            last = last.next;
        }
    }
    /**
     * 出队列,并且删除元素
     * @return
     */
    public int poll(){
        //出队列就是删除头结点,但是如果链表里面没有节点那就不能删除
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        int oldVal = head.val;
        head = head.next;
        return oldVal;
    }
    /**
     * 判断队列是否为空,如果队列为空那就返回true,否则返回FALSE
     * @return
     */
    public boolean isEmpty(){
        return this.head == null;
    }
    /**
     * 获取对头的元素
     * @return
     */
    public int peek(){
        //出队列就是删除头结点,但是如果链表里面没有节点那就不能删除
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        return head.val;
    }
}
四、循环队列
我们说了可以利用链表实现队列,那能不能利用数组实现队列???
 
 上图转载于:https://blog.csdn.net/DarkAndGrey/article/details/122511544
队列面试题
设计循环队列

 
 上图转载于:https://blog.csdn.net/DarkAndGrey/article/details/122511544
代码如下:
public class MyCircularQueue {
    //我们知道循环队列是有数组实现的,所以要创建一个数组,并且还有表示对头和队尾的下标
    public int[] elem;
    public int front;//对头的下标
    public int rear;//队尾的下标
    /**
     * 构造方法,初始化数组的大小
     * @param k
     */
    public MyCircularQueue(int k) {
        this.elem = new int[k+1];
    }
    /**
     * 入队列
     * @param value
     * @return
     */
    public boolean enQueue(int value) {
        //在入队列的时候先判断队列是否满,满了不能入
        if(isFull()){
            return false;
        }
        elem[rear] = value;
        rear = (rear+1) % elem.length;
        return true;
    }
    /**
     * 出队列
     * @return
     */
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front = (front+1) % elem.length;
        return true;
    }
    /**
     * 返回对头下标的元素
     * @return
     */
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return elem[front];
    }
    /**
     * 获取队尾元素
     * @return
     */
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        int index = 0;
        if(rear == 0){
            index = elem.length - 1;
        }else{
            index = rear - 1;
        }
        return elem[index];
    }
    
    public boolean isEmpty() {
        //front的下一个是rear,那就说明空了
        return front == rear;
    }
    /**
     * 判断队列是否满
     * @return
     */
    public boolean isFull() {
        //rear的下一个如果是front,那这个队列就满了
        if((rear+1) % elem.length == front){
            return true;
        }
        return false;
    }
}
用队列实现栈

 
代码如下:
class MyStack {
    private Queue<Integer> qu1;
    private Queue<Integer> qu2;
    public MyStack() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    /**
     * 添加元素,将要添加的元素放入不为空的栈里面
     * @param x
     */
    public void push(int x) {
        if(!qu1.isEmpty()){
            //如果qu1不为空,那就插入元素
            qu1.offer(x);
        }else if(!qu2.isEmpty()){
            //如果qu2不为空,那就插入元素
            qu2.offer(x);
        }else{
            //第一次插入的时候,两个都为空的时候,那就指定队列插入元素
            qu1.offer(x);
        }
    }
    /**
     * 弹出元素
     * @return
     */
    public int pop() {
        if (empty()){
            return -1;
        }
        if(!qu1.isEmpty()){
            int size = qu1.size();
            for (int i = 0; i < size - 1; i++) {
                int val = qu1.poll();
                qu2.offer(val);
            }
            return qu1.poll();
        }
        if(!qu2.isEmpty()){
            int size = qu2.size();
            for (int i = 0; i < size - 1; i++) {
                int val = qu2.poll();
                qu1.offer(val);
            }
            return qu2.poll();
        }
        return -1;
    }
     public int top() {
        if (empty()){
            return -1;
        }
        if(!qu1.isEmpty()){
            int val = 0;
            //要记录这个size ,不然当出一个元素的时候这个函数都会变化,得到的值也会变化
            int size = qu1.size();
            for (int i = 0; i < size; i++) {
                val = qu1.poll();
                qu2.offer(val);
            }
            return val;
        }
        if(!qu2.isEmpty()){
            int val = 0;
            int size = qu2.size();
            for (int i = 0; i < size; i++) {
                val = qu2.poll();
                qu1.offer(val);
            }
            return val;
        }
        return -1;
    }
    public boolean empty() {
        return qu1.isEmpty() && qu2.isEmpty();
    }
}
用栈实现队列

 栈 的特性是:先进后出。也就是说第一个入栈的数据,将是最后一个出栈,我们利用两个栈来实现这题。
 
 代码如下:
class MyQueue {
    Stack<Integer> stack1;
    Stack<Integer> stack2;
    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }
    public void push(int x) {
        stack1.push(x);
    }
    public int pop() {
        if(stack2.isEmpty()){
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
    public int peek() {
        // 防止 别人一开始 就调用 peek,所以 peek 也需要 写 stack1 导入 stack2 的程序
        if(stack2.isEmpty()){
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }
    public boolean empty() {// 如果模拟的队列 将全部数据出队,那么 stack1 和 stack2 都为空
        return stack1.isEmpty() && stack2.isEmpty();
    }
}



















