数据结构(堆)

news2025/1/21 15:43:58

文章目录

  • 一、概念
  • 二、堆的使用
  • 三、PriorityQueue 介绍
    • 3.1 PriorityQueue 的特性
    • 3.2 PriorityQueue 的方法
    • 3.3 集合框架中PriorityQueue的比较方式
  • 四、堆的应用

一、概念

1.什么是优先级队列

     队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,比如我们在处理事情的时候,会优先性处理最重要的事,在该种场景下,使用队列显然不合适,由此引出了优先级队列的概念

2.什么是堆

JDK1.8中的PriorityQueue底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整(堆可以模拟实现优先级队列)
对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低

在这里插入图片描述

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

二、堆的使用

1.结构

public class TestHeap {

    public int[] elem;
    public int usedSize;

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

2.堆的创建

堆创建的时间复杂度为O(n) ----------------->数学计算

public static void createHeap(int[] array) {
// 找倒数第一个非叶子节点,从该节点位置开始往前一直到根节点,遇到一个节点,应用向下调整
    int root = ((array.length-2)>>1);
    for (; root >= 0; root--) {
        shiftDown(array, root);
    }
}
 //创建一个大根堆  时间复杂度O(N)
 public void createHeap(int[] array) {
     for (int i = 0; i < array.length; i++) {
         elem[i] = array[i];
         usedSize++;
     }
     //把原始数据 给到了 elem数组
     for (int parent = (usedSize-1-1)/2; parent >= 0 ; parent--) {
         shiftDown(parent,usedSize);
     }
 }

 /**
  *
  * @param parent 每棵子树的根节点
  * @param len 代表每棵子树的结束位置
  */
 private 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 + 1;
         }
         if(elem[child] > elem[parent]) {
             int tmp = elem[child];
             elem[child] = elem[parent];
             elem[parent] = tmp;
             parent = child;
             child = 2 * parent+1;
         }else {
             //此时本身 就是一个大根堆
             break;
         }
     }
 }

3.堆的插入

  1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2. 将最后新插入的节点向上调整,直到满足堆的性质
public void push(int val) {
    //1. 检查满
    if(isFull()) {
        elem = Arrays.copyOf(elem,2*elem.length);
    }
    //2、存数据
    elem[usedSize] = val;
    usedSize++;
    shiftUp(usedSize-1);
}

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

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

4.堆的删除

  1. 将堆顶元素对堆中最后一个元素交换
  2. 将堆中有效数据个数减少一个
  3. 对堆顶元素进行向下调整
public void poll() {
    if(empty()) {
        throw new HeapEmptyException("优先级队列是空的!");
    }
    int tmp = elem[0];
    elem[0] = elem[usedSize-1];
    elem[usedSize-1] = tmp;
    usedSize--;//9
    shiftDown(0,usedSize);
}

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

peek()方法

public int peek() {
    if(empty()) {
        throw new HeapEmptyException("优先级队列是空的!");
    }
    return elem[0];
}

三、PriorityQueue 介绍

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

3.1 PriorityQueue 的特性

1.注意事项

  1. 使用时必须导入PriorityQueue所在的包,即:

    import java.util.PriorityQueue;

  2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
    ClassCastException异常

初始化如果传入的是对象,参数要求,这个类是实现Comparable接口的

因为offer()方法中,会最终调用一个siftUpComparable() 方法,这里会有一个强转为(Comparable)的操作,如果这个自定义类没有实现Comparable接口,就无法强转,会报错

  1. 不能插入null对象,否则会抛出NullPointerException
  2. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
  3. 插入和删除元素的时间复杂度为
  4. PriorityQueue底层使用了堆数据结构
  5. PriorityQueue默认情况下是小堆—即每次获取到的元素都是最小的元素

3.2 PriorityQueue 的方法

1.构造方法

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

2.PriorityQueue 的扩容

在集合中,所有的扩容都要去看grow()方法

在这里插入图片描述

3.其他

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

3.3 集合框架中PriorityQueue的比较方式

集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了:Comparble和Comparator两种方式。

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

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

在这里插入图片描述

四、堆的应用

1.PriorityQueue的实现
用堆作为底层结构封装优先级队列

2.堆排序

  1. 建堆
    升序:建大堆
    降序:建小堆
  2. 利用堆删除思想来进行排序
    建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
    把0下标最后一个下标的数值交换,然后进行向上调整,然后再把0下标和倒数第二个下标的数值交换
 public static void heapSort(){
     int end = usedSize - 1;
     while (end > 0){
         int tmp = elem[0];
         elem[0] = elem[end];
         elem[end] = tmp;
         shiftDown(0, end);
         end--;
     }
 }

