数据结构之数组下的循环队列

循环队列

由于自定义的队列在出队操作时,需要将所有元素向前移动,时间复杂度为O(n),比较浪费时间,所以优化为O(1)。我们就需要用到循环队列。正所谓:"用空间换时间”。

解决方法:声明两个变量,分别指向队头和队尾。

自定义循环队列实现类

package com.company.queue;

/**
 * 自定义循环队列
 *
 * @param <T> 泛型
 * @Author: wenhua
 * @CreateTime: 2023-01-07  12:28
 */
public class LoopQueue<T> implements Queue<T> {

    private T[] data;
    // size 表示队列长度,front 指向队列头部元素(移除元素) tail 指向队列尾部最后一个元素(添加元素)
    private int size, front, tail;

    public LoopQueue() {
        this(5);// 调用有参构造函数,默认初始化队列长度为5
    }

    /**
     * 有参构造函数
     *
     * @param capacity 队列容量
     */
    public LoopQueue(int capacity) {
        data = (T[]) new Object[capacity + 1];// 浪费一个空间,为了判断其为空或队列已满,对用户隐藏
        front = tail = size = 0;
    }

    /**
     * 循环队列元素个数
     *
     * @return
     */
    @Override
    public int getSize() {
        return size;
    }

    /**
     * 循环队列容量
     *
     * @return
     */
    public int getCapacity() {
        return data.length - 1;
    }

    /**
     * 判断循环队列是否为空
     *
     * @return
     */
    @Override
    public boolean isEmpty() {
        return front == tail;//size == 0;
    }

    /**
     * 循环队列添加数据
     *
     * @param ele
     */
    @Override
    public void add(T ele) {
        // 当front == tail时队列为空,当(tail+1)%data.length == front时队列已满
        if ((tail + 1) % data.length == front) {
            // 扩容
            resize((data.length - 1) * 2);// 可以调用getCapacity()
        }
        data[tail] = ele;
        size++;// 元素数量加1
        tail = (tail + 1) % data.length;// 队尾指针指向下一个即将存放元素的位置
    }

    /**
     * 扩容
     *
     * @param newSize
     */
    private void resize(int newSize) {
        T[] newDate = (T[]) new Object[newSize + 1];
        for (int i = 0; i < size; i++) {
            newDate[i] = data[(front + i) % data.length];
        }
        tail = size;// 此处可以为getSize()也可以为类属性size或者data.length-1等等
        front = 0;// 更新队首指针
        data = newDate;
        newDate = null;
    }

    /**
     * 循环队列队首移除元素
     *
     * @return
     */
    @Override
    public T remove() {
        // 队列为空
        if (front == tail) {// if(isEmpty()){
            return null;
        }
        T result = data[front];// 存储当前队头指针所指向的元素
        // 可以将当前元素置空 即 data[front] = null
        front = (front + 1) % data.length;// 队头指针指向下一个元素
        size--;// 循环队列元素个数减1
        // 缩容
        if (size == data.length / 4 && data.length / 2 > 0) {
            resize(data.length / 2);
        }
        return result;
    }

    /**
     * 查看队首元素
     *
     * @return
     */
    @Override
    public T getFirst() {
        T result = null;
        try {
            result = data[front];
        } catch (Exception e) {
            System.out.println("error");
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuffer sbf = new StringBuffer();
        sbf.append("循环队列容量为:" + getCapacity() + ",循环队列中元素个数为:" + getSize() + ",元素为:[");
        for (int i = 0; i < size; i++) {
            sbf.append(data[(front + i) % data.length]);
            if (i != size - 1) {
                sbf.append(",");
            }
        }
        sbf.append("]");
        return sbf.toString();
    }
}

main方法测试

package com.company.queue;

/**
 * @Author: wenhua
 * @CreateTime: 2023-01-07  12:28
 */
public class LoopTest {
    public static void main(String[] args) {

        LoopQueue<String> loopQueue = new LoopQueue<>(2);
        System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:0,元素为:[]
        loopQueue.add("Jim");
        System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:1,元素为:[Jim]
        loopQueue.add("wenhua");
        System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:2,元素为:[Jim,wenhua]
        System.out.println("移除循环队列队首元素:"+loopQueue.remove());
        System.out.println(loopQueue);
        loopQueue.add("Jack");
        System.out.println(loopQueue);
        loopQueue.add("Jeep");
        System.out.println(loopQueue);
        loopQueue.add("DanNi");
        System.out.println(loopQueue);
        loopQueue.add("weijie");
        System.out.println(loopQueue);
        loopQueue.add("Deng");
        System.out.println(loopQueue);
        loopQueue.add("Yuan");
        System.out.println(loopQueue);
        loopQueue.add("Hua");
        System.out.println(loopQueue);
        loopQueue.add("Feng");
        System.out.println(loopQueue);
        while (loopQueue.getSize() != 0){
            System.out.println("移除循环队列队首元素:"+loopQueue.remove());
            System.out.println(loopQueue);
        }
    }
}

运行结果

循环队列容量为:2,循环队列中元素个数为:0,元素为:[]
循环队列容量为:2,循环队列中元素个数为:1,元素为:[Jim]
循环队列容量为:2,循环队列中元素个数为:2,元素为:[Jim,wenhua]
移除循环队列队首元素:Jim
循环队列容量为:2,循环队列中元素个数为:1,元素为:[wenhua]
循环队列容量为:2,循环队列中元素个数为:2,元素为:[wenhua,Jack]
循环队列容量为:4,循环队列中元素个数为:3,元素为:[wenhua,Jack,Jeep]
循环队列容量为:4,循环队列中元素个数为:4,元素为:[wenhua,Jack,Jeep,DanNi]
循环队列容量为:8,循环队列中元素个数为:5,元素为:[wenhua,Jack,Jeep,DanNi,weijie]
循环队列容量为:8,循环队列中元素个数为:6,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng]
循环队列容量为:8,循环队列中元素个数为:7,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan]
循环队列容量为:8,循环队列中元素个数为:8,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua]
循环队列容量为:16,循环队列中元素个数为:9,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:wenhua
循环队列容量为:16,循环队列中元素个数为:8,元素为:[Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Jack
循环队列容量为:16,循环队列中元素个数为:7,元素为:[Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Jeep
循环队列容量为:16,循环队列中元素个数为:6,元素为:[DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:DanNi
循环队列容量为:16,循环队列中元素个数为:5,元素为:[weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:weijie
循环队列容量为:8,循环队列中元素个数为:4,元素为:[Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Deng
循环队列容量为:8,循环队列中元素个数为:3,元素为:[Yuan,Hua,Feng]
移除循环队列队首元素:Yuan
循环队列容量为:4,循环队列中元素个数为:2,元素为:[Hua,Feng]
移除循环队列队首元素:Hua
循环队列容量为:2,循环队列中元素个数为:1,元素为:[Feng]
移除循环队列队首元素:Feng
循环队列容量为:1,循环队列中元素个数为:0,元素为:[]

以上实现底层为数组,也可以通过链表的方式,对栈,队列进行实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值