优先队列

优先队列

最大堆

最大堆是指每个根节点都大于等于左右子节点。例如下图
在这里插入图片描述

最小堆

最小堆是指每个根节点都小于等于左右子节点。例如下图

在这里插入图片描述

堆的表示

以上图最小堆为例子
它对应的数组为1,2,3,17,19,36,7,25,100
假设下标从0开始,那么1的小标是0,2的小标是1,3的小标是2.
可以发现规律若根节点下标i
那么左孩子的下标是2i+1
右孩子的下标是2
i+2

入堆

只演示最小堆
在这里插入图片描述
假设现在堆的元素如上图所示,要把2入堆
第一步2和父亲5比较
5明显大于2,把父亲下调到2的位置,如下图所示
在这里插入图片描述
第二步2和3比较
3明显大于2,把3下调,如下图所示
在这里插入图片描述
第三步2和1比较
2>1 不需要再调整了,直接把2放在1的左边

在这里插入图片描述代码如下

	public boolean enque(int in) {
		//不允许0是因为出堆的时候size=0的时候我想返回0,所以干脆就不允许入堆0
		if(in==0)return false;
        int i = size++;//当前节点的下标
        if(i>=capacity)return false;
        while(i>0){
            int par = (i-1)/2;//父亲的下标
            //flag==false 最小堆
            //falg=true 最大堆
            if(!flag?queue[par]<=in:queue[par]>=in)break;
            
            queue[i] = queue[par];//把父亲的值放下来
            i = par;//自己的下标提上去
        }
        queue[i] = in;//把入堆元素放在合适的位置
        return true;
    }

代码看不懂没关系,手动模拟一遍就看懂了,然后多写几遍代码就自然会写了。

出堆

只演示最小堆
在这里插入图片描述
如上图所示:现在要出堆
第一步暂存temp=1,用最后一个元素8代替堆顶,并重置堆尾为0,size–, 操作后如下图所示
在这里插入图片描述
第二步,对8进行最小堆调整,让8与左右孩子较小的交换,交换后如下图
在这里插入图片描述
第三步,此时8还是不满足最小堆的性质,还要对8进行调整,让8与左右孩子较小的交换,交换后如下图
在这里插入图片描述
出堆代码如下

	public int dequeue(){
        if(size==0)return 0;
        int temp = queue[0];//保留 出堆的元素
        --size;
        queue[0] = queue[size];//最后一个元素赋给堆顶
        queue[size] = 0;//最后一个置为0
        //对根节点进行调整
        sift(queue,0,size-1);
        return temp;
    }
    
    //调整算法
    //k是待调整的节点的下标
    //m是最后一个元素的下标
    public void sift(int[] arr,int k,int m){
        int i = k;//i指向待调整的节点
        int j = 2*i+1;//j先指向左孩子
        while(j<=m){
            if(!flag){//最小堆
                if(j<m&&arr[j]>arr[j+1]){//右孩子较小,j应该指向右孩子
                    ++j;
                }
                if(arr[i]<arr[j]){//已经是最小堆了,break
                    break;
                }
            }else{//最大堆
                if(j<m&&arr[j]<arr[j+1]){//右孩子较大,j指向右孩子
                    ++j;
                }
                if(arr[i]>arr[j]){//已经是最大堆,break
                    break;
                }
            }
            swap(arr,i,j);//交换
            i=j;//继续向下调整
            j=2*i+1;
        }
    }

完整代码

public class PriorityQueue  {
    private int size;
    private int capacity = 10;
    private int[] queue;
    private boolean flag;//false:默认最小堆,true代表最大堆

    public PriorityQueue(boolean flag,int capacity){
        this.flag = flag;
        this.capacity = capacity;
        queue = new int[capacity];
    }
    public PriorityQueue(boolean flag){
        this.flag = flag;
        queue = new int[capacity];
    }
    //默认最小堆
    public PriorityQueue(int capacity){
        this.capacity = capacity;
        queue = new int[capacity];
    }
    //默认最小堆 默认capacity = 10;
    public PriorityQueue(){
        queue = new int[capacity];
    }

    public int dequeue(){
        if(size==0)return 0;
        int temp = queue[0];//保留 出堆的元素
        --size;
        queue[0] = queue[size];//最后一个元素赋给堆顶
        queue[size] = 0;//最后一个置为0
        //对根节点进行调整
        sift(queue,0,size-1);
        return temp;
    }
    //调整算法
    //k是待调整的节点的下标
    //m是最后一个元素的下标
    public void sift(int[] arr,int k,int m){
        int i = k;//i指向待调整的节点
        int j = 2*i+1;//j先指向左孩子
        while(j<=m){
            if(!flag){//最小堆
                if(j<m&&arr[j]>arr[j+1]){//右孩子较小,j应该指向右孩子
                    ++j;
                }
                if(arr[i]<arr[j]){//已经是最小堆了,break
                    break;
                }
            }else{//最大堆
                if(j<m&&arr[j]<arr[j+1]){//右孩子较大,j指向右孩子
                    ++j;
                }
                if(arr[i]>arr[j]){//已经是最大堆,break
                    break;
                }
            }
            swap(arr,i,j);//交换
            i=j;//继续向下调整
            j=2*i+1;
        }
    }
    public static  void swap(int[] arr, int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    public int take() {
        return size==0?0:queue[0];
    }
    //入堆 不允许0
    public boolean enque(int in) {
        if(in==0)return false;
        int i = size++;//当前节点的下标
        if(i>=capacity)return false;
        while(i>0){
            int par = (i-1)/2;//父亲的下标
            //flag==false 最小堆
            //falg=true 最大堆
            if(!flag?queue[par]<=in:queue[par]>=in)break;

            queue[i] = queue[par];//把父亲的值放下来
            i = par;//自己的下标提上去
        }
        queue[i] = in;//把入堆元素放在合适的位置
        return true;
    }

    public int size() {
        return size;
    }
    public int[] getQueue(){
        return queue;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值