java实现队列MyQueue,底层使用数组实现

本文介绍了如何使用数组实现Java队列,包括两种不同的实现思路。通过维护两个索引,确保基本的队列操作得以实现。文章还强调了面向接口编程和多态的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * 队列的接口
 * 队列是一种先进先出的数据结构
 * 队列支持的操作:
 * 判断队列是否为空
 * 判断队列是否已经满了
 * 查看队列已经有多少元素
 * 将一个元素入队
 * 将一个元素出队
 * 查看队头的元素,但不出队
 * 队列在底层可以用数组实现,也可以用链表实现
 * 但不管实现方式如何,都必须满足此接口中的规定
 */
public interface MyQueue<Item> extends Iterable<Item>{
    /**
     * 判断队列是否为空
     * @return 如果队列为空,则返回true;否则,返回false
     */
    public boolean isEmpty();

    /**
     * 判断队列是否为满,满了返回true,否则返回false
     * @return
     */
    public boolean isFull();

    /**
     * 返回队列中元素的个数
     * @return 个数
     */
    public int size();

    /**
     * 入队,将一个元素入队
     * @param item 待入队的元素
     * @return 入队成功返回true,否则返回false
     */
    public boolean enqueue(Item item);

    /**
     * 将一个元素出队
     * @return  出队成功返回出队的元素,否则返回null
     */
    public Item dequeue();

    /**
     * 查看队列头部的元素,但不出队
     * @return 队列头部的元素,如果没有元素,返回null
     */
    public Item get();
}

以上是队列的接口,接下来用数组来实现队列。

/**
 * 队列的具体实现,底层使用数组实现
 * 数组的实现也分几种情况
 *版本1中,维护两个索引,front和rear
 * 初始状态front和rear都在-1的位置(假想有-1的位置)
 * 第一个元素入队的时候,front=0、rear++、再入队
 * 出队的时候,正常情况下front++就可以,但是当front和rear相同的时候出队,那么就把front和rear初始化为-1
 * 队列空的条件为front=-1;
 * 队列满的条件为(rear+1)%maxsize==front
 * Queue还要满足foreach的自动迭代,所以需要实现Iterable<Item>接口
 */
public class ArrayQueueVersion1<Item> implements MyQueue<Item>{
    private Item[] items;
    private int front;
    private int rear;
    private int maxsize;
    public ArrayQueueVersion1() {
        this(10);   //调用无参数构造器,实际上调用的是带参数的构造器,默认大小为10
    }

    /**
     * 有参数的构造器,
     * @param k 队列的最大容量
     */
    public ArrayQueueVersion1(int k) {
        items= (Item[]) new Object[k];
        maxsize=k;
        front=-1;
        rear=-1;
    }

    @Override
    public boolean isEmpty() {
        return front==-1;
    }

    @Override
    public boolean isFull() {
        return (rear+1)%maxsize==front;
    }

    @Override
    public int size() {
        if(isFull()){
            return maxsize;
        }
        return (rear+1-front+maxsize)%maxsize;
    }

    @Override
    public boolean enqueue(Item item) {
        if(isFull()){
            return false;
        }
        if(front==-1){
            front=0;
        }
        rear=(rear+1)%maxsize;
        items[rear]=item;
        return true;
    }

    @Override
    public Item dequeue() {
        if(isEmpty()){
            return null;
        }
        if(front==rear){
            front=-1;
            rear=-1;
        }
        Item delete=items[front];
        front=(front+1)%maxsize;
        return delete;
    }

    @Override
    public Item get() {
        if(isEmpty()){
            return null;
        }
        return items[front];
    }

    @Override
    public Iterator<Item> iterator() {
        return new ArrayQueueVersion1Iterator();
    }

    private class ArrayQueueVersion1Iterator implements Iterator<Item>{
        private int cur=front;

        @Override
        public boolean hasNext() {
            return cur<=rear;
        }

        @Override
        public Item next() {
            Item nextItem=items[cur];
            cur++;
            return nextItem;
        }

    }
}

以上是第一个版本的实现,思路是使用数组来存储元素,并维护两个索引。测试一下:

