Java优先级队列(堆)

1 优先级队列

概念:队列是一种先进先出的数据结构,操作的数据可能带有优先级,一般出队列时可能需要优先级高的元素先出队列。

数据结构提供两种基本操作:返回最高优先级对象;添加新的对象。

2 优先级队列的模拟实现

PriorityQueue底层使用了堆的数据结构,堆是在完全二叉树的基础上进行了一些元素的调整。

2.1 堆的概念

  • 小堆(小根堆):每颗二叉树的根节点都比左右孩子小;
  • 大堆(大根堆):每颗二叉树的根节点都比左右孩子大;

2.2 堆的存储方式

堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储。

  • 已知孩子节点下标,父亲节点下标为(i-1)/2
  • 已知父亲节点下标,左右孩子节点下标分别为2*i+1、2*i+2

2.1 创建大根堆代码:

时间复杂度:O(n)

import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;
    public TestHeap(){
        this.elem=new int[10];
    }

    //向下调整
    //parent:每次调整的根节点;len:每次的结束位置
    public void shiftDown(int parent,int len){
        int child=(2*parent)+1;
        //说明这棵树没调整完
        while (child<len){

            if(child+1<len && elem[child]<elem[child+1]){
                child++;
            }
            //child下标一定是左右孩子最大值的下标
            if(elem[child]>elem[parent]){
                int tmp=elem[parent];
                elem[parent]=elem[child];
                elem[child]=tmp;
                //交换child和parent的值,使得根节点是最大值
                parent=child;
                child=2*parent+1;
            }else{
                break;
            }
        }
    }

    //创建大根堆
    public void createHeap(int[] array){
        for(int i=0;i<array.length;i++){
            this.elem[i]=array[i];
            this.usedSize++;
        }

        for (int i=(usedSize-1-1)/2;i>=0;i++){
            shiftDown(i,usedSize);
        }
    }
}

2.2 插入元素到堆中

import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;
    public TestHeap(){
        this.elem=new int[10];
    }
    //插入元素到堆中

    //向上调整
    public void shiftUp(int child){
        int parent=(child-1)/2;
        while (parent>=0){
            if(elem[child]>elem[parent]){
                int tmp=elem[parent];
                elem[parent]=elem[child];
                elem[child]=tmp;
                child=parent;
                parent=(child-1)/2;
            }else {
                break;
            }
        }
    }

    public void push(int val){
        if(isFull()){
            this.elem=Arrays.copyOf(this.elem,2*this.elem.length);//2倍扩容
        }
        this.elem[this.usedSize]=val;//将新插入的元素,放在最后一个位置
        this.usedSize++;//元素多一个,usedSize加1
        shiftUp(this.usedSize-1);
    }

    public boolean isFull(){
        return this.usedSize==this.elem.length;
    }
}

删除堆顶元素

import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;
    public TestHeap(){
        this.elem=new int[10];
    }
    //删除堆顶元素
    public int pop(){
        if(isEmpty()){
            throw new HeapEmptyException("堆为空");
        }
        int tmp=elem[0];
        elem[0]=elem[this.usedSize-1];
        elem[this.usedSize]=tmp;
        usedSize--;
        shiftDown(0,usedSize);
        return tmp;
    }
    public boolean isEmpty(){
        return this.usedSize==0;
    }
}
public class HeapEmptyException extends RuntimeException {
    public HeapEmptyException(String message) {
        super(message);
    }
}

3 堆的应用

  • 堆排序
import java.util.Arrays;

public class TestHeap {
    public int[] elem;
    public int usedSize;
    public TestHeap(){
        this.elem=new int[10];
    }
    //堆排序
    public void heapSort(){
        int end=usedSize-1;
        while (end>0){
            int tmp=elem[end];
            elem[end]=elem[0];
            elem[0]=tmp;
            shiftDown(0,end);
            end--;
        }
    }

}
  • Top-k问题

Top-k问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

时间复杂度:N*log K

  • PriorityQueue的实现

用堆作为底层结构封装优先级队列。PriorityQueue是线程不安全的。

使用PriorityQueue时要注意:

  1. 使用时必须导入 PriorityQueue 所在的包 ;
  2. PriorityQueue 中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException 异常;
  3. 不能插入 null 对象,否则会抛出 NullPointerException ;
  4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容;
  5. 插入和删除元素的时间复杂度为 O (log2N);
  6. PriorityQueue 底层使用了堆数据结构;
  7. PriorityQueue默认情况下是小堆﹣-﹣即每次获取到的元素都是最小的元素;
import java.util.Comparator;
import java.util.PriorityQueue;

public class TestDemo {
    public static void main(String[] args) {
        PriorityQueue<Integer> priorityQueue=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;//小堆
                //return o2-o1;//大堆
            }
        });
        //PriorityQueue默认小堆
        priorityQueue.offer(10);
        priorityQueue.offer(90);
        priorityQueue.offer(3);
        priorityQueue.offer(67);
        System.out.println(priorityQueue.poll());
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值