队列
一般队列
队列是一种先进先出的数据结构。
public class MyQueue<E> {
private Object[] data;
private int maxSize;
private int size;
private int front;
private int tail;
public MyQueue(int maxSize) {
if (maxSize <= 0)
throw new IllegalArgumentException("队列容量必须大于0 : " + maxSize);
this.maxSize = maxSize;
data = new Object[this.maxSize];
}
public void add(E e) {
if (this.isFull())
throw new IllegalArgumentException("队列已经满了,无法再加入……");
data[tail++] = e;
size++;
}
public E remove() {
if (isEmpty())
throw new IllegalArgumentException("队列是空的,无法移除……");
E e = (E)data[front];
data[front++] = null;
size--;
return e;
}
public boolean isFull() {
// 最后一个位置是不存储数据的
return tail == maxSize-1;
}
public boolean isEmpty() {
//队列头和队列尾指向同一空间的时候,并且没到队尾,表示队列是空的
return front == tail && !isFull();
}
public int getSize() {
return size;
}
}
测试一下
public static void main(String[] args) {
MyQueue myQueue = new MyQueue(10);
System.out.println("isEmpty()=" + myQueue.isEmpty());
System.out.println("isFull()=" + myQueue.isFull());
System.out.println("getSize()=" + myQueue.getSize());
for (int i = 0; i < 9; i++) {
myQueue.add(i * 100);
myQueue.remove();
}
System.out.println("----------------------------");
System.out.println("isEmpty()=" + myQueue.isEmpty());
System.out.println("isFull()=" + myQueue.isFull());
System.out.println("getSize()=" + myQueue.getSize());
}
运行结果
isEmpty()=true
isFull()=false
getSize()=0
----------------------------
isEmpty()=false
isFull()=true
getSize()=0
我们添加了9次,然后又移除了9次,结果队列竟然满了,如果我们再添加一次的话肯定会抛异常,但实际上队列的size是0,还是空的,也就是说数组的每个位置只能使用一次,这样就造成了极大的浪费。那么前面使用过的空间还能不能再次利用了呢,实际上是可以的,我们可以把队列看成是环形的,当tail到达数组末尾的时候,如果数组的前面有空位子,我们可以让tail从头开始,这个时候一个新的队列就产生了,那就是双端队列。
双端队列
双端队列的队首和队尾都可以添加和删除元素,这样空间就可以循环利用了,不会造成浪费。
public class MyQueue<E> {
private Object[] data;
private int front;
private int tail;
public MyQueue(int maxSize) {
data = new Object[maxSize];
}
// //空间扩容,这里选择扩大一倍
private void doubleCapacity() {
int p = front;
int n = data.length;
// 扩大一倍
Object [] newData = new Object[n<<1];
// 先 copy 后面的r个
System.arraycopy(data, p, newData, 0, n-p);
// 再 copy 前面的p个
System.arraycopy(data, 0, newData, n-p, p);
data = newData;
// 重新调整 front 和 tail 的值
front = 0;
tail = n;
}
// 添加到第一个
public void addFirst(E e) {
// 添加到 front 的前面,所以 front-1
front = (front - 1 + data.length) % data.length;
data[front] = e;
if (front == tail) // 如果已满就扩容
doubleCapacity();
}
// 添加到最后一个
public void addLast(E e) {
// 因为 tail 位置是空的
data[tail] = e;
tail = (tail + 1) % data.length;
if (tail == front)//判断是否满
doubleCapacity();
}
// 删除第一个
public E removeFirst() {
if (isEmpty())
throw new IllegalArgumentException("队列是空的,无法移除……");
E e = (E)data[front];
data[front] = null;
front = (front + 1 + data.length) % data.length;
return e;
}
// 删除最后一个
public E removelast() {
if (isEmpty())
throw new IllegalArgumentException("队列是空的,无法移除……");
tail = (tail - 1 + data.length) % data.length;
E e = (E)data[tail];
data[tail] = null;
return e;
}
// 返回第一个
public E peekFirst() {
if (isEmpty())
throw new IllegalArgumentException("队列是空的,无法移除……");
return (E)data[front];
}
// 返回最后一个
public E peekLast() {
if (isEmpty())
throw new IllegalArgumentException("队列是空的,无法移除……");
return (E)data[(tail - 1 + data.length) % data.length];
}
public boolean isEmpty() {
//队列头和队列尾指向同一空间的时候,并且没到队尾,表示队列是空的
return front == tail;
}
public int getSize() {
return (tail - front + data.length) % data.length;
}
测试一下
public static void main(String[] args) {
MyQueue myQueue = new MyQueue(10);
System.out.println("isEmpty()=" + myQueue.isEmpty());
System.out.println("getSize()=" + myQueue.getSize());
for (int i = 0; i < 5; i++)
myQueue.addFirst(i * 100);
for (int i = 5; i < 10; i++)
myQueue.addLast(i * 100);
myQueue.removeFirst();
myQueue.removelast();
System.out.println("----------------------------");
System.out.println("isEmpty()=" + myQueue.isEmpty());
System.out.println("getSize()=" + myQueue.getSize());
System.out.println("----------------------------");
System.out.println("First Element=" + myQueue.peekFirst());
System.out.println("Last Element=" + myQueue.peekLast());
}
}
运行结果
isEmpty()=true
getSize()=0
----------------------------
isEmpty()=false
getSize()=8
----------------------------
First Element=300
Last Element=800