普通的队列是一种先进先出的数据结构,元素先在队列尾追加、而从队列头删除。
优先队列按照其作用不同,可以分为以下两种:
最大优先队列:
可以获取并删除队列中最大的值;
最小优先队列:
可以获取并删除队列中最小的值。
最大优先队列api设计:
堆这种结构可以方便删除最大的值,所以,我们可以基于堆区实现最大优先队列。
package com.yyy;
//继承Comparable接口,给每个数据提供比较规则
public class MaxPriorityQueue<T extends Comparable<T>> {
//记录堆中元素的个数
private int N;
//记录堆中元素的个数
private T[] items;
//创建容量为capacity的MaxPriorityQueue对象
public MaxPriorityQueue(int capacity){
this.N=0;
this.items = (T[]) new Comparable[capacity + 1];
}
//判断堆中索引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 tmp = items[i];
items[i]=items[j];
items[j]=tmp;
}
//删除队列中最大的元素,并返回这个最大元素
public T delMax(){
if(N==0){
return null;
}
T max= items[1];
exch(1,N);
N--;//把最大的数据放到最后,最小的数据放到第一个结点,N--就删除了最后一个结点
sink(1);//将换过来的结点进行下沉
return max;
}
//往队列中插入一个元素
public void insert(T t){
items[++N]=t;
swim(N);
}
//使用上浮算法,使索引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){
//1.找出当前结点的较大的子结点
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(k,max)){//k>=max,则退出
break;
}
exch(k,max);
k=max;
}
}
//获取队列中元素的个数
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N==0;
}
}
测试代码:
package test;
import com.yyy.MaxPriorityQueue;
public class MaxPriorityQueueTest {
//创建优先队列
public static void main(String[] args) {
MaxPriorityQueue <String> queue = new MaxPriorityQueue <>(10);
//往队列中存储元素
queue.insert("A");
queue.insert("B");
queue.insert("C");
queue.insert("D");
queue.insert("E");
queue.insert("F");
//通过循环从队列中获取最大的元素
while(!queue.isEmpty()){
String max = queue.delMax();
System.out.println(max+" ");
}
}
}
最小优先队列api设计:
代码实现:
package com.yyy;
public class MinPriorityQueue<T extends Comparable<T>> {
//用来存储元素的数组
private T[] items;
//记录堆中元素的个数
private int N;
//创建容量为capacity的MinPriorityQueue对象
public MinPriorityQueue(int capacity){
this.items = (T[]) new Comparable[capacity + 1];
this.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 tmp = items[i];
items[i]=items[j];
items[j]=tmp;
}
//删除队列中最小的元素,并返回这个最小元素
public T delMin(){
if(N==0){
return null;
}
T min=items[1];
exch(1,N);//把最小的元素放到最后,最末的一个数据放到第一个结点,N--就删除了最后一个元素
N--;
sink(1);
return min;
}
//使用下沉算法,使索引k处的元素能处在一个正确的位置
private void sink(int k){
if(k<1) {
return;
}
int min;
while(2*k<=N){
if(2*k+1<=N){
if(less(2*k,2*k+1)){
min=2*k;
}else{
min=2*k;
}
}else{
min=2*k;
}
if(less(k,min)){//k>=min,则退出,否则进行后续的步骤
break;
}
exch(k,min);
k=min;
}
}
//往队列中插入一个元素
public void insert(T t){
N++;
items[N]=t;
swim(N);
}
//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
private void swim(int k){
if(N<1){
return ;
}
while(k/2>0){
if(less(k,k/2)){
exch(k,k/2);
}
k=k/2;
}
}
//获取队列中元素的个数
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N==0;
}
}
测试代码:
package test;
import com.yyy.MinPriorityQueue;
public class MinPriorityQueueTest {
public static void main(String[] args) {
MinPriorityQueue <String> queue = new MinPriorityQueue <>(10);
//往队列中存储元素
queue.insert("F");
queue.insert("E");
queue.insert("D");
queue.insert("C");
queue.insert("B");
queue.insert("A");
//通过循环从队列中获取最小的元素
while(!queue.isEmpty()){
String min = queue.delMin();
System.out.println(min+" ");
}
}
}