k:特殊的线性表—队列
队列的概念:
队列是另一种特殊的线性表,它的特殊性体现在其只允许在线性表的一端插入数据元素,在线性表的另一端删除数据元素(一般会采用在线性表的表尾那端(没被head指针所指的那端)插入数据元素,在线性表的表头(被head指针所指的那端)那端删除数据元素,因为按照此种方式进行操作的队列,无论采用的是顺序存储方式的物理结构还是链式存储方式的物理结构,其插入和删除数据元素的时间复杂度为O(1))。所以队列是一种操作受限的特殊的线性表,它具有先进先出(First In First Out,FIFO)或(Last In Last Out,LILO)的特性。
运行进行插入的一端称为队尾(rear),运行进行删除的一端成为队首(front)。队列的插入操作通常成为入队操作,而删除操作通常称为出队操作。
队列的相关API(java):
public interface Queue<T>
{
public abstract void clear();//清空
public abstract boolean isEmpty();//判空
public abstract int length();//求长度
public abstract T peek();//取队首元素
public abstract void offer(T x)throws Exception;//入队
public abstract T poll();//出队
}
同栈一样,队列也有顺序和链式两种存储结构。顺序存储结构的队列称为顺序队列,链式存储结构的队列称为链队列。
顺序队列:
对于顺序队列,采用数组的方式进行实现,在实现类中维护两个int型变量front和rear(一般而言int型够用了)用于记录队首的索引值和队尾的下一个存储单元的索引值,其值随着入队和出队的操作而发生改变。但是,由于采用数组的方式对队列进行实现,所以,其可能会发生“假溢出”的情况,所谓的“假溢出”即是因顺序队列的多次入队和出队操作后出现有存储空间,但是不能进行入队操作的溢出现象。
要解决“假溢出”问题,最好的办法就是把顺序队列所使用的存储空间看成一个逻辑上首尾相连的循环顺序队列。但是对于循环顺序队列而言,其需要考虑的一个问题是出现了判空和判满的条件均为front==rear的情况,要解决判空和判满的条件均为front==rear的情况,有三种解决的办法。
第一种:
采用少用数组中的一个存储单元的方式,当顺序存储空间的容量为maxSize时,只允许最多存放maxSize-1个数据元素。此时,队空的判断条件为front==rear,而队满的判断条件为:front==(rear+1)%maxSize
第二种:
采用设置一个boolean型标识变量flag的方法,设其初始化值为false;当入队操作成功后就置该标识为true;每当出队操作成功后,就置为false;则此时队空的判断条件为:front==rear&&!flag,而队满的判断条件为:front==rear&&flag
第三种:
采用设置一个计数器的方式,在实现队列的过程中,引入一个计数变量num,其初始化值为0,每当入队操作成功后,就将计数变量num的值加一;每当出队操作成功后,就将计数变量num的值减一,则此时队空的判断条件为:num==0,队满的判断条件为:num>0&&front==rear
采用以上任何一种解决循环顺序队列判空和判满条件相同的,计算其队列中元素个数的时候,均可以使用(rear-front+maxSize)%maxSize的计算方式计算出队列的长度,其中maxSize为数组的长度。
ps:
由于队列的实现可以在线性表的实现之上进行修改,从而得到相关的值,为此,不在此处进行实现。对于顺序队列而言,其API中相关的方法的实现其时间复杂度均为O(1)。对于链队列,其API中相关的方法的实现,其时间复杂度也均为O(1)。关于链队列和顺序队列的孰优孰劣的比较,个人认为和顺序表和链表的相同,可以参考:顺序表和链表的比较
对于链队列,其在java中相关的实现为Queue
对于顺序队列,其在java中相关的实现为Queue
对于队列,其有一个重要的变形,就是优先队列,对于优先队列,其也是队列的一种,也满足队列的相关API,但是,优先队列不满足先进先出的特点,因为优先队列在插入数据元素的时候,其不是限定在队尾进行插入的,而是顺序插入到队列的合适的位置,以确保队列的优先顺序,同时,优先队列也可以采用顺序和链式两种存储结构。一般而言,在考虑到优先队列中,既要保证快速的访问到优先级高的数据元素,又要保证可以较快的实现插入操作,所以通常以链式存储结构来实现优先队列。
对于优先队列的实现,这里进行省略。在java中,优先队列的实现类为PriorityQueue,其相关的使用及其事例,参见java中PriorityQueue优先级队列使用方法