Java 超详细讲解数据结构中的堆的应用


Posted in Java/Android onApril 02, 2022

一、堆的创建

1、向下调整(以小堆为例)  

让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)

如果parent的左孩子存在,即:child < size, 进行以下操作,直到parent的左孩子不存在:

  • parent右孩子是否存在,存在找到左右孩子中最小的孩子,让child进行标记
  • 将parent与较小的孩子child比较,如果:

parent小于较小的孩子child,调整结束否则:交换parent与较小的孩子child,交换完成之后,parent中大的元素向下移动,可能导致子树不满足堆的性质,因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续2。

public void shiftDown(int[] elem,int parent,int len){
        int cur=parent*2+1;
        while(cur<len){
           if(cur+1<len){
               if(elem[cur+1]<elem[cur]){
                   cur++;
               }
           }
            if(this.elem[cur]<this.elem[parent]) {
                swap(cur, parent);
            }
            parent=cur;
            cur=parent*2+1;
        }
    }

2、创建堆

对于普通序列,我们需要从它的第一个有左节点的父节点开始调整,知道整棵树满足堆的性质。

Java 超详细讲解数据结构中的堆的应用

3、创建堆的时间复杂度

堆必须是完全二叉树,满二叉树也是完全二叉树。由下面的计算,创建堆的时间复杂度为O(n).

Java 超详细讲解数据结构中的堆的应用

 二、堆的插入和删除

1、堆的插入

  • 将要插入的元素放在堆的最后,如果放不了,进行扩容
  • 将新插入的节点向上调整,直到满足堆的性质

Java 超详细讲解数据结构中的堆的应用

 【向上调整】

public void shiftUp(int elem[],int child){
        int parent=(child-1)/2;
        while(parent>=0){
            if(elem[child]>elem[parent]){
                swap(child,parent);
                child=parent;
                parent=(child-1)/2;
            }else{
                break;
            }
        }
    }

2、堆的删除

根据堆的性质,对删除的一定是堆顶元素。步骤如下:

  • 将堆顶元素和最后一个元素交换
  • 堆的元素个数减一
  • 对堆顶元素进行向下调整

Java 超详细讲解数据结构中的堆的应用

 三、堆的应用

1、堆排序

升序:创建大根堆

降序:创建小根堆

交换堆顶元素和堆得最后一个元素,进行向下调整,直到堆有序。

Java 超详细讲解数据结构中的堆的应用

2、top-k问题 【求最小的K个数

top-k问题:求数据集合中前k个大或者小的元素,一般数据量都比较大。

Java 超详细讲解数据结构中的堆的应用

class Solution {
    public int[] smallestK(int[] arr, int k) {
        int[] array=new int[k];
        if(arr==null||arr.length<=k||k==0){
            return array;
        }
        PriorityQueue<Integer> queue=new PriorityQueue<>((a,b)->b-a);
        int i=0;
        for(;i<k;++i){
            queue.offer(arr[i]);
        }
        while(i<arr.length){
            if(arr[i]<queue.peek()){
                queue.poll();
                queue.offer(arr[i]);
            }
            i++;
        }
        int size=queue.size();
        for(int j=0;j<size;++j){
            array[j]=queue.poll();
        }
        return array;
    }
}

四、常用接口的介绍

1、PriorityQueue的特性

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

【PriorityQueue】使用的注意事项:

  • 必须导入PeioriryQueue的包;
  • 放置的元素必须是能够比较大小的,否则会抛出ClassCastException异常;
  • 不能放置null元素,否则会抛出NullPointerException;
  • 可以插入任意多的元素,内部会自动扩容;
  • 底层使用了堆数据结构,默认是小堆。如果要构建大堆,则需要提供比较器。

PriorityQueue的扩容方式:

  • 如果容量小于64时,是按照oldCapacity的2倍方式扩容的
  • 如果容量大于等于64,是按照oldCapacity的1.5倍方式扩容的
  • 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

int newCapacity = oldCapacity + ((oldCapacity < 64) ?

                      (oldCapacity + 2) : 

                   (oldCapacity >> 1));

PriorityQueue采用了:Comparble和Comparator两种方式。

1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法

2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法

// 用户自己定义的比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
class IntCmp implements Comparator<Integer>{
   @Override
   public int compare(Integer o1, Integer o2) {
      return o2-o1;
   }
}
PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp());

