循环队列与优先级队列的Java实现

来源:互联网 发布:智阅pdf阅读器 源码 编辑:程序博客网 时间:2024/05/16 03:13

与栈的后进先出(LIFO,Last In Frist Out)不同,队列是先进先出(FIFO,Frist In First Out),在现实中就像排队买票一样,每个人都得从队尾排队,然后排在队前的人才能先拿到票。

队列也是基本的数据结构,可以用双端链表(或者双向链表)、数组存储,我们这里用数组存储来解释循环队列。

什么是循环队列捏?假如有一辆过山车有5个位子,规定,进入过山车的人只能从车后进,车前出。这样,当五个人进入过山车后,这个队列就满了。这时,坐在最前面的人走了,应该有了个空座,可以进去一个人,但是按照规定人只能从车后进,所以不能进人,而循环队列就是相当把最后一个位子移到最后,从而使人进去。换成数组的话,就是把数组头与尾相连,形成一个圆(循环)。而使用这个数组存储的队列就叫循环队列。

循环队列与一般队列不同,需要做边界判断,因为你不知道,这个数组是否已经循环过,尤其是在做判空和判满操作时,你得考虑两种情况,在《Java数据结构与算法》中,作者做过处理,但是还是不好理解,尤其是当你没插一个数据与插满数据,队头标识位又回到起点的情况,所以我在程序中添加了一个是否已经循环的标识位,相当于,对队头队尾是否已经颠倒。其代码如下:

package test.queue;public class Queue{//存储数组、队头、队尾、是否已经循环private int[] items;private int head;private int tail;private boolean isTraned;public Queue(int size){items = new int[size];head = 0;tail = 0;isTraned = false;}//反转,用于控制计算整个队列的长度时,是否要跨边界。private void tran(){isTraned = !isTraned;}//计算长度public int size(){if(isTraned)//已经循环,需要跨边界计算return items.length + tail - head;elsereturn tail - head;}//判空public boolean isEmpty(){return size()<=0;}//判满public boolean isFull(){return size()>=items.length;}//插入public void insert(int in){if(isFull())throw new IndexOutOfBoundsException("队列已满");else{items[tail++] = in;if(tail == items.length){tail = 0;tran();}}}//移除public int remove(){int out = 0;if(isEmpty())throw new IndexOutOfBoundsException("队列为空");else{out = items[head++];if(head == items.length){head = 0;tran();}}return out;}//查看public int peek(){if(isEmpty())throw new IndexOutOfBoundsException("队列为空");elsereturn items[head];}public static void main(String[] args) {Queue q = new Queue(3);q.insert(3);q.insert(2);System.out.println(q.remove());System.out.println(q.remove());q.insert(11);q.insert(12);System.out.println(q.remove());System.out.println(q.remove());q.insert(100);q.insert(101);q.insert(102);System.out.println(q.remove());System.out.println(q.remove());System.out.println(q.remove());}}

运行一下:

321112100101102

大家可以试试,如果在q.insert(102);后再insert。或者System.out.println(q.remove());再remove都会出现IndexOutOfBoundsException错误。

我们再来看看优先级队列。

优先级队列可以这样理解,就好像一个奇怪的电影院,也需要排队买票,但是他对规定:必须按照从高到矮的顺序排队。也就是说,新来的人必须在队伍中找到高矮正合适的位置,而先拿到票的永远是队伍中最矮的。

相对于前面循环队列,优先级队列没有队尾,队头即元素数,也不用判断边界,所不同的是需要一个插入算法,其代码如下:

package test.queue;public class PriorityQueue{//存储数组、已有元素个数private int[] items;private int itemNum;public PriorityQueue(int size){items = new int[size];itemNum = 0;}//个数public int size(){return itemNum;}//判满public boolean isFull(){return itemNum >= items.length;}//判空public boolean isEmpty(){return itemNum <= 0;}//移除public int remove(){if(isEmpty())throw new IndexOutOfBoundsException("队列为空");elsereturn items[--itemNum];}//插入public void insert(int in){if(isFull())throw new IndexOutOfBoundsException("队列已满");else{int i = itemNum - 1;while(i >= 0 && items[i] < in)//按照从小到大的顺序排列,这里有点像插入排序。{items[i+1]=items[i];i--;}items[i+1] = in; itemNum++;}}//查看队前元素public int peek(){return items[itemNum - 1];}public static void main(String[] args) {PriorityQueue pq = new PriorityQueue(3);pq.insert(8);pq.insert(4);pq.insert(6);System.out.println(pq.remove());System.out.println(pq.remove());System.out.println(pq.remove());}}

运行一下:

468

大家可以看出的确是从小到大输出了。

原创粉丝点击