public class ArrayQueueVersion1Test {
    public static void main(String[] args) {
        MyQueue<Integer> myQueue=new ArrayQueueVersion1<>(7);
        myQueue.enqueue(1);
        myQueue.enqueue(2);
        myQueue.enqueue(13);
        myQueue.enqueue(20);
        myQueue.enqueue(35);
        myQueue.enqueue(50);
        myQueue.enqueue(70);
        System.out.println("size is "+myQueue.size());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        myQueue.enqueue(100);
        System.out.println("size is "+myQueue.size());
        System.out.println("next is "+myQueue.get());
        for (int i:myQueue){
            System.out.println(i);
        }
    }
}

结果是:

size is 7
删除了1
删除了2
删除了13
删除了20
size is 4
next is 35
35
50
70
100

满足了队列的基本操作。这就是使用数组来实现队列的第一个版本。
在第二个版本中,思路类似,但是细节变了。具体如下:

/**
 * 队列的实现,底层依然是使用数组。
 * 但是这次初始化时,front和rear都指向0这个位置。
 * 队列为空的条件为:front==rear
 * 队列为满的条件不变:(rear+1)%maxsize==front
 * 队列中元素的个数为:(rear-front+1+maxsize)%maxsize
 * 说明一下为什么队列为空是front==rear:
 * 如果底层存储元素的数组只有k个大小,那么在这种实现方式下,要舍弃一个位置的存储空间,
 * 这样队列只有在空的时候front才和rear是指向同一个位置的。
 * 这种舍弃一个位置的存储空间换来的是判断上的简洁,是值得的。
 * @param <Item>
 */
public class ArrayQueueVersion2<Item> implements MyQueue<Item> {
    private Item[] items;
    private int front;
    private int rear;
    private int maxsize;

    public ArrayQueueVersion2() {
        this(10);
    }

    /**
     * 注意这里的k是实际要存储的元素的个数,
     * 而真正开辟的数组却要比k大一个空间,
     * 因为前面说过要牺牲一个空间来进行条件的判断
     * @param k
     */
    public ArrayQueueVersion2(int k) {
        items= (Item[]) new Object[k+1];
        front=0;
        rear=0;
        maxsize=k+1;
    }

    @Override
    public boolean isEmpty() {
        return front==rear;
    }

    @Override
    public boolean isFull() {
        return (rear+1)%maxsize==front;
    }

    @Override
    public int size() {
        if(isFull()){
            return maxsize-1;
        }
        return (rear-front+1+maxsize)%maxsize-1;
    }

    @Override
    public boolean enqueue(Item item) {
        if(isFull()){
            return false;
        }
        items[rear]=item;
        rear=(rear+1)%maxsize;
        return true;
    }

    @Override
    public Item dequeue() {
        if(isEmpty()){
            return null;
        }
        Item delete=items[front];
        front=(front+1)%maxsize;
        return delete;
    }

    @Override
    public Item get() {
        if (isEmpty()){
            return null;
        }
        return items[front];
    }

    @Override
    public Iterator<Item> iterator() {
        return new ArrayQueueVersion2Iterator();
    }

    private class ArrayQueueVersion2Iterator implements Iterator<Item>{
        private int cur=front;
        @Override
        public boolean hasNext() {
            return rear!=cur;
        }

        @Override
        public Item next() {
            Item nextItem = items[cur];
            cur=(cur+1)%maxsize;
            return nextItem;
        }
    }
}

测试一下,因为是面向接口编程,所以只要把之前的测试用例的实现类替换了就行了,这也是多态的好处。

public class ArrayQueueVersion2Test {
    public static void main(String[] args) {
        MyQueue<Integer> myQueue=new ArrayQueueVersion2<>(7);
        myQueue.enqueue(1);
        myQueue.enqueue(2);
        myQueue.enqueue(13);
        myQueue.enqueue(20);
        myQueue.enqueue(35);
        myQueue.enqueue(50);
        myQueue.enqueue(70);
        System.out.println("size is "+myQueue.size());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        System.out.println("删除了"+myQueue.dequeue());
        myQueue.enqueue(100);
        System.out.println("size is "+myQueue.size());
        System.out.println("next is "+myQueue.get());
        for (int i:myQueue){
            System.out.println(i);
        }
    }
}

结果是:

size is 7
删除了1
删除了2
删除了13
删除了20
size is 4
next is 35
35
50
70
100

以上两种思路都需要掌握,因为虽然底层都是使用数组,但是细节完全不一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值