2、优先级队列的构造

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

到此这篇关于Java 超详细讲解数据结构中的堆的应用的文章就介绍到这了,更多相关Java 堆的应用内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
总结一下关于在Java8中使用stream流踩过的一些坑
Jun 24 Java/Android
浅谈Python魔法方法
Jun 28 Java/Android
浅谈resultMap的用法及关联结果集映射
Jun 30 Java/Android
java设计模式--三种工厂模式详解
Jul 21 Java/Android
java中用float时,数字后面加f,这样是为什么你知道吗
Sep 04 Java/Android
springboot 多数据源配置不生效遇到的坑及解决
Nov 17 Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
Apr 13 Java/Android
Android开发手册Chip监听及ChipGroup监听
Jun 10 Java/Android
Java 多线程并发FutureTask
Jun 28 Java/Android
利用Java连接Hadoop进行编程
Jun 28 Java/Android
Java实现超大Excel文件解析(XSSF,SXSSF,easyExcel)
Jul 15 Java/Android
Spring boot实现上传文件到本地服务器
Aug 14 Java/Android
Java 数据结构七大排序使用分析
Java基础——Map集合
Apr 01 #Java/Android
Android基于Fresco实现圆角和圆形图片
Apr 01 #Java/Android
Android自定义scrollview实现回弹效果
Apr 01 #Java/Android
Android自定义ScrollView实现阻尼回弹
Java实战之课程信息管理系统的实现
Android超详细讲解组件ScrollView的使用
You might like
在WordPress的文章编辑器中设置默认内容的方法
2015/12/29 PHP
Zend Framework教程之请求对象的封装Zend_Controller_Request实例详解
2016/03/07 PHP
php中pcntl_fork创建子进程的方法实例
2019/03/14 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
2019/12/20 PHP
jQuery图片滚动图片的效果(另类实现)
2013/06/02 Javascript
jQuery prev ~ siblings选择器使用介绍
2013/08/09 Javascript
jQuery的缓存机制浅析
2014/06/07 Javascript
给应用部分的js代码设定一个统一的入口
2014/06/15 Javascript
Jquery 实现checkbox全选方法
2015/01/28 Javascript
JS加载iFrame出现空白问题的解决办法
2016/05/13 Javascript
12个非常实用的JavaScript小技巧【推荐】
2016/05/18 Javascript
jQuery实现点击任意位置弹出层外关闭弹出层效果
2016/10/19 Javascript
js遍历获取表格内数据的方法(必看)
2017/04/06 Javascript
基于JavaScript实现微信抢红包功能
2017/07/20 Javascript
在vue项目中使用element-ui的Upload上传组件的示例
2018/02/08 Javascript
Vue-resource安装过程及使用方法解析
2020/07/21 Javascript
VUE UPLOAD 通过ACTION返回上传结果操作
2020/09/07 Javascript
python topN 取最大的N个数或最小的N个数方法
2018/06/04 Python
Python判断两个文件是否相同与两个文本进行相同项筛选的方法
2019/03/01 Python
python jenkins 打包构建代码的示例代码
2019/11/29 Python
在python里创建一个任务(Task)实例
2020/04/25 Python
python 使用事件对象asyncio.Event来同步协程的操作
2020/05/04 Python
利用Python的folium包绘制城市道路图的实现示例
2020/08/24 Python
python工具快速为音视频自动生成字幕(使用说明)
2021/01/27 Python
CSS3 选择器 伪类选择器介绍
2012/01/21 HTML / CSS
CSS3的颜色渐变效果的示例代码
2017/09/29 HTML / CSS
HTML5 canvas画矩形时出现边框样式不一致的解决方法
2013/10/14 HTML / CSS
AC Lens:购买隐形眼镜
2017/02/26 全球购物
iHerb中文官网:维生素、保健品和健康产品
2018/11/01 全球购物
Kate Spade澳大利亚官方网站:美国设计师手袋品牌
2019/09/10 全球购物
正宗的澳大利亚Ugg靴子零售商:UGG Express
2020/04/19 全球购物
如何让Java程序执行效率更高
2014/06/25 面试题
临床医师个人自我评价
2014/04/06 职场文书
民生工作实施方案
2014/05/31 职场文书
医院安全生产月活动总结
2014/07/05 职场文书
vue判断按钮是否可以点击
2022/04/09 Vue.js