堆应用实例

本文介绍了如何使用堆数据结构在数据流中实时计算中位数。通过维护一个大根堆和一个小根堆,确保较小一半的数在大根堆中,较大一半的数在小根堆中。当堆不平衡时,通过调整保持堆的平衡,从而可以在常数时间内获取中位数,而插入新数的时间复杂度为O(logN)。
摘要由CSDN通过智能技术生成

一个数据流中,怎么样做到随时可以取得中位数

  • 题目描述:有一个源源不断地吐出整数的数据流,假设你有足够的空间来保存吐出的数。请设计一个名叫MedianHolder的结构,MedianHolder可以随时取得之前吐出所有树的中位数。

  • 要求:

    1.如果MedianHolder已经保存了吐出的N个数,那么任意时刻将一个新的数加入到MedianHolder的过程中,时间复杂度O(logN)。

    2.取得已经吐出的N个数整体的中位数的过程,时间复杂度O(1).

减堆操作:

 *  //1.将堆顶位置上的数弹到小根堆
 * 2.把最后一个叶子结点(即为堆的最好一个位置)的数放到(堆顶)根节点
 * (或者说与堆顶的数交换,反正后面HeapSize都要减一的,堆顶的数最终都会失效,当然交换还是更容易操作)
 * 3.将标记越界的变量(HeapSize)减一
 * 4.从堆顶开始经历一个Heapify,即可恢复为大根堆
  • 为啥一定要将最后一个位置的数放在堆顶? *
    因为:标记越界的变量(HeapSize:表示当前一个堆已经形成的大小)需要减一,如果将其他位置上的 数 放在堆顶, *
    势必会导致最后一个位置的数因为越界而失效

    如何将大根堆位置上的数赶到小根堆?

    • 如果当前数大于大根堆中的堆顶的数,就直接扔到小根堆里面,否则扔到大根堆里面
    • //1.将堆顶位置上的数弹到小根堆
    • 2.把最后一个叶子结点(即为堆的最后一个位置)的数放到(堆顶)根节点
    • (或者说与堆顶的数交换,反正后面HeapSize都要减一的,堆顶的数最终都会失效,当然交换还是更容易操作)
    • 3.将标记越界的变量(HeapSize)减一
    • 4.从堆顶开始经历一个Heapify,即可恢复为大根堆
    • 如果大根堆与小根堆不平衡了(相差为2个数时),怎么办呢?
    • 数较多的堆若为大根堆,就将大根堆中的最小的数(经过以上的排序后,最小的数已经到了大根堆堆顶)拿到小根堆中
    • 数较多的堆若为小根堆,就将小根堆中的最大的数(经过以上的排序后,最大的数已经到了小根堆堆顶)拿到大根堆中,
    • 使得大根堆与小根堆中分别盛放较小的N/2个元素和较大的N/2个元素
    • 这样随时都可以随时拿到中位数
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
 
/**
 * 随时找到数据流的中位数
 * 思路:
 * 利用一个大根堆和一个小根堆去保存数据,保证前一半的数放在大根堆,后一半的数放在小根堆
 * 在添加数据的时候,不断地调整两个堆的大小,使得两个堆保持平衡
 * 要取得的中位数就是两个堆堆顶的元素
 */
public class MedianQuick {
   
    public static class MedianHolder {
   
        private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new MaxHeapComparator());
        private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new MinHeapComparator());
 
        /**
         * 调整堆的大小
         * 当两个堆的大小差值变大时,从数据多的堆中弹出一个数据进入另一个堆中
         */
        private void modifyTwoHeapsSize() {
   
            if (this.maxHeap.size() == this.minHeap.size() + 2) {
   
                this.minHeap.add(this.maxHeap.poll());
            }
            if (this.minHeap.size() == this.maxHeap.size() + 2) {
   
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追梦_赤子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值