队列概念
队列(Queue)是限定只能在一端插入、另一端删除的线性表。允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear),没有元素的队列称为“空队列”。
队列具有先进先出(FIFO)的特性。
普通顺序队列存在的问题
在普通顺序队列中,入队的操作就是先将尾指针rear右移一个单位,然后将元素值赋值给rear单位。出队时,则是头指针front后移一个单位。像这样进行了一定数量的入队和出队操作后,可能会出现这样的情况:
尾指针rear已指到数组的最后有一个元素,即rear==MaxLen-1,此时若再数组的前面部分可能还有很多闲置空间,即这种溢出并非是真的没有可用的存储空间,故称这种溢出现象为“假溢出”。显然,必须要解决这一块假溢出的问题,否则顺序队列就没有太多使用价值。
循环队列
说明:
1. 判断满条件为 front = (rear + 1) % size 即满
2. 每入队一个元素, tail = (tail + 1) % size
3. 令队列空间中的一个单元闲置,使得队列非空时,rear与front之间至少间隔一个空闲单。
循环队列:
1 public class LoopQueue<E> implements Queue<E> { 2 3 private E[] data; 4 private int front,tail; 5 private int size; 6 7 public LoopQueue(int capacity){ 8 //需要多一个空间 留空 9 data = (E[])new Object[capacity+1]; 10 front = 0; 11 tail = 0; 12 size = 0; 13 } 14 15 public LoopQueue(){ 16 this(10); 17 } 18 19 public int getCapacity(){ 20 return data.length - 1; 21 } 22 23 @Override 24 public boolean isEmpty(){ 25 return front == tail; 26 } 27 28 @Override 29 public int getSize(){ 30 return size; 31 } 32 33 //入队 34 @Override 35 public void enqueue(E e){ 36 //队列满了判断 37 if ((tail + 1) % data.length == front) 38 resize(getCapacity() * 2); 39 40 data[tail] = e; 41 tail = (tail + 1) % data.length; 42 size++; 43 } 44 45 //出队 46 @Override 47 public E dequeue(){ 48 49 if (isEmpty()) 50 throw new IllegalArgumentException("Cannot dequeue from an empty queue"); 51 52 E ret = data[front]; 53 //data[front] = null; 54 front = (front + 1) % data.length; 55 size --; 56 57 //缩容 58 if (size == getCapacity() / 4 && getCapacity() / 2 != 0 ) 59 resize(getCapacity() / 2); 60 61 return ret; 62 } 63 64 @Override 65 public E getFront(){ 66 if (isEmpty()) 67 throw new IllegalArgumentException("Cannot dequeue from an empty queue"); 68 69 return data[front]; 70 } 71 72 private void resize(int newCapacity){ 73 E[] newData = (E[])new Object[newCapacity + 1]; 74 for (int i = 0; i < size; i++){ 75 //把旧的数组的首元素 放入到新的元素中 ,这里不用i,因为i不一定是首位元素 76 newData[i] = data[(front + i) % data.length]; 77 } 78 79 data = newData; 80 front = 0; 81 tail = size; 82 } 83 84 //覆盖父类 85 @Override 86 public String toString() { 87 StringBuilder res = new StringBuilder(); 88 res.append(String.format("Queue:size = %d,capacity = %d\n", size, getCapacity())); 89 res.append("front ["); 90 for (int i = front; i != tail; i = (i + 1) % data.length){ 91 res.append(data[i]); 92 if ((i + 1) % data.length != tail) 93 res.append(", "); 94 } 95 res.append("] tail"); 96 97 return res.toString(); 98 } 99 100 }