java-数据结构与算法-02-数据结构-04-队列

1. 概述

计算机科学中,queue 是以顺序的方式维护的一组数据集合,在一端添加数据,从另一端移除数据。习惯来说,添加的一端称为尾,移除的一端称为头,就如同生活中的排队买商品

先定义一个简化的队列接口

public interface Queue<E> {

    /**
     * 向队列尾插入值
     * @param value 待插入值
     * @return 插入成功返回 true, 插入失败返回 false
     */
    boolean offer(E value);

    /**
     * 从对列头获取值, 并移除
     * @return 如果队列非空返回对头值, 否则返回 null
     */
    E poll();

    /**
     * 从对列头获取值, 不移除
     * @return 如果队列非空返回对头值, 否则返回 null
     */
    E peek();

    /**
     * 检查队列是否为空
     * @return 空返回 true, 否则返回 false
     */
    boolean isEmpty();

    /**
     * 检查队列是否已满
     * @return 满返回 true, 否则返回 false
     */
    boolean isFull();
}

2. 链表实现

下面以单向环形带哨兵链表方式来实现队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

package com.itheima.datastructure.queue;

import java.util.Iterator;
import java.util.StringJoiner;

/**
 * 链表实现的队列。
 * 基于单向环形链表,支持先进先出(FIFO)的队列操作。
 * @param <E> 队列中元素的类型。
 */
public class LinkedListQueue<E>
        implements Queue<E>, Iterable<E> {

    /**
     * 链表节点。
     * 包含节点值和指向下一个节点的引用。
     */
    private static class Node<E> {
        E value;
        Node<E> next;

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 队列头部。
     * 永远指向空节点,简化队列操作。
     */
    private final Node<E> head = new Node<>(null, null);
    /**
     * 队列尾部。
     * 指向当前队列的最后一个元素。
     */
    private Node<E> tail = head;
    /**
     * 队列当前大小。
     */
    int size = 0;
    /**
     * 队列的最大容量。
     * 默认为Integer.MAX_VALUE,表示不限制容量。
     */
    private int capacity = Integer.MAX_VALUE;

    /**
     * 初始化队列。
     * 将尾部节点指向头部,形成环形链表。
     */
    {
        tail.next = head;
    }

    /**
     * 构造函数,创建一个空的链表队列。
     */
    public LinkedListQueue() {
    }

    /**
     * 构造函数,创建一个具有指定容量的链表队列。
     * @param capacity 队列的最大容量。
     */
    public LinkedListQueue(int capacity) {
        this.capacity = capacity;
    }

    /**
     * - **功能概述**:此方法向队列中添加一个元素。
     * - **检查条件**:首先判断队列是否达到最大容量,若已满,则直接返回`false`。
     * - **节点创建**:若未满,创建一个新的`Node`对象,其值为传入的参数`value`,并将新节点的`next`属性指向当前队列头节点。
     * - **插入操作**:将队列的尾节点的`next`属性指向新创建的节点,并更新队列的尾节点为新创建的节点。
     * - **更新状态**:增加队列的元素计数`size`。
     * - **返回结果**:返回`true`,表示元素添加成功。
     * @param value 要添加到队列的元素。
     * @return 如果添加成功,返回true;如果队列已满,返回false。
     */
    @Override
    public boolean offer(E value) {
        if (isFull)) {
            return false;
        }
        Node<E> added = new Node<>(value, head);
        tail.next = added;
        tail = added;
        size++;
        return true;
    }

    /**
     * 从队列中移除并返回头部的元素。
     * 如果队列为空,返回null。
     * @return 队列头部的元素,如果队列为空,返回null。
     */
    @Override
    public E poll() {
        if (isEmpty)) {
            return null;
        }
        Node<E> first = head.next;
        head.next = first.next;
        if (first == tail) {
            tail = head;
        }
        size--;
        return first.value;
    }

    /**
     * 返回队列头部的元素,但不移除。
     * 如果队列为空,返回null。
     * @return 队列头部的元素,如果队列为空,返回null。
     */
    @Override
    public E peek() {
        if (isEmpty)) {
            return null;
        }
        return head.next.value;
    }

    /**
     * 检查队列是否为空。
     * @return 如果队列为空,返回true;否则返回false。
     */
    @Override
    public boolean isEmpty() {
        return head == tail;
    }

    /**
     * 检查队列是否已满。
     * @return 如果队列已满,返回true;否则返回false。
     */
    @Override
    public boolean isFull() {
        return size == capacity;
    }

    /**
     * 返回队列元素的迭代器,按顺序遍历元素。
     * @return 队列元素的迭代器。
     */
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> p = head.next;

            @Override
            public boolean hasNext() {
                return p != head;
            }

            @Override
            public E next() {
                E value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    /**
     * 返回队列的字符串表示,元素用逗号分隔。
     * @return 队列的字符串表示。
     */
    @Override
    public String toString() {
        StringJoiner sj = new StringJoiner(",");
        for (E e : this) {
            sj.add(e.toString());
        }
        return sj.toString();
    }
}

