堆排序

堆排序基本介绍

  • 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
  • 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆, 注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系。
  • 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆

                   

 

堆排序基本思想

堆排序的基本思想是:

  • 将待排序序列构造成一个大顶堆
  • 此时,整个序列的最大值就是堆顶的根节点。
  • 将其与末尾元素进行交换,此时末尾就为最大值。
  • 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。 可以看到在构建大顶堆的过程中,元素的个数逐渐减少,最后就得到一个有序序列了.

剑指:数据流中的中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

思路分析:

使用大顶堆和小顶堆, 核心: 保持大顶堆小顶堆size差距不超过1的情况下, 正确地插入数据: 要保证大顶堆的最大值小于小顶堆的最小值; 堆为空就不涉及比较过程了,直接插入

我们将数据分为两部分,位于左边大顶堆的数据比右边小顶堆的数据要小,左、右两边内部的数据没有排序,也可以根据左边最大的数及右边最小的数得到中位数。

接下来考虑用大顶堆和小顶堆实现的一些细节。

首先要保证数据平均分配到两个堆中,因此两个堆中数据的数目之差不能超过1.为了实现平均分配,可以在数据的总数目是偶数时把新数据插入到小顶堆中,否则插入到大顶堆中。

此外,还要保证大顶堆中所有数据小于小顶堆中数据。所以,新传入的数据需要先和大顶堆的最大值或者小顶堆中的最小值进行比较。以总数目为偶数为例,按照我们制定的规则,新的数据会被插入到小顶堆中,但是在这之前,我们需要判断这个数据和大顶堆中的最大值谁更大,如果大顶堆中的数据比较大,那么我们就需要把当前数据插入最大堆,然后弹出新的最大值,再插入到小顶堆中。由于最终插入到小顶堆的数字是原大顶堆中最大的数字,这样就保证了小顶堆中所有数字都大于大顶堆的数字。

import java.util.PriorityQueue;
import java.util.Comparator;

public class Solution {
    //大根堆
    public PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(
        new Comparator<Integer>(){
            public int compare(Integer o1, Integer o2){
                return o2 - o1;
            }
        }
    );
    //小根堆
    public PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
    public int count=1;
    //要保证大根堆的最大值小于小根堆的最小值
    //插入策略: 先插入再调整; 轮流向大根堆和小根堆中插入一个数, 不妨先大根堆,再小根堆. 这样就能保证大根堆和小根堆的size最多差1
    public void Insert(Integer num) {
        //第奇数个数插入大根堆
        if(count%2==1){
            //当前数比小根堆的最小值大的话,就不能插入大根堆了,只能插入小根堆
            if(!minHeap.isEmpty() && num > minHeap.peek()){
                minHeap.add(num);
                num = minHeap.poll();
            }
            maxHeap.add(num);
            count++;
        }
        //第偶数个数插入小根堆
        else{
            //如果当前数小于大根堆的最大值,就只能插入大根堆了
            if(!maxHeap.isEmpty() && num < maxHeap.peek()){
                maxHeap.add(num);
                num = maxHeap.poll();
            }
            minHeap.add(num);
            count++;
        }
    }

    public Double GetMedian() {
        return maxHeap.size()==minHeap.size() ? (maxHeap.peek()+minHeap.peek())/2.0 : maxHeap.peek()*1.0;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值