通俗解释大顶堆和小顶堆

Posted 元之田

tags:

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

  1. 基础数据结构
    想象我们有一个数组,数组中有0到9,10个元素。

    我们按照顺序将一颗二叉树画出来。
  2. 如果我们将数据填入数组之中,树种相应节点的值也将填入。

这里我们观察到,树中节点之间存在如下关系:

假设当前节点的下标为i ——

节点的左子节点的下标为:2 * i + 1;
节点的右子节点的下标为:2 * i + 2;

  1. 大顶堆和小顶堆
    我们知道大顶推满足的条件是每一个父节点都比子节点大。
    那么我们应该如何通过调换节点的位置来构建这样的数据结构呢?

我们取这个树的一个片段,假设数据为2,1,3。那么我们需要进行的一个操作是heapify-down,通过将2和1与3中比较大的节点替换位置,以此来满足条件。

这是我们调整的过程。

我们观察可知,对于一颗长度为10的树(堆),我们自上而下只需要将节点4,3,2,1,0分别进行heapify既可以满足大顶堆的满足条件。

建堆代码:

    //build max heap
    public void buildHeap(int[] arr)
        for(int i = arr.length/2; i >=0; i--)
            adjust(arr, i);
        
    

但这里有需要注意的地方。举个例子,如果我们对节点1进行heapify,节点1将与节点3和4中值比较大的节点交换值。这样的话,节点3或4其中之一的值就会发生改变,为了满足堆的条件,因此我们需要再对替换顺序后的节点进行一次heapify,这也是为什么heapify中存在递归的原因。

对于大顶堆,我们是自下而上进行建堆,这样我们把最大值推上0的位置。
注意我们的heapify是自上而下将大的元素向下转移。

    public void adjust(int[] arr, int i)
        int maxIndex = i;
        int len = arr.length;
        if(2*i+1 < len && arr[2*i+1] > arr[maxIndex]) maxIndex = 2*i+1;
        if(2*i+2 < len && arr[2*i+2] > arr[maxIndex]) maxIndex = 2*i+2;
        if(maxIndex != i)
            swap(arr, maxIndex, i);
            adjust(arr, maxIndex);
        
    
  1. 新元素的加入。
    当有新元素加入堆中时,我们需要重新进行heapify的操作,我们只需要把元素加入到堆的末尾,然后重新进行heapify即可。
    在应用中,我们往往需要找到第k大的数字,只需要在建好大顶堆后,判断新元素是否比堆顶元素小即可,如果小即替换,再重新heapify-down。

  2. 除此之外,也有heapify-up进行自下而上的调整操作,这些根据具体需要可以自行构建。

在java中我们可以使用PriorityQueue来解决涉及堆的问题。

以上是关于通俗解释大顶堆和小顶堆的主要内容,如果未能解决你的问题,请参考以下文章

大顶堆,小顶堆

大顶堆,小顶堆

大顶堆构造过程

堆排序

详解堆排序算法

堆排序