3. 环形数组实现

好处

  1. 对比普通数组,起点和终点更为自由,不用考虑数据移动
  2. “环”意味着不会存在【越界】问题
  3. 数据性能更佳
  4. 环形数组比较适合实现有界队列、RingBuffer 等

在这里插入图片描述
下标计算

例如,数组长度是 5,当前位置是 3 ,向前走 2 步,此时下标为 ( 3 + 2 ) % 5 = 0 (3 + 2)\%5 = 0 (3+2)%5=0

在这里插入图片描述

  • cur 当前指针位置
  • step 前进步数
  • length 数组长度

注意: 如果 step = 1,也就是一次走一步,可以在 >= length 时重置为 0 即可

判断空

在这里插入图片描述
判断满

在这里插入图片描述
满之后的策略可以根据业务需求决定

  • 例如我们要实现的环形队列,满之后就拒绝入队

代码

package com.itheima.datastructure.queue;

import java.util.Iterator;

/**
 * 使用数组实现的队列,支持先进先出(FIFO)的特性。
 * 通过head和tail两个指针来标识队列的首尾位置,其中tail指向插入位置,head指向删除位置。
 * 队列的容量由数组的长度决定,为了简化队列满和空的判断,数组长度比实际存储容量多1。
 *
 * @param <E> 队列中元素的类型
 */
public class ArrayQueue1<E> implements Queue<E>, Iterable<E> {

    private final E[] array; // 存储队列元素的数组
    private int head = 0; // 队列头部的索引
    private int tail = 0; // 队列尾部的索引

    /**
     * 构造函数,初始化队列。
     * 
     * @param capacity 队列的容量
     */
    @SuppressWarnings("all")
    public ArrayQueue1(int capacity) {
        array = (E[]) new Object[capacity + 1];
    }

