堆结构-高效维护数据集中最大最小值问题
作者:互联网
堆结构介绍
堆结构是一颗完全二叉树,堆结构可以实现O(log n)级别的插入数据的时间复杂度,查询最大最小值可以达到O(1)的效率。
堆结构实现
堆结构维护代码
void put(int data){
int ch,fa;//child,father
heap[++heap_size]=data;//heap_size为全局变量 堆内元素个数
ch = heap_size;//从堆尾开始查找
while(ch>1){//child不为根
fa = ch / 2;//父亲位置
if(heap[ch] <= heap[fa])break;//如果child不够大,就没必要冒上去
swap(heap[ch],heap[fa]);//否则交换二值
ch = fa;//更新
}
}
Java定义堆结构
PriorityQueue<Integer> min = new PriorityQueue<>(); // 小顶堆
PriorityQueue<Integer> max = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆
堆结构使用
- 295. 数据流的中位数
题目:
这道题要实现一个数据结构,用来保存一个数据流,支持向数据流中插入数据和查询数据流中的中位数,操作数量是50000次。
分析
如果是插入之后排序,假设插入和查询是1:1,那么每次排序的复杂度是n*log n ,就是25000 * 16 * 25000 ,时间复杂度过高。
如果我们把这段数据流分为两段,一段保存排序后的左半部分,一半保存排序后的右半部分,例如 1,2 ; 3,4 ,这个数据流的中位数就是 (2 + 3)/2。
对于左半部分只需要知道左半部分的最大值,右半部分只需要知道最小值,则可以使用堆结构来维护最大最小即可。
维护方法
- 使用大顶堆来维护左半部分数据,使用小顶堆维护右半部分数据。
- 插入时如果两个堆大小一致,则将数据放入小顶堆排序,之后将小顶堆的根节点放入大顶堆。
- 如果两个堆大小不一致,则将数据放入大顶堆排序,之后将大顶堆的头部放入小顶堆。
- 因为大顶堆(左边)中的数据全部小于小顶堆(右边)中的数据,而新插入的数据可能会小于小顶堆(左边)中的数据,所以只需要将数据放入左边序,之后取出小的数据块中的最大值,放入右边的数据块中即可
代码
class MedianFinder {
Queue<Integer> A, B;
public MedianFinder() {
A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
B = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆,保存较小的一半
}
public void addNum(int num) {
if(A.size() != B.size()) {
A.add(num);
B.add(A.poll());
} else {
B.add(num);
A.add(B.poll());
}
}
public double findMedian() {
return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
}
}
标签:大顶,高效,PriorityQueue,最小值,数据流,小顶,维护,数据,size 来源: https://www.cnblogs.com/xyqxyq/p/16139430.html