Java数据结构和算法-栈和队列(3-优先级队列)

时间:2022-12-28 16:20:43

优先级队列是比栈和队列更为专用的数据结构,它和普通的队列一样有一个队尾和一个队头,并且每一次移除数据项时,都从队头处移除,不同的地方在于,优先级队列是按照关键字有序排列的,比如在本文中,我们将优先级队列按照关键字从队头到队尾由大到小排列,那么关键字越大越接近队头也就越早会被移除(访问)。也正因为这个性质,所以优先级队列的插入不是在队尾插入,而是根据关键字的值被插入合适的位置。
以之前讲的职员安排工作的例子为例,如果职员只是按照工作的先后顺序,先进后出,而不关心工作的重要性,那么用普通的队列即可,但是当不同的工作重要性不同时,职员就必须按照工作的重要性来安排优先级,在队头先放入最重要的工作,然后次重要,最后是不重要的,这样才不会发生意外。
优先级队列同栈和队列一样,是程序员的一个重要辅助工具。比如在后面要将的图的最小生成树算法就利用了优先级队列来实现。
优先级队列在计算机系统中也有很多的应用,例如,抢先式多任务操作系统中,程序排列在优先级队列当中,这样优先级高的程序就会显得到时间片并得以运行。
除了能够快速访问优先级高的数据项之外,优先级队列也必须要有较快插入速度。优先级队列可以通过数组和堆来实现,堆能够满足这个条件,但是由于还未讲,所以本文先以数组来实现。虽然数组插入会比较慢,但它也比较简单,使用数据量小并且不怎么关心插入速度的情况。
在以下的图中,显示了优先级队列的插入和移除数据的过程:
Java数据结构和算法-栈和队列(3-优先级队列)
Java数据结构和算法-栈和队列(3-优先级队列)

优先级队列的Java代码

在优先级队列实现当中,我们没有使用循环队列进行回绕,因为要找到合适的位置,插入会很慢,虽然删除速度很快,但是回绕并不会改善这种情况。队头的位置始终是在下标为nItem-1的位置,而队尾的位置下标为0是保持不变的,因此我们在代码中不需要再使用这两个变量

class PriorityQueue {
private int maxSize;
private int[] array;
private int nItem;

public PriorityQueue(int s) {
maxSize = s;
array = new int[s];
nItem = 0;
}

public void insert(int val) {
int i;
for(i = nItem- 1; i >= 0; i --) {
if(array[i] > val)
array[i + 1] = array[i];
else
break;
}
array[i + 1] = val;
nItem ++;
}

public int remove() {

return array[-- nItem];
}

public int peak() {
return array[nItem - 1];
}

public int size() {
return nItem;
}

public boolean isEmpty() {
return (nItem == 0);
}

public boolean isFull() {
return (nItem == maxSize);
}
}

在使用上述的remove方法和insert方法时必须先判断队列是否为空和是否已满。对于移除数据,比较简单,当队列不为空时,移除队头所指数据即可。对于插入数据,当队列为空时,只需在下标为0的位置插入新数据,并且将队头指向该位置,如果队列中已存在数据,那么就从队头开始,将数据不断上移,直到找到新数据插入的合适位置。此时队头的位置也因为移动,上移了一个位置。

优先级队列的效率

优先级队列的插入消耗的的时间与数据项的个数N有关,需要O(N)的时间。移除操作和队列相同,所消耗的时间为O(1)。