假设我有一个包含1到100个键的字典(在.NET中)。 我从历史数据中知道,比如99%的时间我访问这个词典来检索密钥5,37,88的数据。 有没有办法我可以组织这个dicionary,以便使用这3个键非常快,即使以寻找剩余的97个键浪费更多的时间为代价? 或者是否有不同的数据结构可以使用这些知识来改善平均访问数据的时间?
答案 0 :(得分:0)
在字典的合理实现中,查找的成本将由内存访问的成本决定。您的硬件将为您优化此功能,将最常访问的项目保留在最快的缓存级别。除非你有一台小型计算机,否则100个项目将适合你最快的缓存。
也就是说,如果您使用具有单独链接的哈希表,则可以将这些项目移动到其链的前面。这确保查找这些项目将是O(1)最坏情况保证,而对于字典中的至少一个项目,查找是O(log n / log log n),概率很高。
当然,如果你只有100个密钥,使用哈希表而不是字典将确保每个密钥都有O(1)最坏情况访问。
答案 1 :(得分:0)
你可以在字典前面使用一个小缓存,这可能会更快。例如,如果您知道大多数访问权限是针对第3项,第37项和第88项,那么您可以拥有:
private Dictionary<int, MyDataType> TheDictionary;
private KeyValuePair<int, MyDataType>[] quickLookup;
void InitializeDictionary()
{
TheDictionary = new Dictionary<int, MyDataType>();
// here, initialize the dictionary with the data.
// Now, set up the cache
quickLookup = new KeyValuePair<int, MyDataType>[]
{
new KeyValuePair(3, TheDictionary[3]),
new KeyValuePair(37, TheDictionary[37]),
new KeyValuePair(88, TheDictionary[88])
};
现在,当您想要查找项目时,首先要检查缓存:
bool TryDictionaryLookup(int key, out MyDataType data)
{
foreach (var kvp in quickLookup)
{
if (kvp.key == key)
{
data = kvp.Value;
return true;
}
}
// didn't find it. Check the dictionary.
return TheDictionary.TryGetValue(key, out data);
}
如果您的缓存只有三个项目,这可以为您提供小性能提升。但是,如果你得到超过五个或六个项目,它可能会比直接字典查找更糟糕。你必须做一些时间来确定甜蜜点的位置。
另请注意,如果您真正进行此类微优化,则可能应将foreach
替换为for
循环:
for (int i = 0; i < quickLookup.Length)
{
if (quickLookup[i].Key == key)
...
...
这将消除创建枚举器的开销。
此技术应提供性能提升的原因是访问字典需要从密钥计算哈希值。虽然这是一个快速操作,但它仍然比一些数组访问更多的开销。同样,在您投入生产之前,您需要使用代表性数据对其进行全面测试和分析。
在为switch
语句生成代码时,C#编译器使用(至少用于;我暂时没有检查过)类似的东西。如果switch
包含少于几个数字的情况(我认为它是六次,我上次检查过),那么编译器会生成一系列if/else
语句。对于六个或更多项,它会生成一个键和分支位置的字典,以及用于在字典中查找案例值并分支到相关代码的代码。