1.什么是优先级队列(priority Queue)
队列是一种先进先出的数据结构,有的时候,我们可能需要被操作的数据带有优先级之分,出队列时,先出优先级高的元素,比如打游戏时,来了一个电话或者一个消息,我们需要优先处理电话和消息,所以就有提示来电。
在这样的情况下,我们就要使用优先级队列,我们的数据结果应该提供两个基本操作,一是返回最高优先级对象,二是添加新对象,我们把这样的数据结构叫做优先级队列(priority Queue)。
2.优先级队列的模拟实现
priority Queue的底层使用了堆的数据结构,堆其实就是在完全二叉树的基础上对元素经行了调整
1.堆的概念(图解更好理解)
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一
个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大
堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
小根堆:
大根堆:
堆的性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树
总结:堆分为大根堆和小根堆。
- 大根堆中每颗子树的根节点的值,大于左右子树的值
- 小根堆中每颗子树的根节点的值,小于左右子树的值
2堆的存储方式
堆是一颗完全二叉树,因此可以使用层序的规则采取顺序的方式存储它(使用数组)
3实现优先级队列讲解 (代码)
优先级队列底层是堆的数据结构,它的逻辑结构是完全二叉树的样子,存储结构是数组,小根堆为例
1.首先初始化元素
public class PriorityQueue{
public int[] elem;//用数组来存储元素
public int UsedSize;//记录有效数的个数
public PriorityQueue(){
this.elem = new int[10];//初始大小为10
this.UsedSize = 0;
}
}
2.对数组进行赋值
public void InitQueue(int[] array){
elem = Arrays.copyOf(array,array.length);//给elem赋值
UsedSize = elem.length;
}
public static void main(String[] args) {
int[] array = {27,15,19,18,28,34,65,49,25,37};
PriorityQueue priorityQueue = new PriorityQueue();
priorityQueue.InitQueue(array);
}
3.进行大小堆的创建,以下以小根堆为例
创建前我们需要知道根节点和左右子树的节点下标怎么求
将元素存储到数组之后,假设i为节点的下标:
public void createHeap(int[] elem){
for(int parent = (UsedSize-1-1)/2; parent >= 0;parent--){
shiftDown(parent,UsedSize);//UsedSize作为结束标志
}
}
//向下调整 这里建立一个小根堆
public void shiftDown(int parent,int len){
int child = (parent*2)+1;//左孩子
//判断是否有左孩子
while(child < len){
// child+1 < len 至少有右孩子 否则child+1越界
if(child+1 < len && elem[child] > elem[child+1]){
child++;//左右子树中保存较小值
}
//小于根时,交换
if(elem[child] < elem[parent]){
swap(elem,parent,child);
//交换完后不能保证整个树是小根堆
//需要向下调整直到是小根堆
parent = child;
child = parent*2+1;
}else{
break;//向下调整,if不满足,此时一定时一个小根堆
}
}
}
public void swap(int[] elem,int parent,int child){
int tmp = elem[parent];
elem[parent] = elem[child];
elem[child] = tmp;
}
4.入队操作
public void offer(int x){
if(Full()){
elem = Arrays.copyOf(elem,elem.length*2);
}
elem[UsedSize] = x;
UsedSize++;
shiftUp(UsedSize-1);
}
//向上调整
public void shiftUp(int child){
int parent = (child-1)/2;
while(child > 0){//child会一直向上移动
if(elem[child] < elem[parent]){
swap(elem,child,parent);
child = parent;
parent = (child-1)/2;
}else{
break;
}
}
}
public boolean Full(){
return UsedSize == elem.length;
}
5.出队操作
public int poll(){
if(Empty()){
return -1;
}
int tmp = elem[0];//保存出队的元素
swap(elem,0,UsedSize-1);
UsedSize--;//--后,有效数个数减少,也就是删除
shiftDown(0,UsedSize);//UsedSize结束 从0下标开始向下调整
return tmp;
}
public boolean Empty(){
return UsedSize == 0;
}
6.查看最高优先级元素
public int peek(){
if(Empty()){
return -1;
}
return elem[0];
}
4完整代码
import java.util.Arrays;
public class PriorityQueue{
public int[] elem;//用数组来存储元素
public int UsedSize;//记录有效数的个数
public PriorityQueue(){
this.elem = new int[10];
this.UsedSize = 0;
}
public void InitQueue(int[] array){
elem = Arrays.copyOf(array,array.length);//给elem赋值
UsedSize = elem.length;
}
public void createHeap(int[] elem){
for(int parent = (UsedSize-1-1)/2; parent >= 0;parent--){
shiftDown(parent,UsedSize);//UsedSize作为结束标志
}
}
//向下调整 这里建立一个小根堆
public void shiftDown(int parent,int len){
int child = (parent*2)+1;//左孩子
//判断是否有左孩子
while(child < len){
// child+1 < len 至少有右孩子 否则child+1越界
if(child+1 < len && elem[child] > elem[child+1]){
child++;//左右子树中保存较小值
}
//小于根时,交换
if(elem[child] < elem[parent]){
swap(elem,parent,child);
//交换完后不能保证整个树是小根堆
//需要向下调整直到是小根堆
parent = child;
child = parent*2+1;
}else{
break;//向下调整,if不满足,此时一定时一个小根堆
}
}
}
public void offer(int x){
if(Full()){
elem = Arrays.copyOf(elem,elem.length*2);
}
elem[UsedSize] = x;
UsedSize++;
shiftUp(UsedSize-1);
}
//向上调整
public void shiftUp(int child){
int parent = (child-1)/2;
while(child > 0){//child会一直向上移动
if(elem[child] < elem[parent]){
swap(elem,child,parent);
child = parent;
parent = (child-1)/2;
}else{
break;
}
}
}
public int poll(){
if(Empty()){
return -1;
}
int tmp = elem[0];//保存出队的元素
swap(elem,0,UsedSize-1);
UsedSize--;//--后,有效数个数减少,也就是删除
shiftDown(0,UsedSize);//UsedSize结束 从0下标开始向下调整
return tmp;
}
public int peek(){
if(Empty()){
return -1;
}
return elem[0];
}
public boolean Full(){
return UsedSize == elem.length;
}
public boolean Empty(){
return UsedSize == 0;
}
public void swap(int[] elem,int parent,int child){
int tmp = elem[parent];
elem[parent] = elem[child];
elem[child] = tmp;
}
public static void main(String[] args) {
int[] array = {27,15,19,18,28,34,65,49,25,37};
PriorityQueue priorityQueue = new PriorityQueue();
priorityQueue.InitQueue(array);
}
}