一、基本概念
队列是一种先进先出(FIFO)的线性表。循环队列即为队列的顺序表示和实现,其优点主要是入队和出队的时间复杂度均为O(1),这要归功于“循环队列将存储结构的理解由序列型转换为环型”的思维方式,如图1所示。
图1 序列型转换为环型的思维方式
循环队列使用的局限性是其在使用前必须明确和预知队列长度。
二、基本思路
- 建立尾标记(c语言中为尾指针)
- 设立头标记(c语言中为头指针)
- 入队时尾标记加1,出队时头标记加1
三、程序实现
ISequenceQueue.java
package org.linxiupan.algrithm.sequency.queue;
public interface ISequenceQueue<T> {
public boolean push(T t);
public T pop();
public int length();
public int size();
public boolean isEmpty();
public boolean isFull();
}
SequenceQueue.java
package org.linxiupan.algrithm.sequency.queue;
import org.linxiupan.algrithm.Logger;
public class SequenceQueue<T> implements ISequenceQueue<T>{
Object[] datas;
int size;
int front = 0;
int rear =0;
public SequenceQueue(int size){
this.size = size;
this.datas = new Object[size];
}
public boolean push(T t) {
if(isFull())return false;
datas[rear]=t;
rear=(rear+1)%size;
return true;
}
public T pop() {
if(isEmpty())return null;
@SuppressWarnings("unchecked")
T t = (T) datas[front];
datas[front]=null;
front=(front+1)%size;
return t;
}
public int length(){
return (rear-front+size)%size;
}
public boolean isEmpty(){
if(rear==front)return true;
return false;
}
public boolean isFull() {
if((rear+1)%size==front)return true;
return false;
}
public int size() {
return size;
}
public static void main(String[] args) {
SequenceQueue<Integer> o = new SequenceQueue<Integer>(10);
for(int i=1;i<=30;i++){
boolean b = o.push(i);
Logger.log("%d 入队后队列长度为 %d",i,o.length());
if(i%2==0){
Integer out=o.pop();
Logger.log("%d -> 现在的长度是 %d, 出队值=%d",i,o.length(),out);
}
if(!b){
Logger.log("%d 未入队",i);
}
}
for(int i=1;i<=10;i++){
Integer out=o.pop();
Logger.log("%d -> 现在的长度是 %d, 出队值=%d",i,o.length(),out);
}
Logger.log("");
}
}
Logger.java
package org.linxiupan.algrithm;
public class Logger {
public static void log(String format, Object... args){
System.out.println(String.format(format, args));
}
public static void log(String log){
System.out.println(log);
}
}
三、测试结果
1 入队后队列长度为 1
2 入队后队列长度为 2
2 -> 现在的长度是 1, 出队值=1
3 入队后队列长度为 2
4 入队后队列长度为 3
4 -> 现在的长度是 2, 出队值=2
5 入队后队列长度为 3
6 入队后队列长度为 4
6 -> 现在的长度是 3, 出队值=3
7 入队后队列长度为 4
8 入队后队列长度为 5
8 -> 现在的长度是 4, 出队值=4
9 入队后队列长度为 5
10 入队后队列长度为 6
10 -> 现在的长度是 5, 出队值=5
11 入队后队列长度为 6
12 入队后队列长度为 7
12 -> 现在的长度是 6, 出队值=6
13 入队后队列长度为 7
14 入队后队列长度为 8
14 -> 现在的长度是 7, 出队值=7
15 入队后队列长度为 8
16 入队后队列长度为 9
16 -> 现在的长度是 8, 出队值=8
17 入队后队列长度为 9
18 入队后队列长度为 9
18 -> 现在的长度是 8, 出队值=9
18 未入队
19 入队后队列长度为 9
20 入队后队列长度为 9
20 -> 现在的长度是 8, 出队值=10
20 未入队
21 入队后队列长度为 9
22 入队后队列长度为 9
22 -> 现在的长度是 8, 出队值=11
22 未入队
23 入队后队列长度为 9
24 入队后队列长度为 9
24 -> 现在的长度是 8, 出队值=12
24 未入队
25 入队后队列长度为 9
26 入队后队列长度为 9
26 -> 现在的长度是 8, 出队值=13
26 未入队
27 入队后队列长度为 9
28 入队后队列长度为 9
28 -> 现在的长度是 8, 出队值=14
28 未入队
29 入队后队列长度为 9
30 入队后队列长度为 9
30 -> 现在的长度是 8, 出队值=15
30 未入队
1 -> 现在的长度是 7, 出队值=16
2 -> 现在的长度是 6, 出队值=17
3 -> 现在的长度是 5, 出队值=19
4 -> 现在的长度是 4, 出队值=21
5 -> 现在的长度是 3, 出队值=23
6 -> 现在的长度是 2, 出队值=25
7 -> 现在的长度是 1, 出队值=27
8 -> 现在的长度是 0, 出队值=29
9 -> 现在的长度是 0, 出队值=null
10 -> 现在的长度是 0, 出队值=null
注:在真实应用中,未入队意味着队列已满,此处在一般情况应该一直等待直到入队成功为止。