其实在上一堂课讲到了queue的接口设计。本来想将queue整个包含在上一篇文章中,但是对于队列的问题包含了很多东西,便想单独列出来说明一下。
首先我们先了解什么是队列:
队列同样是一种特殊的线性表,其插入和删除的操作分别在表的两端进行,队列的特点就是先进先出(First In First Out)。我们把向队列中插入元素的过程称为入队(Enqueue),删除元素的过程称为出队(Dequeue)并把允许入队的一端称为队尾,允许出的的一端称为队头,没有任何元素的队列则称为空队。
上篇文章中,由我的教授提出的接口是:
public interface Queue<Item> { /** * Update this Queue by adding an item on the newest end; * @param item the item to add; */ void enqueue(Item item); /** * Update this Queue by taking the oldest item off the queue * @return the item or null if there is no such item; */ Item dequeue(); /** * @return true if the queue is empty; */ boolean isEmpty(); }
这个接口都没有表明这是一个顺序队列还是一个循环队列。当然对于实际应用,顺序队列会消耗掉大量的内存空间。其中enqueu的时间复杂度是O(1),但是如果在dequeue()的时候进行位移操作,那么整个程序的复杂度为O(n).而对于循环列表,enqueue仍然是O(1)的复杂度,dequeue则降低为O(1)。
其中关于循环队列在建立的时候包含一个问题,如果将整个队列全部装满,那么front==rear的判断条件符合队列空,也符合队列满!
所以在建立队列的时候,有两种方法来解决这个问题:
1)另设一个标识为来判断是否队列满了;
2)少一个元素空间,规定front指针在rear指针的下一个位置上,即:
队空时:front=rear;
队满时:front=(rear+1)%maxsize
下面,我自己对queue接口进行实现。当然,这是一个循环队列的实现。
其中使用第二种方法对队满进行判断:
public class MyQueue<Item> implements Queue<Item>{ private static int DEFAULT_SIZE=10; private Item elements[]; private int front,rear; private int size; public MyQueue(){ elements=(Item[])new Object[DEFAULT_SIZE]; front=rear=0; size=0; } public MyQueue(int capacity) { elements=(Item[])new Object[capacity]; front=rear=0; size=0; } public int size(){ return size; } public boolean isEmpty(){ return front==rear; } public void enqueue(Item data){ if(this.front==(this.rear+1)%this.elements.length){ ensureCapacity(this.elements.length*2+1); } elements[rear]=data; this.rear=(this.rear+1)%this.elements.length; size++; } public Item dequeue(){ Item temp=this.elements[front]; this.front=(this.front)%this.elements.length; size--; return temp; } public void ensureCapacity(int capacity){ Item[] old=this.elements; this.elements=(Item[])new Object[capacity]; int j=0; for(int i=this.front;i!=this.rear;i=(i+1)%old.length){ elements[j++]=old[i]; } front=0; rear=j; } }
其中扩展了ensureCapaciy()方法。主要是对array长度不够,而扩展队列的扩展。
其实可以看到,循环队列不会要求enqueue的时候将元素往前移动,而降低了复杂度。
但是,今天上课教授告诉我,用LinkList去实现队列和堆栈是一种更好的方法
我:??????
那我们下一次将会使用LinkList实现队列和堆栈。