4-2 堆的基本实现

4-2 堆的基本实现

如果一个算法的时间复杂度是 O(nlogn) ,那么算法执行的形状一定看起来像是一棵树一样(想一想我们的归并排序),所以堆在形式上就像一棵树。

二叉堆 Binary Heap 的特点

  1. 堆中某个节点的值总是不大于其父节点的值
    最大堆:顶上的元素是堆中所有元素的最大值。
  2. 堆总是一棵完全二叉树
    从形状上看,除了最后一层之外,其它层节点的数量应该是最大值,并且最后一层的节点应该集中在左侧。

使用数组实现二叉堆

为什么使用数组

因为最大堆是一棵完全二叉树,我们当然可以使用树这个数据结构来实现。但是,既然堆是一棵完全二叉树,回想一下完全二叉树的定义,我们使用数组来实现二叉堆(因为完全二叉树的性质,二叉树的索引可以很轻松地与数组的索引建立一一对应的关系),而事实上,数组也是堆的经典实现。

使用数组实现二叉堆的方式是:自上到下、从左到右对索引进行标记,第 0 号索引不使用,从 1 开始编号(根节点从1 开始标记,这是一种经典的做法)。

之所以,第 0 号索引不使用,是因为从 1 开始索引,对于二叉堆来说,有比较如下两条简单的性质,我们无畏浪费一个元素的空间。如果我们不明白为什么这么做,可以自己尝试从第 0 个位置开始索引(以后我们也会遇到这种情况),只不过是增大了一些计算量而已。

从索引为 1 的位置开始放置元素的数组实现的二叉堆的性质

我们自己画一个二叉堆(如下图),从索引为 1 的位置开始放置元素,把索引标注在二叉堆上,如下图,

观察下标的位置,对应数组的索引,以下基本性质就可以一目了然。

性质1:左节点的编号是父节点(如果父亲节点存在)的编号的 2 倍;

性质2:右节点的编号是父节点(如果父亲节点存在)的编号的 2 倍加 1。

我们可以使用数学归纳法得到如上的性质。

所以我们要想找到一个节点的父亲节点(如果父亲节点存在)可以使用公式:&parent(i)=i/2$,(这个除法是计算机的除法,除不开的话向下取整)。

要想找到两个子节点(如果孩子节点存在)可以使用公式: leftchild=2irightchild=2i+1

下面,我们以最大堆为例,讨论最大堆须要实现的 API。

最大堆(MaxHeap)的实现的基本框架

下面的代码展示了一个最大堆的基本实现框架:

public class MaxHeap {

    private int[] data;
    private int count; // 堆中真实元素的个数

    public MaxHeap(int capacity) {
        // 开辟数组空间(整个数组存储从索引 1 开始)
        data = new int[capacity + 1];
        count = 0;
    }

    public int size() {
        return count;
    }
    // 当前堆中的元素个数是否为 0
    public boolean isEmpty() {
        return count == 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值