最小堆排序MinHeap

Posted xiaoli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小堆排序MinHeap相关的知识,希望对你有一定的参考价值。

MinHeap基本性质

  1. 最小堆中的最小元素值出现在根结点(堆顶);
  2. 堆中每个父节点的元素值都小于等于其孩子结点(如果存在)

MinHeap用途

1.求一个数列中的第K大的数,建立一个大小为K的最小堆,堆顶就是第K大的数

2.递归去除最顶元素,用于取top K等。

MinHeap可设置容量上限N带来两个好处:

  1. 内存占用可控
  2. 因为上限N的存在,可提高添加和删除元素的速度

 

以上述思想,接下来开始java编码:

我们要用inputs=[1, 2, 5, 12, 7, 17, 25, 19, 36, 99, 22, 28, 46, 92]中的14个元素来建立最小堆;输出top 为data

1.建堆

对于inputs中的每个元素调用add方法,建堆后是完全二叉树,并且所有父节点都比子节点小

public void add(T ele) {
        int size = data.size();if (size < maxSize) {
            data.add(ele);// 堆底添加新元素
            heapUp(size);// 然后从末位置开始向上调整
        } else {
            if (ele.compareTo(data.get(0)) > 0) {// 如果大于堆顶元素则更新
                data.set(0, ele); // 替换顶元素
                heapDown(0);// 从上到下调整堆排序
            }
        }
    }

 2.向下调整代码

  从堆顶某一元素开始向下调整排序

private void heapDown(int i) {
        int l = 2 * (i + 1) - 1;
        int r = 2 * (i + 1);
        int smallest = i;// 左、右、父节点的最小值的索引
        // 如果左孩子存在,且左孩子小于smallest
        if (l < data.size() && data.get(l).compareTo(data.get(smallest)) < 0) {
            smallest = l;
        }
        // 如果右孩子存在,且右孩子小于smallest
        if (r < data.size() && data.get(r).compareTo(data.get(smallest)) < 0) {
            smallest = r;
        }
        // 如果父节点本来就比左右孩子小,则直接返回,不用继续向下调整
        if (smallest == i) {
            return;
        }
        // 父节点跟较小的那个子节点交换
        swap(i, smallest);
        // 交换后影响到了子树,所以对子树递归进行heapify
        heapDown(smallest);
    }

 3.向上调整代码

  从位置i开始开始向上调整排序

private void heapUp(int i) {
        if (i == 0)//如果是堆顶,就返回,不需要再调整了
            return;
        while (i > 0) {//不在堆顶,并且当前结点i的值比父节点小的时候就继续向上调整
            T ele = data.get(i);
            int p = (i - 1) / 2;// 父节点的index
            if (ele.compareTo(data.get(p)) < 0) {
                swap(i, p);
                i = p;
            } else {// 否则停止
                break;
            }
        }
    }

4.堆排序:删除堆顶元素

时间复杂度是O(NlogN),假如要从小到大排序,那么只需要建立最小堆,然后每次删除顶部元素并将顶部元素输出或者放入到一个新的数组中,直到堆为空为止。

public void delRoot() {
        int size = data.size();
        if (size > 0) {
            T lastEle = data.get(size - 1);
            if (size > 1) {
                data.set(0, lastEle);// 最后元素设置为堆顶
                data.remove(size - 1);
                heapDown(0);// 从根节点开始向下重整堆
            } else {
                data.remove(size - 1);
            }
        }
    }

 

以上是关于最小堆排序MinHeap的主要内容,如果未能解决你的问题,请参考以下文章

为啥有些人使用 PriorityQueue 覆盖比较器函数来实现 minheap,即使 Java 中的 PQ 默认是最小堆?

堆和堆排序

通过 insertKey 和 buildHeap 构建堆获得不同的答案

数据结构之Heap (Java)

如何在最小堆中跟踪元素的位置/索引?

我的堆排序算法时间复杂度分析是不是正确?