堆数据结构、堆排序、topK问题

本文介绍了堆数据结构,包括大顶堆和小顶堆的概念,详细阐述了自上到下和自下到上构建堆的方法,以及堆排序的原理。此外,还探讨了如何利用堆解决TopK问题,并提到了使用Java的PriorityQueue实现堆功能。
摘要由CSDN通过智能技术生成

堆数据结构

堆(heap),是一种特殊的数据结构。之所以特殊,因为堆的形象化是一个棵完全二叉树,并且满足任意节点始终不大于(或者不小于)左右子节点(有别于二叉搜索树Binary Search Tree)。其中,前者称为小顶堆(最小堆,堆顶为最小值),后者为大顶堆(最大堆,堆顶为最大值)。然而更加特殊的是,通常使用数组去存储堆,而不是二叉树。

/**
 *    Heap is a sepcial complete binary tree(CBT)
 *    Heap sketch is a CBT, but stored in Array
 *        9 ---> maxtop         7                 7
 *       / \                   / \               / \
 *      /   \                 /   \             /   \
 *     7     8               4     8           4     5
 *    / \   / \             / \               /     /
 *   /   \ /   \           /   \             /     /
 *  5    3 2    4         3     5           3     6
 *
 *      (1)                  (2)                (3)
 *  maxtop heap       not maxtop(mintop)    not heap(CBT)
 */

具体而言,对于长度为N的数组A中的任意一个元素i(0 <= i < N / 2),其左右子节点为i * 2 + 1和i * 2 + 2。以大顶堆为例,该堆始终满足:

A[i] >= A[i2 + 1] && A[i] >= A[i2 + 2]。(下文不做特殊说明均以大顶堆为例)

如何创建一个堆呢?对于给定的一个数组arr[]和长度n,一般使用在数组上就地堆化。堆化的过程实际是调整堆的过程。有自上到下和自下到上两种堆化方法。

1)自上到下构建堆

// Method 1
// Create (Initialize) Heap, from top to bottom
public void heapCreate(int arr[], int n) {
   
    int i;        // from top to bottom
    for (i = 1; i < n; heapAdjust(arr, i++)) ;
}

自上到下很好理解,首先假设当前数组arr的前i个元素已经满足堆性质(arr[0]只有一个元素肯定满足);然后每次在数组之后添加一个元素A[i],使得新的数组A[0~i]满足堆化性质,其中heap_adjust可以调整当前节点i使其满足堆化;直到i为n时,调整完毕,即堆化完毕。其中heap_adjust如下:

public void heapAdjust(int arr[], int c) {
   
    // c - children, p - parent
    int p = (c - 1) >> 1, temp;
    // heap adjust from maxtop, from bottom to top
    for (; arr[p] < arr[c]; c = p, p = (c - 1) >> 1) {
   
        temp = arr[p];
        arr[p] = arr[c];
        arr[c] = temp;
    }
}   // Time O(logn)

调整代码也很好理解,首先找到当前节点c的父节点p,如果arr[p]<arr[c],则交换,然后继续寻找p的父节点进行调整;否则,调整完毕(因为前文已经假设,数组的前i-1已经满足堆化,新添一个元素i进行调整)。

很有意思,构建堆时使用自上到下,那么调整堆就必须自下到上。

2)自下到上构建堆

// Method 2
// Create (Initialize) Heap, from bottom to top
void heap_create(int arr[], int n) {
   
    int i;        // from bottom to top
    for (i = (n >> 1) - 1; i > -1; headjust(arr, i--, n)) ;
}

此处自下到上的“下”,并不是数组最后一个元素,而是最后一个父节点n/2-1。也就是以父节点为线索,逐渐调整该节点的子节点。因此,此处heap_adjust是自上到下的调整,如下

public void heapAdjust(int arr[], int p, int n) {
   
    // c - children, p - parent
    int maxid = p, temp;
    // heap_adjust for maxtop, from top to bottom
    for (; p < (n >> 1); p = maxid) 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值