时间复杂度计算

  1. 创建堆 O(n)       O(n) 是可以省略的
  2. 堆排序N * logN

3.Top-k问题            最小k个数

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

第一种方法

  1. 排序之后取5个数字,就是最小的

第二种方法

  1. 建立一个小根堆
  2. 弹出5次数据,就能拿出最小的五个数据

缺陷:时间复杂度过高

public static int[] smallestK1(int[] array,int k) {
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    for(int x : array) {
        minHeap.offer(x);
    }
    //小根堆当中 已经把数组所有的元素 存储起来了  k*logn
    int[] ret = new int[k];
    for (int i = 0; i < k; i++) {
        ret[i] = minHeap.poll();
    }
    return ret;
}

第三种方法

  1. 用数据集合中前K个元素来建堆
    前k个最大的元素,则建小堆
    前k个最小的元素,则建大堆
  2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素
    将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素
  1. 堆的大小是K
  2. 遍历N个元素
  3. 极端情况,从第K+1个元素开始,每个元素都要进行调整N*logK次
class Imp implements Comparator<Integer> {

    @Override
    public int compare(Integer o1, Integer o2) {
        return o2-o1;
    }
}

 public static int[] smallestK(int[] array,int k) {

     PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k,new Imp());

     for (int i = 0; i < k; i++) {
         maxHeap.offer(array[i]);
     }

     for (int i = k; i < array.length; i++) {
         //1、获取堆顶元素的值
         int top = maxHeap.peek();
         if(top > array[i]) {
             maxHeap.poll();
             maxHeap.offer(array[i]);
         }
     }

     int[] ret = new int[k];

     for (int i = 0; i < k; i++) {
         ret[i] = maxHeap.poll();
     }
     return ret;
 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527333.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

登录的两种方式

Cookie 起源&#xff1a;「购物车」功能需求 工作机制 1.服务器需要客户端保存的内容&#xff0c;放在set-cookie headers里返回&#xff0c;客户端会自动保存 2.客户端保存的cookies&#xff0c;会在之后的所有请求里都携带进cookie header里发送给服务器 3.客户端保存coo…

服务(第二十一篇)mysql高级查询语句(二)

①视图表&#xff1a; 视图表是虚拟表&#xff0c;用来存储SQL语句的定义 如果视图表和原表的字段相同&#xff0c;是可以进行数据修改的&#xff1b; 如果两者的字段不通&#xff0c;不可以修改数据。 语法&#xff1a; 创建&#xff1a;create view 试图表名 as ... 查…

一分钟图情论文:《大学生数字囤积行为的探索性研究——基于个人信息管理视角》

一分钟图情论文&#xff1a;《大学生数字囤积行为的探索性研究——基于个人信息管理视角》 “仓鼠症”是指一些仓鼠为了过冬而囤积大量食物&#xff0c;但由于储藏过多、遗忘储藏地点或者无力储藏&#xff0c;最终使劳动成果白白浪费。在数字时代&#xff0c;我们很多人也成为…

LSTM-理解 Part-1(RNN:循环神经网络)

在之前博主写过涉及到LSTM的博客见下&#xff1a; 机器学习 Pytorch实现案例 LSTM案例&#xff08;航班人数预测&#xff09; 该项目原始的博客版本是&#xff1a; Time Series Prediction using LSTM with PyTorch in Python 循环神经网络RNN&#xff1a;Recurrent Neural Ne…

B树的插入操作

我的错误插入操作的详细解析 前言一、实现思路二、思路梳理1.我需要解决的问题2.具体函数实现 总结 前言 本文主要记载了我在实现递归插入操作的思路历程&#xff0c;以及遇到的问题和梳理操作的过程。我之前的实现方法有一种很大的问题&#xff0c;因为不是尾递归实现&#x…

智能高效的Go IDE——GoLand v2023.1全新发布,引入gRPC 导航

GoLand 使 Go 代码的阅读、编写和更改变得非常容易。即时错误检测和修复建议&#xff0c;通过一步撤消快速安全重构&#xff0c;智能代码完成&#xff0c;死代码检测和文档提示帮助所有 Go 开发人员&#xff0c;从新手到经验丰富的专业人士&#xff0c;创建快速、高效、和可靠的…

多语言APP的外包开发流程及注意事项

近些年国内越来越多的公司走向海外&#xff0c;有些互联网项目即可以为国内用户使用&#xff0c;也可以为国外用户使用&#xff0c;尤其是一些智力类小游戏&#xff0c;这些小游戏不需要特别的运营&#xff0c;只要在设计和玩法上把握好&#xff0c;那就可以推广到全球用户。今…

