五千字详解—优先级队列的模拟实现(代码)

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.堆总是一棵完全二叉树

总结:堆分为大根堆和小根堆。

  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);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

keild

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值