美文网首页
堆排序和基于堆的扩展

堆排序和基于堆的扩展

作者: yxwithu | 来源:发表于2017-12-05 20:41 被阅读0次

堆排序

首先描述和实现堆排序,以排序结果为从小到大为例:

  1. 堆的基本性质是:子结点的键值或索引总是小于(或者大于)它的父节点。
  2. 首先要将要排序的数组构建成一个堆,即让它满足堆的性质:从第一个非叶子节点起到根节点进行调整,让子节点不大于父节点
  3. 将根节点和最后一个叶子节点交换
  4. 从根节点开始往下一级一级调整使重新满足堆的性质
  5. 再转到3,直到所有结点都交换过了

详细的图解可以参考这里

public class HeapSort {
    private int[] arr;
    public HeapSort(int[] arr){
        this.arr = arr;
    }

    private void swap(int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
     * 调整索引为 index 处的数据,使其符合堆的特性。
     *
     * @param index 需要堆化处理的数据的索引
     * @param len 未排序的堆(数组)的长度
     */
    private void maxHeapify(int index, int len){
        int li = (index << 1) + 1;
        int ri = li + 1;
        int cMax = li;

        if(li > len) return;
        if(ri <= len && arr[ri] > arr[li]){
            cMax = ri;
        }
        if(arr[cMax] > arr[index]){
            swap(cMax, index);
            maxHeapify(cMax, len);
        }
    }

    public void sort(){
        /*
         *  第一步:将数组堆化
         *  beginIndex = 第一个非叶子节点。
         *  从第一个非叶子节点开始即可。无需从最后一个叶子节点开始。
         *  叶子节点可以看作已符合堆要求的节点,根节点就是它自己且自己以下值为最大。
         */
        int len = arr.length - 1;
        int beginIndex = (len - 1) >> 1;
        for(int i = beginIndex; i >= 0; i--){
            maxHeapify(i, len);
        }

        /*
         * 第二步:对堆化数据排序
         * 每次都是移出最顶层的根节点A[0],与最尾部节点位置调换,同时遍历长度 - 1。
         * 然后从新整理被换到根节点的末尾元素,使其符合堆的特性。
         * 直至未排序的堆长度为 0。
         */
        for(int i = len; i > 0; i--){
            swap(0, i);
            maxHeapify(0, i - 1);
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{3,5,3,0,8,6,1,5,8,6,2,4,9,4,7,0,1,8,9,7,3,1,2,5,9,7,4,0,2,6};
        new HeapSort(arr).sort();
        System.out.println(Arrays.toString(arr));
    }
}

数据流中的中位数

基于堆可以做很多的扩展,以找数据流中的中位数为例:

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有值排序之后位于中间的数值。如果数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

需要注意的是,数据流是不断读入的,可能需要动态的输出中位数。

基于堆的解法:
用一个大顶堆和一个小顶堆,维持大顶堆的数都小于等于小顶堆的数,且两者的个数相等或差1。中位数就在两个堆顶的数之中。
java中若想使用堆可以用PriorityQueue,内部是用小顶堆实现的

class MedianFinder {

    private Queue<Long> small = new PriorityQueue(),    //左半部分,源数据从大到小排序,实现方法是数据前面加一个负号
                        large = new PriorityQueue();  //右半部分,数据源从小到大排序(默认)

    public void addNum(int num) {
        large.add((long) num);   //先加到右半部分
        small.add(-large.poll());  //再加大左半部分
        if (large.size() < small.size())  //发现右半部分小了
            large.add(-small.poll());  //再移回来
    }

    public double findMedian() {
        return large.size() > small.size()
               ? large.peek()
               : (large.peek() - small.peek()) / 2.0;
    }
};

相关文章

  • 堆排序和基于堆的扩展

    堆排序 首先描述和实现堆排序,以排序结果为从小到大为例: 堆的基本性质是:子结点的键值或索引总是小于(或者大于)它...

  • 堆 - 堆和堆排序

    什么是堆 堆是一种特殊的树,它有两个特点: 堆是一个完全二叉树 堆中每个节点的值都必须大于等于(或小于等于)其子树...

  • 堆排序

    阅读原文 堆排是基于堆的一种排序算法,对于堆的了解,请看什么是堆排序(如果对堆的插入和删除不清楚,强烈建议先看堆)...

  • 堆排序

    一、定义 堆排序(Heap Sort)是一种基于优先队列(堆实现)的排序方式。堆排序的步骤如下: 初始时待排序元素...

  • Java排序算法 - 堆排序

    堆排序 堆排序是基于堆这种数据结构的一种排序算法,通过每一次弹出堆顶元素,实现排序。预备知识: 堆是一棵完全二叉树...

  • 堆和堆排序

    堆的简介 堆排序是一种复杂度为Nlog(N)的排序算法。介绍堆排序之前先讲一讲什么是堆。这里介绍的是数据结构中的二...

  • 堆和堆排序

    堆: 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于左右孩子节点的值,称为大顶堆;每个节点的值都小于或等于...

  • 堆和堆排序

    姓名:王怀帅 学号:16040410035 转载自:http://www.jianshu.com/p/86428c...

  • 堆和堆排序

    优先队列 优先队列是什么:与常见的队列不同的是,优先队列并不遵循“先进先出”的原则,反而是根据优先级来确定是否先出...

  • 堆和堆排序

    1. 堆的概念 堆是一种特殊的树,一个堆需要满足如下两个条件: 一个堆是一个完全二叉树; 堆中每个节点的值都必须大...

网友评论

      本文标题:堆排序和基于堆的扩展

      本文链接:https://www.haomeiwen.com/subject/ubthixtx.html