    /**
     * 将元素添加到队列尾部。
     * 此Java函数是`offer`方法的一个实现,用于向一个基于数组的循环队列中添加元素。下面是其功能的详细解析:
     *
     * 1. **参数**: 函数接受一个类型为`E`的参数`value`,`E`是泛型类型,意味着它可以是任何对象类型。
     *
     * 2. **检查队列是否已满**:
     *    - 调用`isFull()`方法来检查队列是否已经满了。如果队列已满(即没有剩余空间可以存储更多的元素),函数会立即返回`false`,表明无法添加新的元素。
     *
     * 3. **添加元素到队列**:
     *    - 如果队列未满,函数将`value`添加到队列的当前尾部位置,即`array[tail]`。
     *    - `array`是队列的底层数据结构,通常是一个固定大小的数组,用于存储队列中的所有元素。
     *
     * 4. **更新尾部指针**:
     *    - 在添加元素后,尾部指针`tail`需要更新,以指向队列中的下一个可插入位置。
     *    - 使用`(tail + 1) % array.length`计算新的`tail`值。这里使用模运算`%`是为了确保`tail`始终在数组的有效索引范围内,即使它超过了数组的最大索引,也会“循环”回数组的起始位置,从而实现循环队列的效果。
     *
     * 5. **返回结果**:
     *    - 最后,函数返回`true`,表明元素`value`已被成功添加到队列中。
     *
     * 总之,`offer`方法的主要目的是在不阻塞调用者的情况下尝试向队列中添加一个新元素。如果添加成功,返回`true`;如果队列已满,返回`false`。
     * @param value 要添加到队列的元素
     * @return 添加成功返回true,队列已满返回false
     */
    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        tail = (tail + 1) % array.length;
        return true;
    }

    /**
     * 从队列头部删除并返回元素。
     * 
     * @return 队列头部的元素,若队列为空返回null
     */
    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        E value = array[head];
        array[head] = null; // help GC
        head = (head + 1) % array.length;
        return value;
    }

    /**
     * 返回队列头部的元素,但不删除。
     * 
     * @return 队列头部的元素,若队列为空返回null
     */
    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head];
    }

    /**
     * 判断队列是否为空。
     * 
     * @return 队列为空返回true,否则返回false
     */
    @Override
    public boolean isEmpty() {
        return head == tail;
    }

    /**
     * 判断队列是否已满。
     * 
     * @return 队列已满返回true,否则返回false
     */
    @Override
    public boolean isFull() {
        return (tail + 1) % array.length == head;
    }

    /**
     * 返回队列元素的迭代器,用于遍历队列。
     * 
     * @return 队列元素的迭代器
     */
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = head; // 迭代器的当前位置

            /**
             * 判断是否还有下一个元素。
             * 
             * @return 还有下一个元素返回true,否则返回false
             */
            @Override
            public boolean hasNext() {
                return p != tail;
            }

            /**
             * 获取下一个元素。
             * 
             * @return 下一个元素
             */
            @Override
            public E next() {
                E value = array[p];
                p = (p + 1) % array.length;
                return value;
            }
        };
    }
}

判断空、满方法2

引入 size

public class ArrayQueue2<E> implements Queue<E>, Iterable<E> {

    private int head = 0;
    private int tail = 0;
    private final E[] array;
    private final int capacity;
    private int size = 0;

    @SuppressWarnings("all")
    public ArrayQueue2(int capacity) {
        this.capacity = capacity;
        array = (E[]) new Object[capacity];
    }

    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        tail = (tail + 1) % capacity;
        size++;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        E value = array[head];
        head = (head + 1) % capacity;
        size--;
        return value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head];
    }

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

    @Override
    public boolean isFull() {
        return size == capacity;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = head;

            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public E next() {
                E value = array[p];
                p = (p + 1) % capacity;
                return value;
            }
        };
    }
}

判断空、满方法3

  • head 和 tail 不断递增,用到索引时,再用它们进行计算,两个问题
    • 如何保证 head 和 tail 自增超过正整数最大值的正确性
    • 如何让取模运算性能更高
  • 答案:让 capacity 为 2 的幂
public class ArrayQueue3<E> implements Queue<E>, Iterable<E> {

    private int head = 0;
    private int tail = 0;
    private final E[] array;
    private final int capacity;

    @SuppressWarnings("all")
    public ArrayQueue3(int capacity) {
        if ((capacity & capacity - 1) != 0) {
            throw new IllegalArgumentException("capacity 必须为 2 的幂");
        }
        this.capacity = capacity;
        array = (E[]) new Object[this.capacity];
    }
    /**
     * 此Java函数`offer(E value)`主要负责向循环数组队列中添加元素。下面分点详细说明其功能:
     *
     * 1. **检查队列是否已满**:
     *    - 调用`isFull()`方法检查当前队列是否已达到其最大容量。如果是,则直接返回`false`,表示无法添加更多元素。
     *
     * 2. **计算尾部索引并插入元素**:
     *    - 使用位运算`tail & (array.length - 1)`来计算元素应插入的数组位置。这一步等价于`tail % array.length`,但位运算效率更高。
     *    - 将`value`赋值给`array`数组中计算出的位置,即在队列的“尾部”插入新元素。
     *
     * 3. **更新尾部指针**:
     *    - `tail++`操作使尾部指针向前移动一位,准备下一次插入操作。
     *
     * 4. **返回成功标志**:
     *    - 最后返回`true`,表明元素已成功添加至队列。
     *
     * ### 示例解析
     * 假设初始状态为:
     * - `head = 0`
     * - `tail = 3`
     * - `capacity = 3`
     * - 数组内容:`d, b, c`
     *
     * 调用`offer('x')`后:
     * - 首先检查队列未满(`isFull()`返回`false`)。
     * - 计算尾部索引:`3 & (3 - 1) = 0`,因此`'x'`将被插入到数组的第0个位置。
     * - 更新数组内容为:`'x', b, c`。
     * - `tail`更新为`4`,但由于数组长度为3,实际上指向的是下一个可插入位置0。
     * - 返回`true`,表示操作成功。
     * @param value 待插入值
     * @return
     */
    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail & capacity - 1] = value;
        tail++;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        E value = array[head & capacity - 1];
        head++;
        return value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head & capacity - 1];
    }

    @Override
    public boolean isEmpty() {
        return tail - head == 0;
    }

    @Override
    public boolean isFull() {
        return tail - head == capacity;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = head;

            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public E next() {
                E value = array[p & capacity - 1];
                p++;
                return value;
            }
        };
    }
}

