【数据结构】 -- 优先级队列的模拟实现 + PriorityQueue常用方法

1.优先级队列

1.1概念

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但在有些情况下,操作数据可能带有优先级,一般出队列时,可能就需要优先级高的先出队列.
这种情况下,数据结构应该包含两个最基本的操作,一个是返回优先级高的数据,另一个是添加新的数据,这种数据结构就叫做优先级队列(PriorityQueue).

在java中优先级队列(PriorityQueue)的底层是由堆这种数据结构实现的,而堆则是在完全二叉树上做出了调整.

2.优先级队列的模拟实现

2.1 堆的概念

堆是由一组元素的集合,并把所有元素按照完全二叉树的顺序存储方式存储在一维数组中,将根节点最大的堆称为最大堆或者大根堆,根节点最小的堆称为最小堆或者小根堆.

2.2 堆的性质

  • 在堆中的某一个节点大于或小于孩子节点的值
  • 堆是一颗完全二叉树
    在这里插入图片描述
    在这里插入图片描述

2.3 堆的创建

public class MyHeap {
    public int[] elme;
    public int usedSize;

    public MyHeap() {
        this.elme = new int[10];
    }

    //初始化数组
    public void initHeap(int[] arrya) {
        for (int i = 0; i < arrya.length; i++) {
            this.elme[i] = arrya[i];
            usedSize++;
        }
    }

    //创建大根堆
    public void createBigHeap(int[] arrya){
        for (int parent = (usedSize-1-1)/2; parent >= 0; parent--) {
            shiftDownBig(parent,usedSize);
        }
    }
    private void shiftDownBig(int parent,int len) {
        int child = 2*parent+1;//找到左孩子
        while(child < len) { // 保证最起码一定有左孩子
            if(child+1 < len && this.elme[child] < this.elme[child+1]) {
                child++; // 一定有右孩子,并且右孩子比左孩子大
            }
            //判断最大的孩子与parent交换
            if (this.elme[child] > this.elme[parent]) {
                //孩子大于parent 交换
                int tmp = this.elme[child];
                this.elme[child] = this.elme[parent];
                this.elme[parent] = tmp;
                parent = child;    //继续向上调整
                child = 2*parent+1;
            } else {
                break;
            }
        }
    }
    //创建小根堆
    public void createSmallHeap(int[] arrya){
        for (int parent = (usedSize-1-1)/2; parent >= 0; parent--) {
            shiftUpSmall(parent,usedSize);
        }
    }
    private void shiftUpSmall(int parent,int len) {
        int child = 2*parent+1;//找到左孩子
        while(child < len) { // 保证最起码一定有左孩子
            if(child+1 < len && this.elme[child] > this.elme[child+1]) {
                child++; // 一定有右孩子,并且右孩子比左孩子小
            }
            //判断最小的孩子与parent交换
            if (this.elme[child] < this.elme[parent]) {
                //孩子小于parent 交换
                int tmp = this.elme[child];
                this.elme[child] = this.elme[parent];
                this.elme[parent] = tmp;
                parent = child;   //继续向下调整
                child = 2*parent+1;
            } else {
                break;
            }
        }
    }
}

2.4 堆的插入与删除

2.4.1 堆的插入(小根堆)

堆的插入的步骤:

  1. 先将需要插入的元素放到最后一个位置,如果空间不够则需要扩容。
  2. 然后将新插入的元素向上调整,直到满足堆的性质。
//插入元素  时间复杂度为: O(N*logN)
public void offer(int val) {
    //判断数组是否为满
    if (isFull()) {
        this.elme = Arrays.copyOf(this.elme,2*this.elme.length); //二倍扩容
    }
    this.elme[usedSize++] = val;
    shiftUp(usedSize-1);
}
private void shiftUp(int child) { 
    int parent = (child-1)/2;  // 找到父亲节点
    while(parent >= 0) {
        if (this.elme[child] > this.elme[parent]) { //只需要与根节点比较即可
        	// 比较
            int tmp = this.elme[child];
            this.elme[child] = this.elme[parent];
            this.elme[parent] = tmp;
            
            child = parent;
            parent = (child-1)/2;
        }else {
            break;
        }
    }
}

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

2.4.2 堆的删除(小根堆)

堆删除元素的步骤:

  1. 将根节点与最后一个节点交换
  2. 将堆中有效数据-1
  3. 最后调整堆 直到满足为小根堆
//删除元素
public void pop() {
    if (isEmpty()) {//数组为空
        return;
    }

    int tmp = this.elme[0];
    this.elme[0] = this.elme[usedSize-1];
    this.elme[usedSize-1] = tmp;

    usedSize--;
    shiftUpSmall(0,usedSize);

}
public boolean isEmpty() {
    return usedSize == 0;
}

3. PriorityQueue

3.1 特性

java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,本文主要介绍PriorityQueue.
注意:

  1. PriorityQueue中存放的元素必须是能够比较大小的,不能插入无法比较大小的元素,否则会抛出类型转换异常(ClassCastException).
  2. 可以插入多个元素,其内部可以自动扩容,最大容量为整形的最大值
  3. 插入和删除元素的时间复杂度为O(logN)
  4. PriorityQueue的底层使用了堆这种数据结构
  5. PriorityQueue默认为小根堆
    在这里插入图片描述

3.2 构造方法

方法解释
PriorityQueue()创建一个空的优先级队列,默认容量为11
PriorityQueue(int initialCapacity)创建一个容量为initialCapacity的优先级队列,且initialCapacity不能小于1,否则会抛出异常
PriorityQueue(Collection<? extends E> c)使用集合来创建优先级队列

3.3 常用方法

//插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度 ,注意:空间不够时候会进行扩容
boolean offer(E e)
//获取优先级最高的元素,如果优先级队列为空,返回null
E peek() 
//移除优先级最高的元素并返回,如果优先级队列为空,返回null
E poll() 
// 获取有效元素的个数
int size()
//清空
void clear()
//检测优先级队列是否为空,空返回true
boolean isEmpty()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值