队列(Java详解)

目录

队列

队列实现

双向链表实现

数组实现循环队列

双端队列(Deque)

两个例题

用队列实现栈

用栈实现队列


队列

特点: 先进先出的结构

和现实生活中 排队 的情况类似

队列实现

队列中的方法

双向链表实现

初始化

    static class ListNode {
        public int val;
        public ListNode next;
        public ListNode prev;
        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head;
    public ListNode last;
    public int usedSize = 0;

入队列

    @Override
    public boolean offer(int val) {
        ListNode node = new ListNode(val);
        if(head == null) {
            head = node;
            last = node;
        }else {
            last.next = node;
            node.prev = last;
            last = last.next;
        }
        usedSize++;
        return true;
    }

出队列

    @Override
    public int poll() {
        if(head == null) {
            return -1;
        }
        int retVal = head.val;
        if (head.next == null) {

            head = null;
            last = null;
            return retVal;
        }
        head = head.next;
        head.prev = null;
        return retVal;
    }

获取队头元素但不删除

    @Override
    public int peek() {
        if(head == null) {
            return -1;
        }
        if (head.next == null) {
            int retVal = head.val;
            head = null;
            last = null;
            return retVal;
        }
        return head.val;
    }

获取有效元素个数

    @Override
    public int size() {
        return usedSize;
    }

检测队列是否为空

    @Override
    public boolean isEmpty() {
        return head == null;
    }

注意

1> 使用双向链表实现队列.

2> 在入队时判断是否队列为空.

3> 出队时先判断是否队列为空, 然后判断是否只有头结点.

数组实现循环队列

什么是循环队列?

我们使用数组来实现队列

现在队列满了之后, 我们可以出队列, 出去一个就让front++.

这种情况下入队列时rear++, 会数组越界, 我们选择让rear重新回到起点

这样就构成了一个循环, 不但rear这样, 让front也这样.这样可以用数组实现一个队列

如下图:

接下来解决其他问题:

1> 当rear 和 front 相遇时是什么情况? 队列是满的还是空的?

有多种方案:

1. 使用 usedSize 记录

2. 浪费一个空间表示满 (rear里面放数据时判断下一个值是不是front)

3. 使用标记  (第一次相遇标记一下,第二次标记一下)

2> 怎么让rear 和 front 从 7 下标来到 0 下标?

使用 % 的方法

package queuedemo;

public class MyCircularQueue implements IQueue {
    private int[] elem;
    private int front = 0;   // 对头
    private int rear = 0;    // 队尾
    public MyCircularQueue(int k) {
        this.elem = new int[k+1];
    }

    @Override
    public boolean offer(int x) {
        if(isFull()) {
            return false;
        }else {
            elem[rear] = x;
            rear = (rear+1)%elem.length;
            return true;
        }
    }

    @Override
    public int poll() {
        if(isEmpty()) {
            return -1;
        }else {
            int old = elem[front];
            front = (front+1)%elem.length;
            return old;
        }
    }

    @Override
    public int peek() {
        if(isEmpty()) {
            return -1;
        }
        return elem[front];
    }

    @Override
    public int size() {
        return (rear-front);
    }

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

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

双端队列(Deque)

 在队列两边都可以进行入队和出队的操作

Deque 是一个接口.

        Deque<Integer> deque = new ArrayDeque<>();
        Deque<Integer> deque1 = new LinkedList<>();

其中有很多方法: 从头删除元素, 从队尾删除元素...

这俩结构不仅可以当作队列, 还可以当作栈.

两个例题

用队列实现栈

需要用两个队列

1> 哪个队列不为空放到哪个队列中

2> 出栈的时候那个不为空出哪个 size-1

3> 当两个队列都是空的时候, 说明模拟栈是空的

代码实现:

import java.util.LinkedList;
import java.util.Queue;

public class MyStack {
    private Queue<Integer> qu1;
    private Queue<Integer> qu2;
    public MyStack() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    public void push(int x) {
        if(!qu1.isEmpty()) {
            qu1.offer(x);
        }else if (!qu2.isEmpty()) {
            qu2.offer(x);
        }else {
            qu1.offer(x);
        }
    }
    public int pop() {
        if(empty()) {
            return -1;
        }
        // 判断是否为空
        if(!qu1.isEmpty()) {
            // 注意 size 是会变的, 所以创建一个变量放在外面
            int size = qu1.size()-1;
            for(int i = 0; i < size; i++) {
                int x = qu1.poll();
                qu2.offer(x);
            }
            return qu1.poll();
        } else {
            int size = qu2.size()-1;
            for(int i = 0; i < size; i++) {
                int x = qu2.poll();
                qu1.offer(x);
            }
            return qu2.poll();
        }
    }
    public int top() {
        if(empty()) {
            return -1;
        }
        if(!qu1.isEmpty()) {
            int size = qu1.size()-1;
            for(int i = 0; i < size; i++) {
                int x = qu1.poll();
                qu2.offer(x);
            }
            int tmp = qu1.poll();
            qu2.offer(tmp);
            return tmp;
        } else {
            int size = qu2.size()-1;
            for(int i = 0; i < size; i++) {
                int x = qu2.poll();
                qu1.offer(x);
            }
            int tmp = qu2.poll();
            qu1.offer(tmp);
            return tmp;
        }
    }
    // 两个队列都为空时, 模拟实现的栈是空的
    public boolean empty() {
        return qu1.isEmpty() && qu2.isEmpty();
    }
}

用栈实现队列

1> 入队的时候放到第一个栈里面

2> 出队的时候出第 2 个栈中的元素, 当第 2 个栈中没有元素时把第一个栈中的元素倒过来

import java.util.Stack;

public class MyQueue {
    private Stack<Integer> s1;
    private Stack<Integer> s2;
    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    public void push(int x) {
        s1.push(x);
    }
    public int pop() {
        if(empty()) {
            return -1;
        }
        if(!s2.isEmpty()) {
            return s2.pop();
        }
        while(!s1.isEmpty()) {
            int x = s1.pop();
            s2.push(x);
        }
        return s2.pop();
    }
    public int peek() {
        if(empty()) {
            return -1;
        }
        if(!s2.isEmpty()) {
            return s2.peek();
        }
        while(!s1.isEmpty()) {
            int x = s1.pop();
            s2.push(x);
        }
        return s2.peek();
    }
    public boolean empty() {
        return s1.isEmpty() && s2.isEmpty();
    }
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值