4. 习题

E01. 二叉树层序遍历-Leetcode 102

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:

输入:root = [1]
输出:[[1]]
示例 3:

输入:root = []
输出:[]

提示:

树中节点数目在范围 [0, 2000] 内
-1000 <= Node.val <= 1000

图解:

在这里插入图片描述

代码:

package com.itheima.datastructure.queue;

import com.itheima.datastructure.binarytree.TreeNode;

import java.util.ArrayList;
import java.util.List;

/**
 * 二叉树层序遍历
 */
public class E01Leetcode102 {

    /**
     * 以层级顺序遍历二叉树,并返回每个层级的节点值列表。
     * <p>
     * 层级顺序遍历是指按照二叉树的层级从上到下,每层从左到右遍历节点。
     * 对于空树,返回空列表。
     *
     * @param root 二叉树的根节点
     * @return 每个层级的节点值列表组成的列表
     */
    /*
        [
            [1]
            [2,3]
            [4,5,6,7]
        ]
     */
    public List<List<Integer>> levelOrder(TreeNode root) {
        // 初始化结果列表
        List<List<Integer>> result = new ArrayList<>();
        // 如果根节点为空,直接返回空的结果列表
        if (root == null) {
            return result;
        }

        // 使用队列来进行层级遍历,这里使用了链表队列以支持高效插入和删除
        LinkedListQueue<TreeNode> queue = new LinkedListQueue<>();
        // 将根节点入队
        queue.offer(root);
        // c1 用于记录当前层的节点数量
        int c1 = 1; // 当前层节点数
        // 当队列不为空时,继续遍历
        int c2 = 0; // 下一层节点数
        while (!queue.isEmpty()) {
            // 初始化当前层的节点值列表
            List<Integer> level = new ArrayList<>(); // 保存每一层结果
            // c2 用于记录下一层的节点数量
            for (int i = 0; i < c1; i++) {
                // 出队一个节点,并将其值添加到当前层的列表中
                TreeNode n = queue.poll();
                level.add(n.val);
                // 如果节点有左子节点,将左子节点入队,并更新下一层的节点数量
                if (n.left != null) {
                    queue.offer(n.left);
                    c2++;
                }
                // 如果节点有右子节点,将右子节点入队,并更新下一层的节点数量
                if (n.right != null) {
                    queue.offer(n.right);
                    c2++;
                }
            }
            // 将当前层的节点值列表添加到结果列表中
            result.add(level);
            // 更新当前层的节点数量为下一层的节点数量,准备遍历下一层
            c1 = c2;
        }
        // 返回结果列表
        return result;
    }


