C++ 如果键存在于块中且块之间有间隙,则使用什么数据结构?

C++ 如果键存在于块中且块之间有间隙,则使用什么数据结构?,c++,data-structures,C++,Data Structures,我必须在键(整数)遵循如下模式的位置存储数据: 1,2,4,5,60,61,63 也就是说,关键点有时会聚集在数百个关键点的块中,其中的间隙很少,但块之间可能存在较大的间隙。偶尔,在无处的中央有孤独的钥匙或小块。 目前,std::map用于存储密钥,但它在分析中显示为查找密钥需要时间。这是因为我们需要随机访问密钥,并且有数千个密钥 到目前为止,最大密钥是16位,所以我尝试用std::vector替换,在调试模式下,它的速度提高了约10%(整个程序的性能)。发布模式的改变可以忽略不计,但我们在调试

我必须在键(整数)遵循如下模式的位置存储数据:

1,2,4,5,60,61,63

也就是说,关键点有时会聚集在数百个关键点的块中,其中的间隙很少,但块之间可能存在较大的间隙。偶尔,在无处的中央有孤独的钥匙或小块。

目前,
std::map
用于存储密钥,但它在分析中显示为查找密钥需要时间。这是因为我们需要随机访问密钥,并且有数千个密钥

到目前为止,最大密钥是16位,所以我尝试用
std::vector
替换,在调试模式下,它的速度提高了约10%(整个程序的性能)。发布模式的改变可以忽略不计,但我们在调试模式下做了很多长时间的工作

但现在密钥的长度可能高达32位,所以这是不可能的

我尝试了
std::unordered\u map
,但这比
std::map
的性能差!我对哈希映射没有太多经验,所以也许我可以调整哈希策略,但我不知道如何调整

关于此任务的有效数据结构有什么建议吗


谢谢。

我不会从编程方面回答你,而是从数学方面回答你

也许创建堆分析器是一个很好的解决方案(一切都取决于您必须使用的真实数据),它将把您的数千个数字拆分为数百个堆

请记住最低堆数为“堆基”。 对于每个堆,您可以创建指向数据的指针向量,其中N元素的数字为“heap base”+N(因此,一些指针将为nullptr,但这些向量不会很长)

然后,您可以创建“heap base”编号的映射(每个编号都与其堆向量相连接)。从向量中访问N个元素需要O(1),它必须非常快。在地图堆中搜索也会更快,因为您将搜索数百个堆,而不是数千个数字

使用“lower_bound”,您将能够找到最接近您正在搜索的数字的堆,然后在该堆中搜索它

如果您的中等堆由K个数字组成,您将以Log(2)K的形式提高速度,K=8-三倍。你将失去搜索和其他一些行动的时间,但可能会在速度上大获全胜

如果您只需要创建一次数据存储,然后使用它,那么它可以成为解决方案

根据示例中的数字,您必须收到: (其中T是您正在搜索的对象)

向量a={obj1,obj2,nullptr,obj4,obj5}
向量b={obj60,obj61,nullptr,obj63}
地图我的地图;
追加(对(1,a));
追加(对(60,b));
(其中objN是T*)
然后使用bounds方法搜索数字,例如63。获取向量,并从中提取数字为63的元素-“基”(即数字为3)

如果键或多或少地不断分散(在大范围内),则可以创建树结构并在每一层中将数据分组在一起

例如,您的密钥范围从0到1000000,那么您将在第一层中拥有:

1) all keys from 0 to 99,000
2) from 100,000 to 199,999
3) ...
10) from 900,00 to 1,000,000

然后你继续到较低的层,在那里你再次拆分子组。在最底层,有一个向量,其中包含该组中实际可用的键。通过有3个这样的层,您可以将要通过的关键点数量减少约1/1000倍于原始数量。这将大大缩短某个键的查找时间。

我真的有点惊讶您的
std:::无序的\u map
遇到了您所述的性能问题。通过对密钥的分布分析,可以很好地确定您是否可以调整哈希值算法以更好地分布数据。在大多数基于密钥的算法中没有银弹,但我。。。惊讶
std::map
的性能优于
std::unordered_map
。你看过了吗?恐怕键在大尺度上是不同源的。对于无符号int_32t:UINT_MAX/1000=4.294.967,大尺度是(假设你引入了3个层,每个层有10个子组)。如果此长度间隔内的关键点数量大致相同,则可以。如果在较小的时间间隔内有累积,我建议您找出这些时间间隔的边界,并将其作为上述程序的“起始”时间间隔。如果您必须在运行期间添加密钥,并且在动态更改容器的边界之前不知道任何累积,则每个容器中的密钥数相等。您可以按规则创建堆(数字不超过N)。然后用N=2、4、6、10、20、100测试堆的创建。查看您得到的堆的数量,以及有多少堆由一个元素/少于M的元素组成(当您拥有尽可能多的堆且由少于M的元素组成时,最好是N)。在你找到N之后,你可以一直使用它,即使每个程序开始时你都会收到不同的数字,它们来自相同的规则,你从这样的分析中选择的N必须足够好)。
1) all keys from 0 to 99,000
2) from 100,000 to 199,999
3) ...
10) from 900,00 to 1,000,000