我需要一个数据结构,它将非重叠范围(例如8..15
,16..19
)映射到指向结构的指针。
我需要能够查找该范围内的任何元素并检索该指针。例如:
structure[8..15] = 0x12345678;
structure[16..19] = 0xdeadbeef;
structure[7]; // => NULL
structure[12]; // => 0x12345678
structure[18]; // => 0xdeadbeef
我正在考虑使用二进制搜索树。由于范围永远不会重叠,我可以在对数时间内相对容易地搜索索引。
但是,我想知道是否有更适合这种情况的数据结构。我需要能够有效地插入,删除和查找。所有这些操作都是BST中的O(log n),但我想知道是否有更快的事情。
答案 0 :(得分:4)
如果你想要比O(log n)更快的东西,请使用Van Emde Boas tree。
它应该与使用二叉搜索树的方式相同:使用每个范围的开头作为键,范围的结尾 - 作为值的一部分(与指针一起),映射到此键。时间复杂度为O(log log M),其中M是键的范围(INT_MAX,如果范围的开始可以有任何整数值)。
在某些情况下,Van Emde Boas树的内存开销很大。如果这是不可接受的,请使用Beni解释的简单trie或Y-fast trie。
答案 1 :(得分:3)
我认为你不能做得更好。
非重叠范围与一系列交替的起点/终点等效。因此查找只是“找到最大元素≤x”,然后进行O(1)检查它是开始还是结束。即有序的地图。
通常的嫌疑人 - 二叉树,B树,各种尝试 - 都基本上都是O(log n)。在实践中最好的是调整问题,取决于对范围的了解。它们稀疏还是密集?它们的大小相似还是差别很大?数据有多大(适合缓存/内存/磁盘)?你插入/删除很多或查找占优势?是随机访问还是高位置访问?
适用于许多方案的一个权衡是分割范围,在几个地方复制相同的指针。这可能会加速查找,但代价是插入/删除和内存使用。极端应用程序只是一个由点索引的平面数组,其中lookup是O(1)但插入是O(范围的大小);这需要一个多级结构:一组k个统一的子范围,如果完全由一个范围覆盖则指向值,否则指向子数组。嘿,我刚才描述了一个特里!查找是log(maxint)/ log(k),如果k是2的幂(例如256),则非常快;插入和记忆是k * log(n) 但请记住,浪费内存会损害缓存性能,因此任何此类“优化”实际上都可能适得其反,即使对于查找也是如此。