MySQL 中 CONCAT 函数使用

1&#xff1a;创建数据表&#xff1a; CREATE TABLE user ( id int NOT NULL AUTO_INCREMENT, code varchar(255) NOT NULL, name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT3 DE…

KubeSphere 社区双周报 | 开源之夏已启动 | 2023.04.28-05.11

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.04.28-2023.…

数据结构学习分享之堆的详解以及TopK问题

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:数据结构学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你了解更多数据结构的知识   &#x1f51d;&#x1f51d; 数据结构第七课 1. 前言&a…

未来已来,时代颠覆者ChatGPT你真的了解吗?

文章目录 什么是ChatGPTchatgpt与自然语言处理从gpt1.0到chatgpt&#xff0c;经历了什么chatgpt是一个语言模型chatgpt是如何处理文字输入的写在最后 什么是ChatGPT ChatGPT是美国OpenAI研发的聊天机器人程序&#xff0c;2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语…

网络基础知识(4)——建立与关闭连接

建立 TCP 连接&#xff1a;三次握手 前面我们提到过&#xff0c;TCP 协议是一个面向连接的协议&#xff0c;双方在进行网络通信之间&#xff0c;都必须先在双方之间建立一条连接&#xff0c;俗称“握手”&#xff0c;可能在学习网络编程之前&#xff0c;大家或多或少都听过“…

SpringSecurity安全权限框架及其原理

1. 基础使用 首先创建最基本的SpringBoot项目&#xff0c;默认都会。主要是引入依赖和创建Controller进行测试。 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://w…

十五天MySQL学习计划(运维篇-完结)读写分离-第十五天

十五天MySQL学习计划&#xff08;运维篇-完结&#xff09;读写分离-第十五天 读写分离 1.读写分离 ​ 读写分离&#xff0c;简单的说是把对数据库的读和写操作分开&#xff0c;以对应不同的数据库服务器。主服务器提供写操作&#xff0c;从数据库提供读操作&#xff0c;这样…

linux0.12-8-10-sys.c

[369页] 1、 这个文件需要配合其他文件一起看才能明白函数的作用&#xff1b; 2、 进程ID和进程组ID是描述进程之间的关系&#xff0c;与用户ID和组ID等其他无关系&#xff1b; 3、 用户ID和组ID和文件&#xff08;程序&#xff09;属性有关&#xff0c;当进程执行&#xff08;…

首发!车联网前装搭载率破70%,本土供应商抢下半壁江山

对于汽车智能化来说&#xff0c;网联化是相辅相成的角色&#xff0c;从传统3G、4G到5G的进化&#xff0c;提升座舱信息娱乐的体验&#xff1b;到C-V2X落地为辅助驾驶及自动驾驶提供冗余感知。 同时&#xff0c;车联网的普及&#xff0c;也进一步驱动互联网生态内容、服务以及类…

【AUTOSAR】【以太网】SoAd

目录 一、概述 二、限制与约束 三、依赖模块 5.1 TCPIP模块 5.2 通用上层 四、功能描述 4.1 套接字连接 4.2 PDU传输 4.3 PDU Header option 4.4 PDU 接收 4.5 最佳匹配算法 4.6 消息接受策略 4.7 TP PDU取消 4.8 路由组 4.9 PDU fan-out 五、API接口 5.1 API…

SpringBoot实现登录拦截的实现

对于管理系统或其他需要用户登录的系统&#xff0c;登录验证都是必不可少的环节&#xff0c;在SpringBoot开发的项目中&#xff0c;通过实现拦截器来实现用户登录拦截并验证。 1、SpringBoot实现登录拦截的原理 SpringBoot通过实现HandlerInterceptor接口实现拦截器&#xff…

如何完成GNSS接收器的定时校准

背景 GNSS以其提供亚米级精度定位的能力而闻名。然而鲜为人知的是&#xff0c;GNSS还提供了一种非常便捷的方法&#xff0c;可以通过GNSS接收器获得纳秒&#xff08;甚至亚纳秒&#xff09;的定时精度。事实上&#xff0c;除了三个空间维度之外&#xff0c;GNSS还使用户能够计…

iPhone照片导入电脑的图文教程,批量上传的3个方法!

案例&#xff1a;苹果手机照片怎么批量上传到电脑&#xff1f; 【友友们&#xff0c;手机照片太多&#xff0c;占用了我很多内存。想要把照片上传批量上传到电脑上进行保存&#xff0c;该怎么做&#xff1f;】 随着iPhone的普及和摄影功能的提升&#xff0c;越来越多的用户希望…