    /*
                  1
                 / \
                2   3
               /\   /\
              4  5 6  7

              头 [] 尾

              1 2 3 4 5 6 7
     */
    public static void main(String[] args) {
        TreeNode root = new TreeNode(
                new TreeNode(
                        new TreeNode(4),
                        2,
                        new TreeNode(5)
                ),
                1,
                new TreeNode(
                        new TreeNode(6),
                        3,
                        new TreeNode(7)
                )
        );
        List<List<Integer>> lists = new E01Leetcode102().levelOrder(root);
        for (List<Integer> list : lists) {
            System.out.println(list);
        }
        /*LinkedListQueue<TreeNode> queue = new LinkedListQueue<>();
        queue.offer(root);
        int c1 = 1; // 当前层节点数
        while (!queue.isEmpty()) {
            int c2 = 0; // 下一层节点数
            for (int i = 0; i < c1; i++) {
                TreeNode n = queue.poll();
                System.out.print(n + " ");
                if (n.left != null) {
                    queue.offer(n.left);
                    c2++;
                }
                if (n.right != null) {
                    queue.offer(n.right);
                    c2++;
                }
            }
            System.out.println();
            c1 = c2;
        }*/
    }
}


/**
 * <h3>树节点类</h3>
 */
public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

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

    public TreeNode(TreeNode left, int val, TreeNode right) {
        this.left = left;
        this.val = val;
        this.right = right;
    }

    @Override
    public String toString() {
        return String.valueOf(this.val);
    }
}




Ex1. 设计队列-Leetcode 622

基于链表的实现队列

package com.itheima.datastructure.queue;

/**
 * 基于链表实现的队列。
 * 使用链表作为底层数据结构,支持入队和出队操作,以及查询队列的首尾元素。
 */
/**
 * 实现队列,基于链表
 */
public class Ex1Leetcode622 {

    /**
     * 链表节点。
     * 包含节点值和指向下一个节点的指针。
     */
    private static class Node {
        int value;
        Node next;

        Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 队列的头部。
     * 初始化为一个值为-1的节点,用于标记队列的开始。
     */
    private final Node head = new Node(-1, null);
    /**
     * 队列的尾部。
     * 随着元素的入队,尾指针会指向新的节点。
     */
    private Node tail = head;
    /**
     * 队列中元素的数量。
     * 用于快速判断队列是否为空。
     */
    private int size = 0;
    /**
     * 队列的容量。
     * 限制队列的最大元素数量。
     */
    private int capacity = 0;

    /**
     * 初始化队列。
     * 将尾指针的下一个节点设置为头部,确保队列的初始状态是正确的。
     */
    {
        tail.next = head;
    }

    /**
     * 入队操作。
     * 如果队列未满,将元素添加到队列尾部,并更新尾指针。
     *
     * @param value 要入队的元素值。
     * @return 如果入队成功,返回true;如果队列已满,返回false。
     */
    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        Node added = new Node(value, head);
        tail.next = added;
        tail = added;
        size++;
        return true;
    }

    /**
     * 出队操作。
     * 如果队列不为空,移除队列头部的元素,并更新头部指针。
     *
     * @return 如果出队成功,返回true;如果队列为空,返回false。
     */
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        Node first = head.next;
        head.next = first.next;
        if (first == tail) {
            tail = head;
        }
        size--;
        return true;
    }

    /**
     * 获取队列头部的元素值。
     *
     * @return 队列头部的元素值,如果队列为空,返回-1。
     */
    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return head.next.value;
    }

    /**
     * 获取队列尾部的元素值。
     *
     * @return 队列尾部的元素值,如果队列为空,返回-1。
     */
    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        return tail.value;
    }

    /**
     * 判断队列是否为空。
     *
     * @return 如果队列为空,返回true;否则返回false。
     */
    public boolean isEmpty() {
        return head == tail;
    }

    /**
     * 判断队列是否已满。
     *
     * @return 如果队列已满,返回true;否则返回false。
     */
    public boolean isFull() {
        return size == capacity;
    }
}

注意:

  • Leetcode 的实现里 deQueue(出队)返回值是布尔值,并不会返回队头元素
  • 它期望用法是先用 Front 返回对头元素,再 deQueue 出队

Ex2. 设计队列-Leetcode 622

基于数组实现队列

package com.itheima.datastructure.queue;

/**
 * 使用数组实现循环队列。
 * 循环队列是一种队列数据结构,其中队列的尾部追加元素,头部删除元素。
 * 使用数组实现循环队列,可以有效地利用空间,避免频繁地动态扩容。
 */
/**
 * 实现队列,基于数组
 */
