队列之Java实现循环队列

一、定义

  什么是队列?队列(queue)又叫先进先出表,它是一种运算受限的线性表。其限制是只允许在表的一端进行插入数据和另一端取数据。插入数据的一端是队尾,取数据的一端是队头。

  队列的数据结构:数组或者链表实现

  队列的常用场景:生产者生产数据放入队列缓存,消费者去消费数据。

二、循环队列

  普通的队列往其中添加元素,队头指针和队尾指针分别指向队头和队尾,当队列中元素出队之后,队头指针和队尾指针指在了队尾,此时再有元素进来时会发生假溢出的情况。为此循环队列进行弥补。循环队列是指队头和队尾相连的队列,接下来我们用图来说明入队和出队整个过程。

  假设循环队列总容量为N,并且预留一个空的位置作为队列空,满,长度判断标志:

   队列空:front==rear;

   队列满:(rear+1)%N==front;

   队列元素个数:(rear – front + N)%N

 三、队列的算法实现

   通过上面的分析,队列的操作:队列大小,入队(队尾),出队(队头)

public class Queue<E> {
    Node<E> front; //始终指向
    Node<E> head; //队头
    Node<E> tail; //队尾
    int QUEUE_SIZE; //模拟队列初始化大小
    static final int DEFAULT_QUEUE_SIZE = 5; //设置默认队列大小

    public Queue(){
        this(DEFAULT_QUEUE_SIZE);
    }
    public Queue(int queueSize){
        QUEUE_SIZE = queueSize + 1; //因为要空出一个节点,所以这里加1
        checkQueueSize();
    }

    /**
     * 入队,从队尾添加元素
     */
    public boolean push(E e){
        if (head == tail) {
            Node<E> node = new Node(e,0, null); //入队,第一个节点
            front = head = node; //更新队头
            Node<E> rear = new Node(null, head.index + 1, null); //队尾
            node.next = rear; //下一个节点是空队尾
            tail = rear; //更新队尾指针
            isClose();
        } else {
            full(); //判断是否队满
            if (tail.next != null) { //已经形成闭环
                tail.e = e;
                tail = tail.next;
            } else { //还未形成闭环
                Node<E> rear = new Node(null, tail.index + 1, null); //队尾
                tail.e = e; //队尾添加元素
                tail.next = rear; //添加新的空队尾
                tail = rear; //更新队尾指针
                isClose();
            }
        }
        return true;
    }

    void isClose(){
        if(size() == QUEUE_SIZE - 1) //相等则说明可以形成闭环,因为要留一个空节点,所以这里减1
            tail.next = front;
    }

    /**
     * 出队,从队头取出元素
     */
    public E pop(){
        if(empty())
            return null;
        E e = head.e;
        head.e = null; //节点数据清空
        head = head.next; //更新队头位置
        return e;
    }
    /**
     * 获取队列中元素个数
     * (tail – head + QUEUE_SIZE)%QUEUE_SIZE
     */
    public int size(){
        return (tail.index - head.index + QUEUE_SIZE) % QUEUE_SIZE;
    }
    /**
     * 队列是否为空
     */
    public boolean empty(){
        return head == tail;
    }

    /**
     * 判断队列是否已满
     * (rear+1)%N==front
     */
    void full(){
        if((tail.index + 1) % QUEUE_SIZE == head.index)
            throw new IndexOutOfBoundsException("队列已满,入队失败");
    }

    /**
     * 初始化的队列大小检查
     */
    void checkQueueSize(){
        if(QUEUE_SIZE < 1)
            throw new IndexOutOfBoundsException("QUEUE_SIZE : " + QUEUE_SIZE);
    }

    /**
     * 节点的定义
     * @param <E>
     */
    private static class Node<E>{
        E e; //元素
        int index; //当前节点的下标,从0开始直到QUEUE_SIZE
        Node<E> next; //下一个节点

        Node(E e, int index, Node<E> next){
            this.e = e;
            this.index = index;
            this.next = next;
        }
    } 
}

  写到这里,队列通过单链表已经实现了。队列还可以通过数组来实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值