Java数据结构(队列),数组模拟队列实现

队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,队列是一种操作受限制的线性表。进行插入操作(入口)的端称为队尾,进行删除操作(出口)的端称为队头。


 

队列的特点先进先出(FIFO,First In First Out),因此我们也称队列为FIFO表。

LinkedList类实现了Queue接口,在Queue接口中提供的方法可以实现队列的相关操作。Queue接口扩展了Collection接口,常见的方法如下所示。

Queue接口中方法:

方法名

描述

boolean add(E e);

boolean offer(E e);

这两个方法都是在尾部添加元素

add()会在长度不够时抛出异常;  offer()则不会,只返回false

 E element();

 E peek();

这两个方法都是查看头部元素 ,返回头部元素,但不改变队列

element()会在没元素时抛出异常;  peek()则返回null;

E remove();

E poll();

这两个方法都是删除头部元素,返回头部元素,并且从队列中删除

remove()会在没元素时抛出异常;  poll()返回null; 

boolean isEmpty();

判断队列是否为空,如果为空则返回true;否则返回false。

【示例】使用LinkedList实现队列操作

public class Test {
	public static void main(String[] args) {
		// 队列,先进先出
		Queue queue = new LinkedList();
		// 入队,添加尾部元素
		queue.offer(111); 
		queue.offer(222); 
		queue.offer(333); 
		queue.offer(444); 
		// 遍历队列中的所有元素,直到队列为空为止
		while(!queue.isEmpty()) {
			// 出队,删除头部元素
			System.out.println(queue.poll());
		}
	}
}

数组模拟队列实现:

以下采用数组实现,初始化一个队列数组的空间长度为5,队列有两个标记,一个队头的位置front,一个队尾的位置rear,初始都指向数组下标为0的位置,如图所示

 

在插入元素时,rear标记递增+1,比如依次入队11,22,33这三个元素,则当前队列存储情况如图:

当前front为0,rear为3,接下来执行出队操作,此处将11元素出队,则front标记递增+1,此时队列的存储情况如图:

根据上面的图例,我们可以通过rear-front获得队列中元素的个数。当front==rear时,此时队列为空,而当rear==数组长度时,此时将无法添加元素,我们可以设为队列已满,接下来我们就通过代码实现这个操作。


按照以上的操作,当front==rear时,那么队列是否已经满呢?未必!因为front和rear在入队和出队操作中只增不减,因此front和rear都会最终指向队列之外的存储位置,此时虽然数组为空,但也无法将元素入队。

如何解决这个问题,我们引入了循环队列。当rear的取值为数组空间长度,此时如果数组还有空闲的位置,将rear从新指向数组的0索引处即可,如图所示:

如果继续入队66和77这两个元素,则队列的存储结构如图:

在采用循环队列实现的过程中,当队列满队时,front等于rear,而当队列空时,front也等于rear,为了区分两种状态,一般规定循环队列的长度为”数组长度-1”,即有一个位置不放元素,此时front==rear时为空队,而当front==(rear+1)%数组长度,说明对满。

【示例】循环列列的实现

public class ArrayQueue<T> {
    /**
     * 模拟队列的数组
     */
    private Object[] elementData;
    /**
     * 保存队首的指针
     */
    private int front;
    /**
     * 保存队尾的指针
     */
    private int rear;
    /**
     * 无参构造方法
     */
    public ArrayQueue() {
        // 设置数组的默认空间长度为10
        this(10);
    }

    /**
     * 有参构造方法
     * @param capcaity 设置数组的空间长度
     */
    public ArrayQueue(int capcaity) {
        // 处理capcaity参数不合法的情况
        if (capcaity < 0) {
            throw new IllegalArgumentException("参数不合法异常,capcaity:" + capcaity);
        }
        // 创建指定空间长度的数组
        this.elementData = new Object[capcaity];
    }

    /**
     * 获取队列中元素的个数
     * @return 返回队列中元素的个数
     */
    public int getSize() {
        if (rear > front) {
            return rear - front;
        }
        else {
            return (rear + elementData.length) - front;
        }
    }

    /**
     * 入栈操作
     * @param element
     */
    public void add(T element) {
        // 判断队列是否已满
        if (isFull()) {
            throw new RuntimeException("队列已满,无法执行入队列操作");
        }
        // 执行入队操作
        elementData[rear] = element;
        // 更新rear的值
        rear = (rear + 1) % elementData.length;
    }

    /**
     * 删除队列的首元素
     * @return 返回被删除的元素值
     */
    public T remove() {
        // 判断队列是否为空
        if (isEmpty()) {
            throw new RuntimeException("队列为空,无法执删除队列操作");
        }
        // 获取队列首元素
        T element = (T)elementData[front];
        // 把front索引位置元素设置为默认值
        elementData[front] = null;
        // 更新front索引值
        front = (front + 1) % elementData.length;
        // 返回被删除的队首元素
        return element;
    }

    /**
     * 获得队列的首元素
     * @return 返回队列的首元素
     */
    public T element() {
        // 判断队列是否为空
        if (isEmpty()) {
            throw new RuntimeException("队列为空,无法执获取队列操作");
        }
        // 获取并返回队列的首元素
        return (T)elementData[front];
    }

    /**
     * 判断队列是否已满
     * @return 队列已满,则返回true;队列未满,则返回false。
     */
    private boolean isFull() {
        return front == (rear + 1) % elementData.length;
    }

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值