优先队列
普通的队列是一种先进先出的数据结构,元素在队列尾部追加,从而队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下,计算机的任务都是有优先级的,我们需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,我们就可以使用一种特殊的队列完成这种需求,优先队列。
优先队列按照其作用不同,可以分为以下两种:
最大优先队列:
可以获取并删除队列中最大的值;
最小优先队列:
可以获取并删除队列中最小的值;
最大优先队列API设计;
类名:MaxPriorityQueue
构造方法:public MaxPriorityQueue(int capacity):创建容量为capacity的MaxPriorityQueue对象;
成员方法:
1:public int size():获取队列中元素的个数
2: public boolean isEmpty():断队列是否为空
3:private boolean less(int i,int j):判断堆中索引i处的元素是否小于索引j处的元素
4: private void exch(int i,int j):交换堆中i索引和j索引处的值
5: public void insert(T t):往堆中插入一个元素
6: public T delMax():删除堆中最大的元素,并返回这个最大元素
7:private void swim(int k):使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
8:private void sink(int k):使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
成员变量:
1:private T[] items:存储堆中的元素
2:private int N:记录堆中元素的个数
实现代码如下:
public class MaxPriorityQueue<T extends Comparable<T>> {
//存储堆中的元素
private T[] items;
//记录堆中元素的个数
private int N;
public MaxPriorityQueue(int capacity){
this.items = (T[]) new Comparable[capacity+1];
this.N = 0;
}
//获取队列中元素的个数
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N == 0;
}
//判断堆中索引i处的元素是否小于索引j处的元素
private boolean less(int i,int j){
return items[i].compareTo(items[j]) < 0;
}
//交换堆中i索引和j索引处的值
private void exch(int i,int j){
T temp;
temp = items[i];
items[i] = items[j];
items[j] = temp;
}
//往堆中插入一个元素
public void insert(T t){
items[++N] = t;
//使用上浮算法使堆有序
swim(N);
}
//删除堆中最大的元素,并返回这个最大元素
public T delMax(){
//利用max保存索引1处的最大值
T max = items[1];
//交换
exch(1,N);
//删去最大元素,元素个数-1
N--;
//使用下沉算法使堆有序
sink(1);
//返回最大值
return max;
}
//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
private void swim(int k){
while (k > 1){
//比较其父结点和本身的大小
if(less(k/2,k)){
exch(k/2,k);
}
k = k/2;
}
}
//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
private void sink(int k){
while (2*k <= N){
//记录最大元素
int max;
if(2*k+1 <= N){//父结点有左子和右子
if(less(2*k,2*k+1)){
max = 2*k+1;
}else {
max = 2*k;
}
}else {//父结点只有左字
max = 2*k;
}
//判断父结点是否小于子结点
if(less(max,k)){
break;
}else {
//
exch(k,max);
k = max;
}
}
}
}
测试代码如下:
public class MaxPriorityQueueTest {
public static void main(String[] args) {
//创建优先队列
MaxPriorityQueue<String> queue = new MaxPriorityQueue<>(15);
//往队列中存储元素
queue.insert("a");
queue.insert("m");
queue.insert("b");
queue.insert("l");
queue.insert("c");
queue.insert("k");
queue.insert("d");
queue.insert("j");
queue.insert("e");
queue.insert("i");
queue.insert("f");
queue.insert("h");
queue.insert("g");
//通过循环从队列中获取最大的元素
while (!queue.isEmpty()){
String max = queue.delMax();
System.out.print(max+" ");
}
}
}
测试结果如下:
最小优先队列API设计;
类名:MinPriorityQueue
构造方法:public MinPriorityQueue(int capacity):创建容量为capacity的MaxPriorityQueue对象;
成员方法:
1:public int size():获取队列中元素的个数
2: public boolean isEmpty():断队列是否为空
3:private boolean less(int i,int j):判断堆中索引i处的元素是否小于索引j处的元素
4: private void exch(int i,int j):交换堆中i索引和j索引处的值
5: public void insert(T t):往堆中插入一个元素
6: public T delMin():删除堆中最小的元素,并返回这个最小元素
7:private void swim(int k):使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
8:private void sink(int k):使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
成员变量:
1:private T[] items:存储堆中的元素
2:private int N:记录堆中元素的个数
实现代码如下:
public class MinPriorityQueue<T extends Comparable<T>>{
//存储堆中的元素
private T[] items;
//记录堆中元素的个数
private int N;
public MinPriorityQueue(int capacity){
this.items = (T[]) new Comparable[capacity+1];
this.N = 0;
}
//获取队列中元素的个数
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N == 0;
}
//判断堆中索引i处的元素是否小于索引j处的元素
private boolean less(int i,int j){
return items[i].compareTo(items[j]) < 0;
}
//交换堆中i索引和j索引处的值
private void exch(int i,int j){
T temp;
temp = items[i];
items[i] = items[j];
items[j] = temp;
}
//往堆中插入一个元素
public void insert(T t){
items[++N] = t;
swim(N);
}
//删除堆中最小的元素,并返回这个最小元素
public T delMin(){
T min = items[1];
exch(1,N);
N--;
sink(1);
return min;
}
//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
private void swim(int k){
while (k > 1){
//比较其父结点和本身的大小
if(less(k,k/2)){
exch(k,k/2);
}
k = k/2;
}
}
//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
private void sink(int k){
while (2*k <= N){
//记录最小元素
int min;
if(2*k+1 <= N){//父结点有左子和右子
//找最小值往前方
if(less(2*k,2*k+1)){
min = 2*k;
}else {
min = 2*k+1;
}
}else {//父结点只有左字
min = 2*k;
}
//判断父结点是否小于子结点
if(less(k,min)){
break;
}else {
//交换元素
exch(k,min);
k = min;
}
}
}
}
测试代码如下:
public class MinPriorityQueueTest {
public static void main(String[] args) {
//创建优先队列
MinPriorityQueue<String> queue = new MinPriorityQueue<>(15);
//往队列中存储元素
queue.insert("a");
queue.insert("m");
queue.insert("b");
queue.insert("l");
queue.insert("c");
queue.insert("k");
queue.insert("d");
queue.insert("j");
queue.insert("e");
queue.insert("i");
queue.insert("f");
queue.insert("h");
queue.insert("g");
//通过循环从队列中获取最大的元素
while (!queue.isEmpty()){
String min = queue.delMin();
System.out.print(min+" ");
}
}
}
测试结果如下: