循环队列:
为了重新利用顺序队列底层数组中删除所有元素所占用的空间,消除可能出现的“假满”现象,可以将顺序队列改进为循环队列。
对于循环队列,不管队列是空还是满,都会出现一种情况:front == rear。如果底层数组中elementData[front] == null;则表明此时队列为空,否则表明该队列已满。
为了重新利用顺序队列底层数组中删除所有元素所占用的空间,消除可能出现的“假满”现象,可以将顺序队列改进为循环队列。
循环队列是一种收尾相连的队列:当front、rear变量值达到底层数组的capacity - 1之后,在前进一位就自动变成 0 。如下图所示示意图:
对于循环队列,不管队列是空还是满,都会出现一种情况:front == rear。如果底层数组中elementData[front] == null;则表明此时队列为空,否则表明该队列已满。
下面是代码实现:
import java.util.Arrays;
public class LoopQueue <T> {
//默认队列容量为10
private final int DEFAULT_CAPACITY = 10;
//底层数组
private Object[] elementData;
//容量
private int capacity;
//
private int front = 0;
private int rear = 0;
public LoopQueue(){
this.capacity = DEFAULT_CAPACITY;
elementData = new Object[capacity];
}
public LoopQueue(T element){
this();
elementData[0] = element;
rear ++;
}
public LoopQueue(T element, int initCapacity){
this.capacity = initCapacity;
elementData = new Object[capacity];
elementData[0] = element;
rear ++;
}
//队列长度
public int length(){
if(isEmpty()){
return 0;
}
return (rear > front) ? rear - front : capacity - (front - rear);
}
//判是否为空
public boolean isEmpty(){
return rear == front && elementData[front] == null;
}
//向队列rear端插入元素
public void add(T element){
indexOutOfBoundsForAdd(rear);
elementData[rear ++] = element;
rear = (rear == capacity ? 0 : rear);
}
//向队列front端删除并返回 该元素
@SuppressWarnings("unchecked")
public T remove(){
noneElementForRemove();
T t = (T) elementData[front];
elementData[front ++] = null;
front = (front == capacity ? 0 : front);
return t;
}
//element()返回但不删除front端元素
@SuppressWarnings("unchecked")
public T element(){
noneElementForRemove();
return (T) elementData[front];
}
//清空队列
public void clear(){
Arrays.fill(elementData, null);
front = 0;
rear = 0;
}
//toString 方法
public String toString(){
if(isEmpty()){
return "[]";
}
else{
StringBuilder sb = new StringBuilder("[");
if(rear > front){
for(int i = front; i < rear; i ++){
sb.append(elementData[i].toString() + ",");
}
}else{
/*for(int i = front; i < capacity; i ++){
sb.append(elementData[i].toString() + ",");
}
for(int j = 0; j < rear; j ++){
sb.append(elementData[j].toString() + ",");
}*/
//或者下面这种
for(int i = front; i < capacity + rear; i ++){
sb.append(elementData[i % capacity].toString() + ",");
}
}
return sb.toString().substring(0, sb.length() - 1) + "]";
}
}
private void indexOutOfBoundsForAdd(int index){
if(index == front && elementData[front] != null){
throw new IndexOutOfBoundsException("exception for LoopQueue is filled:index of add is " + index);
}
}
private void noneElementForRemove(){
if(isEmpty()){
throw new IndexOutOfBoundsException("none any element in SequenceQueue to remove!");
}
}
}
测试代码跟前面的一样:
import com.yc.list.LoopQueue;
public class LoopQueueTest {
public static void main(String[] args) {
LoopQueue<String> queue = new LoopQueue<String>("aaa", 4);
queue.add("bbb");
queue.add("ccc");
queue.add("ddd");
System.out.println( "队列为: " + queue);
System.out.println();
String sElement = queue.element();
System.out.println( "队列为: " + queue);
System.out.println( "队首为: " + sElement);
System.out.println();
String sRemove = queue.remove();
System.out.println( "队列为: " + queue);
System.out.println( "移除的队首为: " + sRemove);
System.out.println();
queue.add("eee");
System.out.println( "队列为: " + queue);
}
}
测试结果为:
remove()方法后将front端的元素从队列删除,多出来的空间可以循环使用,可以再次添加新的数据元素 “eee”。并不会抛出异常。