public class Ex2Leetcode622 {

    public static void main(String[] args) {
        Ex2Leetcode622 queue = new Ex2Leetcode622(3);
        queue.enQueue(1);
        queue.enQueue(2);
        queue.enQueue(3);
        System.out.println(queue.Rear());
    }

    // 初始化头部和尾部指针,以及数组和数组长度。
    private int head = 0;
    private int tail = 0;
    private final int[] array;
    private final int length;

    /**
     * 构造函数初始化循环队列。
     * @param capacity 队列的容量,即可以存储的最大元素数量。
     *                 注意:实际数组长度为capacity+1,是为了处理队列满时的情况。
     */
    public Ex2Leetcode622(int capacity) {
        length = capacity + 1;
        array = new int[length];
    }

    /**
     * 向队列中添加元素。
     * @param value 要添加到队列的值。
     * @return 如果队列未满,则添加成功并返回true;否则,队列已满,添加失败,返回false。
     */
    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        tail = (tail + 1) % length;
        return true;
    }

    /**
     * 从队列中删除头部元素。
     * @return 如果队列不为空,则删除头部元素并返回true;否则,队列为空,删除失败,返回false。
     */
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head = (head + 1) % length;
        return true;
    }

    /**
     * 获取队列头部的元素。
     * @return 如果队列不为空,则返回队列头部的元素值;否则,队列为空,返回-1。
     */
    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return array[head];
    }

    /**
     * 获取队列尾部的元素。
     * @return 如果队列不为空,则返回队列尾部的元素值;否则,队列为空,返回-1。
     */
    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        return array[(tail - 1 + length) % length];
    }

    /**
     * 判断队列是否为空。
     * @return 如果队列为空,则返回true;否则,返回false。
     */
    public boolean isEmpty() {
        return head == tail;
    }

    /**
     * 判断队列是否已满。
     * @return 如果队列已满,则返回true;否则,返回false。
     */
    public boolean isFull() {
        return (tail + 1) % length == head;
    }
}

Ex3. 设计队列-Leetcode 622

实现队列,基于数组(未考虑正整数越界)

package com.itheima.datastructure.queue;

/**
 * 使用数组实现循环队列。
 * 循环队列是一种队列数据结构,其中队列的尾部能够追加到队列的头部,形成一个循环。
 * 这种实现方式利用了数组的性质,可以有效地利用空间,并且在操作上具有较高的效率。
 */
/**
 * 实现队列,基于数组(未考虑正整数越界)
 */
public class Ex3Leetcode622 {
    private int head = 0;
    private int tail = 0;
    private final int[] array;
    private final int capacity;

    /**
     * 初始化循环队列。
     * 
     * @param capacity 队列的容量,即队列能够存储的最大元素数量。
     */
    public Ex3Leetcode622(int capacity) {
        this.capacity = capacity;
        array = new int[this.capacity];
    }

    /**
     * 将元素添加到队列的尾部。
     * 
     * @param value 要添加到队列的值。
     * @return 如果队列未满,则返回true;否则返回false,表示队列已满无法添加元素。
     */
    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        array[tail++ % capacity] = value;
        return true;
    }

    /**
     * 从队列的头部移除一个元素。
     * 
     * @return 如果队列不为空,则返回true;否则返回false,表示队列为空无法移除元素。
     */
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head++;
        return true;
    }

    /**
     * 获取队列头部的元素。
     * 
     * @return 如果队列不为空,则返回队列头部的元素值;否则返回-1,表示队列为空。
     */
    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return array[head % capacity];
    }

    /**
     * 获取队列尾部的元素。
     * 
     * @return 如果队列不为空,则返回队列尾部的元素值;否则返回-1,表示队列为空。
     */
    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        return array[(tail - 1) % capacity];
    }

    /**
     * 检查队列是否为空。
     * 
     * @return 如果队列为空,则返回true;否则返回false。
     */
    public boolean isEmpty() {
        return head == tail;
    }

    /**
     * 检查队列是否已满。
     * 
     * @return 如果队列已满,则返回true;否则返回false。
     */
    public boolean isFull() {
        return tail - head == capacity;
    }
}


  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值