1、实现目标
通过Java和Golang两种语言实现队列,此处的队列的满足的要求有:
- 长度需要设定,也即长度固定
- 满足队列的基本要求,先进先出
- 存放的类型自定义,Java通过泛型实现,Golang暂定用interface{}
完整代码和测试代码,参考:https://github.com/lzj09/data-structure
2、实现逻辑
对于Java,内部是通过数组来实现;
对于Golang,内部是通过切片来实现;
同时内部有2个索引,分别用于指向队头和队尾的下一个下标,即:
- 指向队头的下标用front表示
- 指向队尾的下一个下标用rear表示,这里需要注意,这是为了方便下标进行循环,也即为了方便取模运算,特意让rear指向队尾的下一个下标,这也即意味着,队列中总有一个位置是存不了数据的,所以队列长度为n时,实质队列的长度需要为n+1
如图所示,队列的加入数据和获取数据的过程:
上图所演示的队列最大存放数据量为3的队列(实质队列的长度需要4)过程,从上图可以得如下结论:
-
当front==rear时,表示队列为空
-
当加入数据时,数据加入的下标为rear,同时rear需要下移,需要考虑循环,则rear的下移算法为:
rear = (rear + 1) % size
-
当取数据时,数据取front对应的数据,同时front也需要下移,也需要考虑循环,front的下移算法为:
front = (front + 1) % size
-
当队列满时的条件,即为:(rear - front + 1) % size == 0
3、代码实现
Java版本:
package com.github.lzj09.datastructure.queue;
/**
* 基于数组实现队列
*
* @author lzj
* @date 2022-11-29
*/
public class ArrayQueue<T> {
// 指向队头的下标
private int front;
// 指向队尾的下标下一个下标
private int rear;
// 队列的最大容量
private int size;
// 存放数据的数组容器
private T[] arrs;
@SuppressWarnings("unchecked")
public ArrayQueue(int size) {
// 由于rear指向队尾的下一个下标,为此需要多1个空间
this.size = size + 1;
arrs = (T[]) new Object[this.size];
}
/**
* 队列是否满
*
* @return
*/
public boolean isFull() {
return (rear - front + 1) % size == 0;
}
/**
* 队列是否为空
*
* @return
*/
public boolean isEmpty() {
return rear == front;
}
/**
* 往队列中加入数据
*
* @param data
*/
public void add(T data) {
if (isFull()) {
throw new RuntimeException("队列已满");
}
arrs[rear] = data;
rear = (rear + 1) % size;
}
/**
* 从队列中获取数据
*
* @return
*/
public T get() {
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
int tmp = front;
front = (front + 1) % size;
return arrs[tmp];
}
}
Golang版本:
package queue
import "errors"
// ArrayQueue 基于切片实现队列
type ArrayQueue struct {
// 指向队头的下标
front int64
// 指向队尾的下标下一个下标
rear int64
// 队列的最大容量
size int64
// 存放数据的数组容器
arrs []interface{}
}
// NewArrayQueue 获取指定大小的队列
func NewArrayQueue(size int64) *ArrayQueue {
return &ArrayQueue{
size: size + 1,
arrs: make([]interface{}, size+1),
}
}
// ISFull 队列是否满
func (q *ArrayQueue) ISFull() bool {
return (q.rear-q.front+1)%q.size == 0
}
// ISEmpty 队列是否为空
func (q *ArrayQueue) ISEmpty() bool {
return q.rear == q.front
}
// Add 往队列中加入数据
func (q *ArrayQueue) Add(data interface{}) error {
if q.ISFull() {
return errors.New("queue is full")
}
q.arrs[q.rear] = data
q.rear = (q.rear + 1) % q.size
return nil
}
// Get 从队列中获取数据
func (q *ArrayQueue) Get() (interface{}, error) {
if q.ISEmpty() {
return nil, errors.New("queue is empty")
}
tmp := q.front
q.front = (q.front + 1) % q.size
return q.arrs[tmp], nil
}