我正在寻找存储整数集合的最有效方法。现在它们被存储在HashSet<T>
中,但是分析表明这些集合在一些性能关键代码中占很大比重,我怀疑有更好的选择。
更多细节:
目前最痛苦的表现就是创造它们。这似乎与分配有关 - 清除和重用HashSet
在基准测试中有很大帮助,但不幸的是,这在应用程序代码中不是一个可行的选项。
(已添加)实施适合任务的数据结构很好。哈希表还有可行吗?乍一看似乎是一种可能性,但我对它们没有任何实际经验。
答案 0 :(得分:1)
HashSet
通常是最好的通用收藏品。
如果您有关于您的收藏的任何具体信息,您可能有更好的选择。
如果你有一个不太大的固定上限,你可以使用合适大小的位向量。
如果你有一个非常密集的集合,你可以改为存储缺失值。
如果你有非常小的集合,&lt; = 4项左右,你可以将它们存储在一个常规数组中。对这种小型阵列的完全扫描可能比使用散列集所需的散列更快。
如果您的数据没有任何更具体的特征,那么“int
”HashSet
的大集合是可行的方式。
答案 1 :(得分:1)
如果值的大小有限,则可以使用bitset。它每整数存储一位。总的来说,内存使用将是log n位,n是最大整数。
另一种选择是布隆过滤器。 Bloom过滤器非常紧凑,但您必须为查找中的偶然误报做好准备。您可以在维基百科中找到更多相关信息。
第三个选项是使用simle排序数组。查找是log n,n是整数。它可能足够快。
答案 2 :(得分:1)
我决定尝试实现一个特殊用途的基于散列的集合类,它使用线性探测来处理冲突:
long
s 使用基本线性探针搜索后备存储中值的位置,如下所示:
int FindIndex(long value)
{
var index = ((int)(value & 0x7FFFFFFF) % _storage.Length;
var slotValue = _storage[index];
if(slotValue == 0x0 || slotValue == value) return index;
for(++index; ; index++)
{
if (index == _storage.Length) index = 0;
slotValue = _storage[index];
if(slotValue == 0x0 || slotValue == value) return index;
}
}
(我能够确定存储的数据永远不会包含0,因此该数字可以安全地用于空插槽。)
数组需要大于存储的元素数。 (加载因子小于1.)如果该组已被完全填充,则FindIndex()
将进入无限循环,如果它用于搜索该组中尚未存在的值。事实上,它需要有相当多的空白空间,否则搜索和检索可能会受到影响,因为数据开始形成大块。
我确信仍有优化空间,我可能会因为大型集合上的后备存储使用某种BigArray<T>
或分片而陷入困境。但初步结果很有希望。它的负载系数为0.5时,其执行速度是HashSet<T>
的两倍,加载系数为0.8时几乎快两倍,即使在0.9,我的测试仍然可以快40%。
开销是1 / load factor
,所以如果这些性能数据在现实世界中保持不变,那么我相信它的内存效率也会高于HashSet<T>
。我还没有做过正式的分析,但从HashSet<T>
的内部结构来看,我很确定它的开销远高于10%。
-
所以我对这个解决方案很满意,但是如果还有其他可能性我仍然很好奇。也许某种特里?
-
后记:最后还是在实时数据上与HashSet<T>
进行了一些竞争性基准测试。 (在我使用合成测试集之前。)它甚至超过了我以前的乐观期望。现实世界的性能比HashSet<T>
快6倍,具体取决于集合大小。
答案 3 :(得分:0)
我要做的只是创建一个足够大小的整数数组来处理你需要的整数。是否有任何理由远离通用List<T>
? http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
答案 4 :(得分:0)
目前最痛苦的表现就是创造它们......
正如您明显观察到的那样,HashSet<T>
没有一个构造函数,它使用capacity
参数来初始化其容量。
我认为可行的一个技巧如下:
int capacity = ... some appropriate number;
int[] items = new int[capacity];
HashSet<int> hashSet = new HashSet<int>(items);
hashSet.Clear();
...
查看使用反射器的实现,这会将容量初始化为items
数组的大小,而忽略了此数组包含重复项的事实。但是,它实际上只会添加一个值(零),所以我假设初始化和清算应该合理有效。
我没有对此进行测试,因此您必须对其进行基准测试。并且愿意承担取决于未记录的内部实施细节的风险。
知道为什么Microsoft没有像其他集合类型那样为capacity
参数提供构造函数,这将会很有趣。