系列文章目录
01 Java基本数据结构之栈实现
02 Java基本数据结构之队列实现
03 Java基本数据结构之优先级队列
04 Java基本数据结构之链表
如有错误,还请指出
前言
在阅读本篇内容前希望简单看看上一篇关于队列的介绍,然后仍然先简单介绍一下优先级队列,然后是整体的代码实现,和普通队列的实现基本只有插入数据部分的不同,最后对每个部分需要注意的点作了详细说明。
一、优先级队列(简述)
优先级队列是比栈和队列更专用的数据结构。但它在很多情况下很有用,像普通队列一样,优先级队列有一个队头和队尾,并且也是从队头移除数据。不过在优先级队列中,数据项根据关键字的值有序,比如关键字最小的数据项总是在队头(比如要寻找最便宜的方法或者最短路径去做某件事情)。数据项在插入的时候会按照顺序插入到合适的位置以确保队列的顺序。
仍以书中美国邮政服务为例,邮政局收到信时,会投入到一个专门的筐里,待有空闲时间的时候,从上到下处理这写堆叠的信件,但对于紧急需要处理的信会放到最上面优先处理,不太重要的则堆积到下面去。
二、优先级队列-数组实现
优先级队列通常使用一种称为 堆 的数据结构来实现,本次使用简单的数组来实现优先级队列,这种方法插入比较慢,但它比较简单,适用于数据量小且不是特别注重插入速度的情况。
package queue;
/*
* 数组实现的循环队列 有数据项计数字段
* insert : 判断isFull 队尾指针先+1,再插值,到达最大索引时队尾指针则置为-1,接着+1插值
* remove : 判断isEmpty 出队,队头指针+1,出队后队头指针大于最大索引时,队头指针置为0,
* peekFront 查看队头
* isEmpty
* isFull
* size
* */
/*
* 优先级队列,数据小的优先出队
* insert
* remove
* peekFront 查看队头
* isEmpty
* isFull
* size
* */
public class Queue03 {
private long[] queArray;
private int maxSize;
private int nItems;
public Queue03(int maxSize) {
this.queArray = new long[maxSize];
this.maxSize = maxSize;
this.nItems = 0;
}
public void insert(long item) throws Exception {
if (isFull()) throw new Exception("队列已满");
if (nItems==0)
queArray[nItems++]=item;
else {
// 遍历插入,小的在上面(队列前面)
int i;
for (i = nItems - 1; i >= 0; i--) {
if (queArray[i] >= item)
break;
else
//当前位置小于 item则当前数据上移
queArray[i + 1] = queArray[i];
}
queArray[i + 1] =item;
nItems++;
}
}
public long remove() throws Exception {
if (isEmpty()) throw new Exception("队列空");
return queArray[--nItems];
}
public long peekFront(){
return queArray[nItems-1];
}
//
public boolean isEmpty() {
return nItems == 0;
}
public boolean isFull() {
return nItems == maxSize;
}
public int size() {
return nItems;
}
@Override
public String toString() {
return "Queue03{" +
"queArray=" + Arrays.toString(queArray) +
", maxSize=" + maxSize +
", nItems=" + nItems +
'}';
}
}
三、注意点
3.1 循环队列
注意在优先级队列的实现中没有使用指针回绕。因为插入数据要找到合适的位置,所所以优先级队列的插入肯定很慢的,不过删除很快(总是删除队头的数据,并且队头的数据是满足关键字最小或者最大)。实现指针回绕不能改善这种情况。还要注意队尾指针从不移动,它总是指着数组底端下标为0的单元。
3.2构造方法
优先级队列不像普通的队列那样必须又front
,rear
字段,它的front
总是等于nItems-1
,rear
总是等于0.
3.3 insert () 入队
插入操作时,主要是需要对队列做一个遍历,找到刚好比插入数据大的位置(这里假设数据小的优先出队,放在队列前面)。因此,遍历队列,找到目标位置退出循环,反之移动到下一个数据项。
public void insert(long item) throws Exception {
if (isFull()) throw new Exception("队列已满");
if (nItems==0)
queArray[nItems++]=item;
else {
// 遍历插入,小的在上面(队列前面)
int i;
for (i = nItems - 1; i >= 0; i--) {
if (queArray[i] >= item)
break;
else
//当前位置小于 item则当前数据上移
queArray[i + 1] = queArray[i];
}
queArray[i + 1] =item;
nItems++;
}
}
3.4 remove() 出队
待出队的数据项总是在数组的高端,所以删除又快又容易。删除数据项后,队头指针下移,指向队列新的高端,不需要移动和比较其他数据项。
测试
public static void main(String[] args) throws Exception {
System.out.println("优先级队列,数据小的优先出队");
Queue03 queue03=new Queue03(5);
queue03.insert(20);
queue03.insert(40);
queue03.insert(10);
queue03.insert(30);
queue03.insert(50);
System.out.println(queue03);
int j=queue03.size();
for (int i = 0; i <j ; i++) {
System.out.println(queue03.remove());
}
/*
优先级队列,数据小的优先出队
Queue03{queArray=[50, 40, 30, 20, 10], maxSize=5, nItems=5}
10
20
30
40
50
*/