数据结构之堆的应用
创始人
2024-03-31 09:12:39
0

系列文章目录

数据结构之堆_crazy_xieyi的博客-CSDN博客


文章目录

  • 前言
  • 一、Top-k问题
  •         1.前K个最小数(第k个最小数)
  •         2.前K个最大数(第K个最大数)
  • 二、堆排序
    • 1.从小到大排序(建大根堆)
    • 2.从大到小排序(建小跟堆)

前言

JDK1.8中的PriorityQueue底层使用了堆的数据结构,用堆作为底层结构封装了优先级队列。 建堆(向下调整)的时间复杂度O(N):

向上调整建堆的时间复杂度为O(nlogn).

一、Top-k问题

示例:在给定的一个数组中求前K个最小的数

第一种思路:把给定的数组直接进行排序,然后前K个一定是最小的数;

 public int[] getLeastNumbers(int[] arr, int k) {Arrays.sort(arr);int[] str = new int[k];for (int i = 0; i < k; i++) {str[i] = arr[i];}return str;}

显然这种方式是不可取的,如果数据量非常大,排序就不太可取了(可能数据都

不能一下子全部加载到内存中)。最佳的方式就是用堆来解决。 第二种思路:把整个数组整体建小根堆,然后依次弹出K个堆顶的数据。
public static int[] smallestK(int[] arr, int k) {//1. 建立一个小根堆PriorityQueue minHeap = new PriorityQueue<>();//2、取出数组当中的每个元素,存放到小跟堆当中for (int i = 0; i < arr.length; i++) {minHeap.offer(arr[i]);}//3.弹出K个元素,存放到数组当中,返回即可int[] tmp = new int[k];for (int i = 0; i < k; i++) {tmp[i] = minHeap.poll();}return tmp;}

但是你会发现,这种方式虽然可以,但是时间复杂度比较高,还是不可取得。整体建堆的时间复杂度为o(n),然后弹出K次时间复杂度为Klogn,则总体时间复杂度为 O(N + Klogn);

第三种思路:

1. 用数据集合中前K个元素来建堆:前k个最大的元素,则建小堆;前k个最小的元素,则建大堆。 2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素 将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。 下面还是用上面求前K个最小的数为例:
        public int[] getLeastNumbers(int[] arr, int k) {PriorityQueue minHeap = new PriorityQueue<>(new Comparator() {@Overridepublic int compare(Integer o1, Integer o2) {return o2.compareTo(o1);}});if (arr == null || k == 0)return new int[0];//用K个元素,先建立一个大根堆for (int i = 0; i < k; i++) {minHeap.offer(arr[i]);}//剩余元素与堆元素进行比较for (int i = k; i < arr.length; i++) {if (arr[i] < minHeap.peek()){minHeap.poll();minHeap.offer(arr[i]);}}//返回前K个元素int[] str = new int[k];for (int i = 0; i < k; i++) {str[i] = minHeap.poll();}return str;}

此时时间复杂度为:k + (n-k)logk ,约等于nlogk。

那么现在有一个小问题,就是第K个最小的怎么求?

其实这一点非常简单,求第K个最小的,只需要弹出一次就好了,因为此时是大跟堆,那么第K个最小的肯定就是堆顶的元素。

二、堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:  1. 建堆 升序:建大堆 降序:建小堆 2. 利用堆删除思想来进行排序 建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
    /*** 时间复杂度:*  O(n) + O(n*logn) 约等于 O(nlogn)*  空间复杂度:O(1)*/public void heapSort() {//1.建立大根堆 O(n)createHeap();//2.然后排序int end = usedSize-1;while (end > 0) {int tmp = elem[0];elem[0] = elem[end];elem[end] = tmp;shiftDown(0,end);end--;}}private void shiftDown(int root,int len) {int child = root*2 + 1;while (elem[child] > elem[root]){if (child+1 < len && elem[child] < elem[child+1]){child++;}if (elem[child] > elem[root]){int temp = elem[child];elem[child] = elem[root];elem[root] = temp;child = root;root = (child-1)/2;}else {break;}}}

时间复杂度: O(n) + O(n*logn) 约等于 O(nlogn)
空间复杂度:O(1)

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...