Skip to content

队列与栈


队列

队列特点

队列是先进先出的数据结构,类似于排队

内部实现

直接用 java 内部的实现,其实内部就是双向链表 LinkedList,常数操作慢

java
public static class Queue1 {
    // java中的双向链表LinkedList
    // 单向链表就足够了
    public Queue<Integer> queue = new LinkedList<>();

    // 调用任何方法之前,先调用这个方法来判断队列内是否有东西
    public boolean isEmpty() {
        return queue.isEmpty();
    }

    // 向队列中加入num,加到尾巴
    public void offer(int num) {
        queue.offer(num);
    }

    // 从队列拿,从头拿
    public int poll() {
        return queue.poll();
    }

    // 返回队列头的元素但是不弹出
    public int peek() {
        return queue.peek();
    }

    // 返回目前队列里有几个数
    public int size() {
        return queue.size();
    }
}

数组实现

实际刷题时更常见的写法,常数时间好

如果可以确定加入操作的总次数不超过 n,那么可以用

一般笔试、面试都会有一个明确数据量,所以这是最常用的方式

采用双指针 l 和 r 操作元素,左闭右开 [ l , r ),l 指向队头,r 指向队尾的下一个位置

java
public static class Queue2 {
    public int[] queue;
    public int l;
    public int r;

    // 加入操作的总次数上限是多少,一定要明确
    public Queue2(int n) {
        queue = new int[n];
        l = 0;
        r = 0;
    }

    // 调用任何方法之前,先调用这个方法来判断队列内是否有东西
    public boolean isEmpty() {
        return l == r;
    }

    public void offer(int num) {
        queue[r++] = num;
    }

    public int poll() {
        return queue[l++];
    }

    public int head() {
        return queue[l];
    }

    // l...r-1 r
    // [l..r)
    public int tail() {
        return queue[r - 1];
    }

    public int size() {
        return r - l;
    }
}

循环队列

题目链接:https://leetcode.cn/problems/design-circular-queue/

利用双指针 l 和 r 操作元素(指向索引位置),如果到达末尾,就跳回 0,复用之前的位置实现循环利用

java
class MyCircularQueue {

    public int[] queue;

    public int l, r, size, limit;

    // 同时在队列里的数字个数,不要超过k
    public MyCircularQueue(int k) {
        queue = new int[k];
        l = r = size = 0;
        limit = k;
    }

    // 如果队列满了,什么也不做,返回false
    // 如果队列没满,加入value,返回true
    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        } else {
            queue[r] = value;
            // 如果 r 到了末尾,跳回 0,否则 r++
            r = r == limit - 1 ? 0 : (r + 1);
            size++;
            return true;
        }
    }

    // 如果队列空了,什么也不做,返回false
    // 如果队列没空,弹出头部的数字,返回true
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        } else {
            // 如果 l 到了末尾,跳回 0,否则 l++
            l = l == limit - 1 ? 0 : (l + 1);
            size--;
            return true;
        }
    }

    // 返回队列头部的数字(不弹出),如果没有数返回 -1
    public int Front() {
        if (isEmpty()) {
            return -1;
        } else {
            return queue[l];
        }
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        } else {
            // 在入队后 r++,求队尾元素需要反推一个位置
            int last = r == 0 ? (limit - 1) : (r - 1);
            return queue[last];
        }
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == limit;
    }
}

栈特点

栈是后进先出的数据结构,类似于弹夹

内部实现

java
// 直接用java内部的实现
// 其实就是动态数组,不过常数时间并不好
public static class Stack1 {

    public Stack<Integer> stack = new Stack<>();

    // 调用任何方法之前,先调用这个方法来判断栈内是否有东西
    public boolean isEmpty() {
        return stack.isEmpty();
    }

    public void push(int num) {
        stack.push(num);
    }

    public int pop() {
        return stack.pop();
    }

    public int peek() {
        return stack.peek();
    }

    public int size() {
        return stack.size();
    }
}

数组实现

实际刷题时更常见的写法,常数时间好

如果可以保证同时在栈里的元素个数不超过 n,那么可以用

也就是发生弹出操作之后,空间可以复用

一般笔试、面试都会有一个明确数据量,所以这是最常用的方式

size 充当计数的作用,同时也是指针,size 始终指向栈顶元素的下一个位置

java
public static class Stack2 {

    public int[] stack;
    public int size;

    // 同时在栈里的元素个数不会超过n
    public Stack2(int n) {
        stack = new int[n];
        size = 0;
    }

    // 调用任何方法之前,先调用这个方法来判断栈内是否有东西
    public boolean isEmpty() {
        return size == 0;
    }

    public void push(int num) {
        stack[size++] = num;
    }

    /*
        --size
      (1)弹出元素,size 先减一
      (2)size 减一后,size --> size - 1,而栈顶元素的下表索引是 size - 1,弹出栈顶元素
    */
    public int pop() {
        return stack[--size];
    }

    public int peek() {
        return stack[size - 1];
    }

    public int size() {
        return size;
    }
}