让我给你介绍一个有趣的数据结构,叫做 Wavelet Tree:
您通过查看整数的位串表示并递归地二等分它们来构建它:
您首先将整数分为最高有效位 (MSB) 为 0 的整数和最高有效位 (MSB) 为 1 的整数。但是,您将 MSB 以其原始顺序存储在位向量中。然后对于这些整数子集中的每一个,忽略 MSB 并递归地为下一个最高有效位重复此构造。
如果你重复这个直到最低有效位,你会得到一个像这样的树结构(注意索引只是为了说明,你应该只存储位向量):
你可以很容易地看到,这个数据结构的构建需要 O(n log N) 时间,其中 n 是整数的个数,N 是它们的最大值。
小波树具有很好的特性,即它们同时表示原始序列以及排序后的对应物:
要有效地使用小波树,您需要对位向量进行两个基本操作:
-
rank1(k) 告诉你在位向量中第 k 个位置之前有多少个 1,rank0 对 0 也是如此
-
select1(k) 告诉你位向量中第 k 个 1 的索引,select0 对 0s 做同样的事情
请注意,有些位向量表示只需要 o(n)(小 o)位的额外存储空间即可在 O(1) 中实现这些操作
您可以按如下方式使用它们:
现在如何用这个实现范围中值查询?你需要做的最重要的认识是找到一个大小范围k的中值等同于选择 k/第 2 个 元素。
该算法的基本思想类似于快速选择:将元素范围一分为二并仅递归到包含您要查找的元素的范围内。
假设我们要找到从第二个 2(包括)开始到 1(不包括)结束的范围的中位数。
这些是 7 个元素,因此中位数在该范围内具有等级 4(第四小元素)。
现在使用 rank0/1 在这个范围的开始和结束的根位向量中调用,我们在根的孩子中找到相应的范围:
如您所见,左侧范围(仅包含较小的元素)只有 3 个元素,因此排名为 4 的元素必须包含在根的右孩子中。我们现在可以在该右孩子中递归搜索排名为4 - 3 = 1 的元素。通过递归地递减小波树直到到达叶子,因此您可以在小波树的每个级别仅使用两个秩操作(à O(1) 时间)来识别中值,因此整个范围中值查询需要 O(log N) N 是输入序列中的最大数的时间。
如果您想查看这些小波树的实际实现,请查看实现上述位向量和不同 WT 变体的Succinct Data Structures Library (SDSL)。