数组模拟环形队列

该博客介绍了如何使用数组模拟环形队列,通过初始化front和rear为-1,遵循先进先出原则。文章讨论了原实现存在的问题,即队列只能使用一次,然后提出了改进方案,通过巧妙地处理front和rear的索引,确保它们在循环中不会越界,从而实现可重复使用的环形队列。此外,博客还提供了环形队列的添加、获取、检查队列满和空的方法实现。
摘要由CSDN通过智能技术生成

数组模拟环形队列

队列特点

队列是一个有序列表,可以用数组或者链表来实现.
同时队列还遵循着先进先出的原则,即先入队的元素先出队,后入队的元素后出队.
只要保证从队首取数据,队尾放数据就可以保证先进先出.

实现思路

首先需要一个数组和两个指针来记录上次操作的元素的位置,front和rear,
front用来记录取出数据的位置,rear用来记录新增数据的位置.
当存入数据时,rear的值要加一,取出数据时front的值也要加一.

front和rear的初始值都是-1,即不指向任何一个元素,
front 在队列头的第一个元素的位置之前,rear在队尾的最后一个元素之后.

实现

package element.io.data.structure.d2;

/**
 * @author 张晓华
 * @date 2022-12-16
 * 使用数组模拟队列
 */
public class ArrayQueue {

	// 用来指向队列头,记录的是上次操作的元素的索引位置,默认值为-1,队列为空时不指向任何一个元素
	private int front = -1;

	// 用来指向队列尾,记录的也是上次元素的索引的为位置,默认值为-1,即空队列时不指向任何一个元素
	private int rear = -1;

	private int maxSize;

	public ArrayQueue() {
		this(3);
	}


	public ArrayQueue(int maxSize) {
		this.maxSize = maxSize;
		this.arr = new Object[maxSize];
	}

	// 数组,用来存储数据
	private Object[] arr;


	private boolean isFull() {
		// 只要向队列中添加了数据,rear的值一定会发生变化,
		// 并且maxSize代表的是数组的长度即容量,front和rear记录的是索引值,所以必须做-1处理
		return rear == maxSize - 1;
	}

	private boolean isEmpty() {
		// front 和 rear 在初始化时值都为-1,并且存储数据时rear的值会增加,取数据的时候front的值会变化,
		// 如果二者的值相同就代表着队列为空
		return front == rear;
	}

	public void showData() {
		if (isEmpty()) {
			System.out.println("队列为空");
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.printf("arr[%d] = %s \n", i, arr[i].toString());
		}
	}

	// 向队列存入数据
	public void add(Object ele) {
		if (isFull()) {
			throw new RuntimeException("队列已满");
		}
		// 由于rear和front在初始化后都是指向队列尾或者队列头的前一个元素,因此在使用前必须要+1
		this.arr[++rear] = ele;
	}

	// 从队列中取出数据
	public Object get() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		return arr[++front];
	}

	public Object head() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		return this.arr[front +1 ];
	}

}

问题

上面的实现方式很明显存在着比较大的缺陷,就是队列只能够使用一次,不能够重复使用,因此需要将其升级为环形队列

改进的思路
在这里插入图片描述

改进后的代码


package element.io.data.structure.d2;

/**
 * @author 张晓华
 * @date 2022-12-17
 * 使用数组模拟环形队列,其实并不难,核心就是要保证front和rear的值不断的循环并且不能出现索引越界
 */
public class CircleArrayQueue {

	// 指向数组的第一个元素
	private int front;

	// 指向数组的最后一个元素,预留一个元素的空间
	private int rear;

	// 数组的最大容量
	private int maxSize;

	// 存储数据的数组
	private Object[] arr;

	public CircleArrayQueue() {
		this(3);
	}

	public CircleArrayQueue(int maxSize) {
		this.maxSize = maxSize;
		this.arr = new Object[maxSize];
	}

	/**
	 * 假设数组的容量为6,那么初始化完成之后,front=0,rear=0
	 * 队列的可用容量为 6-1,预留了一个空间
	 * 那么队列中最多可以存储5个元素,
	 * 当只存不取的时候,front=0,rear=5
	 * 5 - 0 == front,那么此时队列就已经满了
	 * 当存了4个元素,取了一个元素,front=1,rear=4
	 * 4 - 1 != front 队列没有满
	 * 当存了5个元素,取了五个元素 front =5,rear = 5
	 * front - rear != front 那么这个判断就失效了
	 */
	private boolean isFull() {
		// 这种方式不可行,因为初始化后front和rear的值都为0,首次添加数据就直接判断队列满了
		//return (rear - front) == front;
		// 当存了五个元素,没有取出元素, (5 + 1)%6 == 0
		return (rear + 1) % maxSize == front;
	}


	/**
	 * 当没有向对列中存入数据时,front=0,rear=0,front == rear
	 * 当向对列中存入了三个数据时,front=0,rear=3,front!=fear
	 * 当向对列中存入了五个数据,同时也取出了五个数据,front == rear
	 * 所以就只需要判断front和rear的值是否相等就可以了
	 *
	 * @return
	 */
	private boolean isEmpty() {
		return front == rear;
	}

	public int size() {
		//这样直接相减会出现负数的情况,当rear被重置之后,再开始取值就会出现rear小于front
		//return rear - front;
		// 这样写就可以避免负数的问题了,因为模运算的结果的符号取决于右边
		return (rear - front + maxSize) % maxSize;
	}


	public void add(Object obj) {
		if (isFull()) {
			throw new RuntimeException("队列已满");
		}
		this.arr[rear] = obj;
		// 这里这样写就是为了规避掉索引越界异常,如果只是rear++,
		// 那么一直添加数据,rear的值就会没有限制的一直增长,必然会超过maxLength,
		// 当 rear +1 == maxSize时,rear的值就会被重置为0,
		// 当rear+1 < maxSize时是没有任何影响的, 3%6 = 3
		rear = (rear + 1) % maxSize;
	}

	public Object get() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		Object res = this.arr[front];
		// front和rear一样,都需要在临界值时重置,否则必然会出现索引越界
		front = (front + 1) % maxSize;
		return res;
	}

	public void showData() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		// 必须从front开始获取数据,否则就不是从队列头获取数据了
		for (int i = front; i < front + size(); i++) {
			// 但是此处就会出现i值大于数组长度的情况,所以需要调整一下i的值,
			// i 小于maxSize,对i的值不会产生任何变化,i值大于maxSize,可以调整i的值为正确的值
			System.out.printf("arr[%d]=%s \n", i, arr[i % maxSize].toString());
		}
	}

	public Object head() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		return this.arr[front];
	}


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值