堆与堆排序与topK问题
来源:互联网 发布:淘宝店主贷款 编辑:程序博客网 时间:2024/06/04 19:25
电面的时候问了经典的topK问题,没准备到被问了个措不及防,现在把相关知识点记录下来。
假设我们有一些数据,需要按照某种关键字求出这些数据中最小(大)的K个数,即求出这些数据的topK。
当数据量较小的时候,一个简单的想法是直接对数据进行排序,然后取最前面的K个数据;但是当数据量较大,数据无法一次性放入内存的时候应该怎么办呢?
这时候就需要借助堆这种数据结构。堆通常是一个可以被看做一棵树的数组对象,其总是满足下列性质:
(a)堆中某个节点的值总是不大于或不小于其父节点的值
(b)堆总是一棵完全二叉树
节点值不大于其父节点的堆称为大根堆,反之称为小根堆。
堆排序与topK问题无关,以下内容纯属展开:
以堆为基础的排序方法称为堆排序。堆排序主要可以分为以下几个步骤:
(a)建堆
(b)将堆顶与堆的最后一个元素对换
(c)将堆的大小-1(此时最后一个元素看作已排序好),并对剩下的部分保持堆的性质
(d)重复(b)、(c)直至排序完成
代码如下:
public class MinHeap { public final static int MAX = 100; private int[] heap = null; private int size = 0; public MinHeap(){ heap = new int[MAX]; } public boolean add(int num){ if (size >= MAX){ return false; } heap[size] = num; size++; return true; } public void buildHeap(){ for (int i = (size - 1) / 2;i >= 0;i--){ heapify(i); } } private void heapify(int pos){ int left = pos * 2 + 1, right = pos * 2 + 2; if (left >= size){ return; }else if (right >= size){ if (heap[pos] > heap[left]){ int tmp = heap[pos]; heap[pos] = heap[left]; heap[left] = tmp; } return; }else{ int minPos = pos; if (heap[pos] > heap[left]){ if (heap[left] > heap[right]){ minPos = right; }else{ minPos = left; } }else if (heap[pos] > heap[right]){ minPos = right; } int tmp = heap[pos]; heap[pos] = heap[minPos]; heap[minPos] = tmp; if (minPos != pos){ heapify(minPos); } } } public void heapSort(){ buildHeap(); int length = size; while (size > 0){ int tmp = heap[size-1]; heap[size-1] = heap[0]; heap[0] = tmp; size--; heapify(0); } size = length; } public void print(){ for (int i = 0;i < size;i++){ System.out.print(heap[i] + " "); } System.out.println(); } public static void main(String[] args) { MinHeap heap = new MinHeap(); for (int i = 10;i > 0;i--){ heap.add(i); } heap.heapSort(); heap.print(); }}
堆排序heapSort()的时间复杂度为O(nlgn),其中建堆buildHeap()的时间复杂度为O(n)(不是笔误,具体见算法导论),每一轮保持堆的性质heapify(int pos)的时间复杂度为O(lgn),一共O(n)轮。
回到topK问题上,我们可以维护一个大小为K的堆来帮助我们解决topK问题。以最小的K个数据为例,我们维护一个大小为K的大根堆在内存中,接下来每次从那一大堆数据当中读出一个数据与堆顶比较,若该数据比堆顶数据小,则说明它比当前topK的最大值要小,因此将堆顶替换为该数据,再用heapify(0)保持该堆的最大堆性质即可。
- 堆与堆排序与topK问题
- 【面经笔记】堆排序与topk问题
- 堆排序和TopK问题
- 最小堆获取topK问题与堆的增删
- topK问题解法之-堆排序
- topk--堆排序--小顶堆
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- Android反编译 -- 错误代码还原
- 状态机
- 简单编码
- 观察者模式
- springmvc 相应静态资源,view-controler-path
- 堆与堆排序与topK问题
- 在html中控制tr和td的个数
- 终于开CSDN了。。。
- 干货--Redis+Spring+Struts2实现网站计算器应用项目案例
- Ubuntu服务器-SVN
- Java网络连接-URLConnection类的使用
- C语言循环的实现
- 1020
- Problem H: C语言实验——整数位