堆需要以下2个条件:1. 堆是一个完全二叉树;2. 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。堆排序有几个非常重要的应用:优先级队列、求 Top K 和 求中位数。对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作“小顶堆”。rust 标准库里面提供了 binary heap 的实现,但是现在我们还不能在 Substrate Runtime 环境下直接使用它。那么我们在 Substrate Runtime 环境中实现一个泛型的堆结构,并且利用 Substrate 默认的 storage value 作为堆的存储来解决 Top K 问题。
3.要实现一个堆,
我们先要知道如何存储一个堆
用数组来存储完全二叉树是个不错的选择。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点,非常节省存储空间。先来看一下这个堆结构代码的样子:这里 T 代表堆中元素类型。C 代表 Compare trait,可供自定义排序方式(决定是大顶堆还是小顶堆)。S 代表存储类型,这个数组利用了 Substrate 提供的 StorageValue<Vec<T>, Query=Vec<T>> 类型。我画了一个用数组存储堆的例子:从图中我们可以看到,数组中下标为 i 的节点的左子节点,就是下标为 i∗2+1 的节点,右子节点就是下标为 i∗2+2 的节点。 寻找左子节点,右子节点对应的代码: 寻找父节点对应代码: