当前位置: 首页 > article >正文

堆-数组的堆化+优先队列(PriorityQueue)的使用

一、堆

1、什么是堆?

以完全二叉树的形式将元素存储到对应的数组位置上所形成的新数组

2、为什么要将数组变成堆?

当数组中的元素连续多次进行排序时会消耗大量的时间,将数组变成堆后通过堆排序的方式将会消耗更少的时间

二、接口

给堆定义一个接口,用来规范堆里面的方法

1、在获取堆顶元素和删除堆顶元素的方法中,都必须返回堆顶元素,当堆为空时,返回异常对象要比返回null关键字更加安全

定义堆异常类

package com.ffyc.heap;

/**
 * 自定义堆异常 继承RuntimException而不继承Exception的原因是RuntimException在遇到异常时JVM会自动捕捉异常异常,而Exception必须使用try catch或者throws手动处理异常
 */
public class HeapException extends RuntimeException{
    public HeapException(String message) {
        super(message);
    }
}

三、数组的堆化

这里的时间复杂度是将堆作为满二叉树计算出来的

1、方法一:逐个添加元素创建堆

(1)的高度为h,进行上浮和下沉操作最大时间与高度h有关,时间复杂度为O(h)

(2)是一棵完全二叉树,完全二叉树的时间复杂度与结点有关O(log_{2}^{n}),此处n为二叉树的结点数目

(3)对堆中一个数据进行上浮和下沉操作的时间复杂度均为O(h)=O(log_{2}^{n})

(4)通过逐个添加元素创建堆的方式来创建堆的时间复杂度为O(nlog_{2}^{n})

2、方法二:将外界数组调整成堆(堆化)

使用逐个添加元素的方式创建堆可能会出现索引越界的问题,为了解决索引越界的问题,我们可以采用动态数组扩容的方式,但是由于不知道到底数组大小要扩到什么程度,因此会损失一部分时间和空间,降低了程序运行效率。如果我们直接将外界传进来的数组调整成堆,即对数组进行堆化,这将会避免由于数组容量不足所带来的索引越界问题

1、使用Integer.MAX_VALUE创建数组

/**
         * 运行程序会报异常java.lang.OutOfMemoryError,表明在JVM中创建的数组大小超出了JVM配置的最大限制,
         * 即JVM的堆空间(Heap space)不足以容纳下这个数组
         */
        int[]a=new int[Integer.MAX_VALUE];

2、heapify(堆化)的平均时间复杂度=每层结点数*移动数=O(2^{h}-h-1)=O(2^{h})=O(n)

四、优先队列-PriorityQueue

1、PriorityQueue底层默认使用最小堆实现

public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

2、PriorityQueue底层提供的将最小堆实现优先队列转为最大堆实现优先队列的方法

public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }

3、PriorityQueue底层提供的将外界传入的集合直接进行堆化的方法

 public PriorityQueue(Collection<? extends E> c) {
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            initElementsFromCollection(ss);
        }
        else if (c instanceof PriorityQueue<?>) {
            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            initFromPriorityQueue(pq);
        }
        else {
            this.comparator = null;
            initFromCollection(c);
        }
    }

 4、PriorityQueue底层提供的将外界传入的集合进行堆化的方法

public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

5、集合堆化的三种形式

(1)创建最小堆,调用addAll方法堆化集合

public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(9);
        list.add(2);
        list.add(5);
        list.add(8);
        list.add(3);
        // 创建最小堆,调用addAll方法堆化集合
        PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();
        // 将list集合进行堆化
        priorityQueue.addAll(list);
        // 获取堆顶元素
        System.out.println(priorityQueue.peek());
        // 删除堆顶元素
        priorityQueue.poll();
        System.out.println(priorityQueue.peek());
    }

(2) 创建最小堆,直接堆化集合

public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(9);
        list.add(2);
        list.add(5);
        list.add(8);
        list.add(3);
        // 创建最小堆,直接堆化集合
        PriorityQueue<Integer>priorityQueue=new PriorityQueue<>(list);
        // 获取堆顶元素
        System.out.println(priorityQueue.peek());
        // 删除堆顶元素
        priorityQueue.poll();
        System.out.println(priorityQueue.peek());
    }

(3)创建最大堆,调用addAll方法堆化集合

 public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(9);
        list.add(2);
        list.add(5);
        list.add(8);
        list.add(3);
        // 创建底层由最大堆实现的优先队列(使用匿名内部类作为参数,可用idea工具将其转换为lambda)
        PriorityQueue<Integer>priorityQueue=new PriorityQueue<>(Comparator.reverseOrder());
        // 将list集合进行堆化
        priorityQueue.addAll(list);
        // 获取堆顶元素
        System.out.println(priorityQueue.peek());
        // 删除堆顶元素
        priorityQueue.poll();
        System.out.println(priorityQueue.peek());
    }
 


http://www.kler.cn/news/294473.html

相关文章:

  • python的logging模块setLevel(LEVELS.get(‘default‘,logging.NOTSET))
  • 如何把自动获取的ip地址固定
  • 每日一题~cf 970 div3 (A思维,B小模拟,C二分,D排列数建图成环,E 26个字母暴力+前缀和,F 逆元,G 数论gcd )
  • 13款常用AI编程工具
  • 稳定的亚马逊自养号测评系统需具备哪些条件
  • Redis:Redis性能变慢的原因
  • JavaScript 知识点总结
  • Linux下安装使用Git及常用操作命令详解
  • AIOT人工智能物联网六大场景
  • Linux下基于TCP协议的简易服务器实现(C语言)
  • OpenCV中的颜色映射函数applyColorMap的使用
  • LCP 485. 最大连续 1 的个数[lleetcode -11]
  • 通信工程学习:什么是PCM脉冲编码调制、DPCM差分脉冲编码调制、ADPCM自适应差分脉冲编码调制
  • Flask中实现上下文管理
  • ARM基础---编程模型---ARM汇编
  • 把设计模式用起来!(1)——楔
  • 算法复杂度 —— 数据结构前言、算法效率、时间复杂度、空间复杂度、常见复杂度对比、复杂度算法题(旋转数组)
  • 掌握Hive函数[2]:从基础到高级应用
  • 对比测评3款BI分析工具
  • es数组包含查询
  • 『功能项目』战士的A键连击【33】
  • Java项目: 基于SpringBoot+mybatis+maven+mysql图书馆管理系统(含源码+数据库+任务书+答辩PPT+毕业论文)
  • 2024 批量下载公众号渤海小吏1千篇文章导出pdf(带留言),抓取文章标题时间链接封面阅读数分享数留言数粉丝数导出excel
  • Python测试开发---什么是单例模式
  • tomato靶场攻略
  • 基于单片机的多功能数字闹钟设计
  • 【简单】 猿人学web第一届 第15题 备周则意怠,常见则不疑
  • javaWeb【day03】---(Vue-Element)
  • python | 字符串字母大小写转换方法
  • HalconDotNet中的图像特征与提取详解