JAVA简单实现循环队列

循环队列介绍

  • ”先进先出”(FIFO)的一种数据结构;
  • 空间循环使用(队尾队头成环),分别有”队头”和“队尾"两个指针。

循环队列实现

基本属性和构造方法

利用泛型数组作为底层数据结构实现循环队列,定义基本属性和构造方法。

注意:

  • 数组中采用牺牲一个空间来作为判空和判满的区别
  • 定义默认大小MAX_SIZE为11,即数组默认开辟11个空间,初始化队列容量为10
  • 区分队列的容量为(MAX_SIZE-1),和实现数组的长度为MAX_SIZE
 //利用泛型数组作为底层数据结构实现循环队列
    private T[] data;
    private static  int MAX_SIZE = 11;
    //队头指针
    int front;
    //队尾指针
    int rear;
    //true为满 false为空
    boolean flag = false;

    public MyQueue(){
        data = (T[]) new Object[MAX_SIZE];
        front = rear = 0;
    }
    public MyQueue(int maxsize){
        this.MAX_SIZE = maxsize+1;
        data = (T[]) new Object[MAX_SIZE];
        front = rear = 0;
    }

循环队列指针的理解

MAX_SIZE为数组实际长度,不是队列实际长度或队列容量

入队(移动队尾指针): rear =  ( rear + 1 ) %  MAX_SIZE

出队(移动对头指针):front =  ( front + 1 ) %  MAX_SIZE

判满:front ==  ( rear + 1 ) %  MAX_SIZE

判空:front == rear

为了方便理解,以上是一个容量为4的循环队列的一次循环过程图。可以对着理解一下”队头”和“队尾"两个指针在这个过程中的计算变化。

基本方法实现


       //入队
    public void enqueue(T t) {
        if(front == (rear+1)%MAX_SIZE || flag){
           throw new RuntimeException("queue is full!!!!!!");
        }else {
            data[rear] = t;
            rear = (rear + 1) % MAX_SIZE;
            if (front == (rear+1)%MAX_SIZE) {
                flag = true;
            }
        }
    }

    //出队
    public T dequeue() {
        if(front == rear && !flag){
            throw new RuntimeException("queue is empty!!!!!!");
        }else {
            T element = data[front];
            front = (front + 1) % MAX_SIZE;
            if (front == rear) {
                flag = false;
            }
            return element;
        }
    }

    //返回队头元素
    public T peek(){
        if(front == rear && !flag){
            throw new RuntimeException("queue is empty!!!!!!");
        }else {
            return data[front];
        }
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return !flag;
    }

    //返回队列容量
    public int capacity(){
        return MAX_SIZE-1;
    }


    //返回队列长度
    public int actualSize(){
        if(rear > front){
            return rear-front;
        } else if (rear < front){
            return MAX_SIZE - (front - rear);
        } else if (rear == front) {
            return 0;
        }
        return -1;
        }

        //tostring
        public String toString(){
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("[");
            if(rear > front){
                for (int i = front; i < rear; i++) {
                    stringBuilder.append(data[i]);
                    if (i != rear - 1){
                        stringBuilder.append(",");
                    }
                }
            } else if (rear < front){
                for (int i = front; i < MAX_SIZE; i++) {
                    stringBuilder.append(data[i]);
                    if (i != MAX_SIZE - 1){
                        stringBuilder.append(",");
                    }
                }
                for (int i = 0; i < rear; i++) {
                    stringBuilder.append(data[i]);
                    if (i != rear - 1){
                        stringBuilder.append(",");
                    }
                }
            } else if (rear == front) {
                stringBuilder.append("null");
            }

            stringBuilder.append("]");
            return stringBuilder.toString();
        }

扩容方法的实现

思路就是改变MAX_SIZE的值,利用System.arraycopy方法把旧数组复制到新数组。

    public void ensureCapacity(int size) {
        if(size < MAX_SIZE-1){
            throw new RuntimeException("Size is less than MAX_SIZE!!!!!!");
        }else {
            int old = MAX_SIZE;
            MAX_SIZE = size+1;
            T[] oldElements = data;
            data = (T[]) new Object[MAX_SIZE];
            System.arraycopy(oldElements, 0, data, 0, old);
            System.out.println("queue is full, capacity is expanded to " + data.length);
        }
    }

作业

设计一个循环队列,用data[0..MaxSize-1]存放队列元素,用front和rear分别作为队头和队尾指针,另外用一个标志tag标识队列可能空(false)或可能满(true),这样加上front==rear可以作为队空或队满的条件。要求设计队列的相关基本运算算法。

package queue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class WorkTwoTest {
    MyQueue<Character> mq;
    @BeforeEach
    @DisplayName("入队测试")
    void init(){
        System.out.println("Test begin.......");
        mq = new MyQueue<>();
        mq.enqueue('a');
        mq.enqueue('b');
        mq.enqueue('c');
        mq.enqueue('d');
    }

    @Test
    @DisplayName("出队测试")
    void dequeueTest() {
        System.out.println("出队前:"+mq);
        System.out.println(mq.dequeue()+"已出队!");
        System.out.println("出队后:"+mq);
        System.out.println("========================");
    }

    @Test
    @DisplayName("扩容+返回队列长度测试")
    void ensureCapacityTest() {
        System.out.println("队列容量为:" + mq.capacity());
        System.out.println("队列实际长度为:" + mq.actualSize());
        mq.ensureCapacity(20);
        System.out.println("队列容量为:" + mq.capacity());
        System.out.println("========================");
    }

    @Test
    @DisplayName("返回队头元素测试")
    void peekTest() {
        System.out.println("队头元素为:"+mq.peek());
        System.out.println("========================");
    }
}

测试结果如下

总结

根据循环队列的思想,可以学到:

  • 循环地使用空间可以减少空间的占用。
  • 想要获得循环的一组数可以参考循环队列指针的计算方法,用取模%运算得到。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BenChuat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值