堆结构和堆排序

堆(优先队列)

时间复杂度:

初始化建堆的时间复杂度为 O(n)

堆排序重建堆 O(nlogn)

PriorityQueue小顶堆

小顶堆:任意一个非叶子节点的权值,都不大于其左右子节点的权值

构造函数

构造器 功能介绍
PriorityQueue() 创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity) 创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛 IllegalArgumentException异常
PriorityQueue(Collection c) 用一个集合来创建优先级队列

image-20211010104338141

也可以在初始化的时候指定comparator接口的实现,

常用api

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

特性:

  1. PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的

  2. PriorityQueue中存储的对象必须要能够比较大小,如果不能比较大小就会抛出ClassCaseException异常.

  3. 不能插入null对象,否则抛出NullPointerException

  4. 带有自动扩容机制

  5. 插入和杀出的时间复杂度为
    O ( l o g 2 N ) O(log_2N) O(log2N)

  6. 底层使用了堆

扩容的过程 jdk1.8

    private void grow(int minCapacity) {
   
        int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));
        // overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }

从扩容方法上可以看出

  • 如果容量小于64使用oldCapacity+oldCapacity+2的方式
  • 如果容量大于64使用oldCapacity+(oldCapacity>>1)的方式(相当于1.5倍扩容)

底层数据结构

堆的概念

将一个关键码的集合k={k,k1,k2,k3…kn-1}把它的所有元素按照完全二叉树的顺序方式存储在数组中

在一个一维数组中

  • 满足ki<=k2i+1 且 ki<=k2i+2的称为小堆
  • 满足ki>=k2i+1 且 ki>=k2i+2的称为大堆

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

性质:

  • 堆中某个节点的值总是不大于或者不小于父节点的值
  • 堆总是一个完全二叉树

image-20211010111536354

  • 如果i为0,则i表示的节点为根节点,否则i节点的双亲为(i-1)/2
  • 如果2*i+1小于节点个数,则节点i的左孩子下标为2*i+1,否则没有左孩子
  • 如果2*i+2小于节点个数,则节点i的右孩子下标为2*i+2,否则没有右孩子

向上调整

向上调整的过程(最小堆)

  1. 先设定倒数第一个叶子节点为当前节点,标记为cur,找出他的父节点,用parent来标记
  2. 比较paren和cur的值,如果cur比parent小.则不满足小顶堆的规则,需要进行交换. 如果cur比parent大就不交换,此时调整结束.
  3. 如果不满足条件交换后, cur就重设为父节点下标,重新开始循环.然后检测是否满足最小堆的性质,一直到满足条件或者cur小于等于0结束.

向下调整

  1. 首先设定根节点为当前节点标记为cur,比较左右子树的值,找出更小的值,用child来标记.
  2. 比较child和cur的值,如果child比cur小,则不满足小堆的规则,需要进行交换.如果cur比parent大就不交换.此时调整结束
  3. 如果不满足条件交换后, cur就重设为子节点下标,重新开始循环.然后检测是否满足最小堆的性质,一直到满足条件或者cur小于等于0结束.

堆的创建(向上调整)

当有了个一个数组,但是不满足堆的结构要求,我们要从倒数第一个非叶子节点的子树开始调整,一直到根节点的树.

ArrayList<Integer> integers = new ArrayList<>();
        integers.add(95);
        integers.add(9);
        integers.add(14);
        integers.add(48);
        integers.add(29);
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值