前言
这个系列咕了好久啦
今天没事做看了一下王道考研的数据结构,看着看着才想起来我的数据结构系列拖了好久了,上来水一篇比较简单而巧妙的数组实现队列吧~
源码
看完代码有收获的话,别忘了点个Star哦~
有界队列的实现
我们上次用链表实现过队列,用链表可以实现有界或者无界的队列,那么可不可以用数组来实现队列呢,答案是肯定的
思考
在链表中,我们可以使用头尾指针 Object head,tail;
来指向链表的头部和尾部,辅助实现队列的出队和入队
而在数组中,我们同样可以使用头尾索引 int head,tail;
,在数组elements
中,使用elements[head]
表示队头,elements[tail]
表示队尾
可是,数组的大小是有限的,如果我们用数组实现队列,在我们出队和入队的时候,都需要让head++
或tail++
,这样自增下去,是会数组越界的,怎么办呢?
取模的作用
这时候我们就要发挥取模的作用了,已知任意整数a、b,当a%b时,得到的结果区间只能是 [0, b) 的半闭半开的区间,我们将这个数学知识用在数组上,就可以让head
和tail
两个索引做到循环使用了~
- 例:当尾索引
++tail==capacity
,在用elements[tail]
的话已经会造成数组越界了(capacity == elements.length;
),但是,如果我们将入队操作对尾索引的操作替换为:tail = (tail+1)%capacity;
时 ,tail就会重新归为0 - 总结:在入队时将
tail++;
操作更换为tail = (tail+1)%capacity;
,可在索引即将越界的时候归零,其它时候为正常自增
实现
一、基本字段 & 构造方法
public class ArrayQueue<T> {
/**
* 存放队列元素的数组
*/
Object[] elements;
/**
* 头、尾指针
*/
private int head, tail;
/**
* 队列容量与队列当前大小
*/
private int capacity, size;
/**
* 有界队列构造方法
*
* @param capacity
*/
public ArrayQueue(int capacity) {
this.capacity = capacity;
this.elements = new Object[capacity];
}
// ...未完
这里做了详细的注释,不多说了吧
二、出队 & 入队
/**
* 出队操作,队列为空时抛出异常
*
* @return 队头
* @throws Exception
*/
public T pop() throws Exception {
if (size == 0) {
throw new Exception("队列为空!");
}
// 元素出队时,size记得自减
--size;
T res = (T) elements[head];
elements[head] = null;
// head+1,并与容量取模
// 例:capacity为10,head为9+1=10,即将数组越界
// 将当前头指针索引10与容量10取模,得head=10%10=0(头指针循环)
head = (head + 1) % capacity;
return res;
}
/**
* 入队操作,队列满时返回false,入队成功时返回true
*
* @param t
* @return
*/
public boolean offer(T t) {
if (size == capacity) {
return false;
}
// 元素入队时,size记得自增
++size;
elements[tail] = t;
// 尾指针的取模与头指针同理(尾指针循环)
tail = (tail + 1) % capacity;
return true;
}
// ...未完
这里在入队出队时,对头索引head
和尾索引tail
的操作用到了之前讲的取模操作,保证了两个索引的循环使用
三、其它方法
/**
* 队列为空时返回true
*
* @return
*/
public boolean isEmpty() {
return size == 0;
}
@Override
public String toString() {
return Arrays.toString(elements);
}
}
四、测试用main方法
/**
* main方法,测试用
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ArrayQueue<Integer> queue = new ArrayQueue<>(5);
for (int i = 1; i <= 6; ++i) {
System.out.println("offer:" + i + "," + queue.offer(i));
}
System.out.println(queue.toString());
for (int i = 1; i <= 3; ++i) {
System.out.println("pop:" + queue.pop());
}
System.out.println(queue.toString());
for (int i = 1; i <= 2; ++i) {
System.out.println("offer:" + i + "," + queue.offer(i));
}
System.out.println(queue.toString());
for (int i = 1; i <= 3; ++i) {
System.out.println("pop:" + queue.pop());
}
System.out.println(queue.toString());
for (int i = 1; i <= 2; ++i) {
System.out.println("offer:" + i + "," + queue.offer(i));
}
System.out.println(queue.toString());
while (!queue.isEmpty()) {
System.out.println(queue.pop());
}
queue.pop();
}
输出:
offer:1,true
offer:2,true
offer:3,true
offer:4,true
offer:5,true
offer:6,false [ 队列满,入队时返回false ]
[1, 2, 3, 4, 5]
pop:1
pop:2
pop:3
[null, null, null, 4, 5]
offer:1,true
offer:2,true
[1, 2, null, 4, 5]
pop:4
pop:5
pop:1
[null, 2, null, null, null]
offer:1,true
offer:2,true
[null, 2, 1, 2, null]
2
1
2
Exception in thread “main” java.lang.Exception: 队列为空![ 队列为空,出队时抛出异常 ]