如果您需要保护您的数据结构免受延迟峰值和哈希冲突攻击,则最好使用平衡的 BST。
前者发生在数组支持的结构增长和调整大小时,后者是散列算法的必然属性,作为从无限空间到有限整数范围的投影。
.NET 中的另一个问题是存在 LOH,如果字典足够大,您会遇到 LOH 碎片。在这种情况下,您可以使用 BST,但要付出更大的算法复杂度等级的代价。
简而言之,使用由分配堆支持的 BST,您将获得最坏情况 O(log(N)) 的时间,而使用哈希表,您将获得 O(N) 最坏情况的时间。
BST 以 O(log(N)) 平均时间、更差的缓存局部性和更多的堆分配为代价,但它具有延迟保证并且可以防止字典攻击和内存碎片。
值得注意的是,BST 在其他平台上也容易产生内存碎片,而不是使用压缩垃圾收集器。
至于内存大小,.NET Dictionary`2 类的内存效率更高,因为它将数据存储为堆外链表,仅存储值和偏移量信息。BST 必须存储对象头(因为每个节点都是堆上的一个类实例)、两个指针和一些用于平衡树的增强树数据。例如,红黑树需要一个解释为颜色(红色或黑色)的布尔值。如果我没记错的话,这至少是 6 个机器字。因此,64 位系统上的红黑树中的每个节点至少是:
标题 3 个字 = 24 字节 子指针 2 个字 = 16 字节 颜色 1 个字 = 8 个字节 值至少 1 个字 8+ 字节 = 24+16+8+8 = 56 字节(+8 字节如果树使用父节点指针)。
同时,字典条目的最小大小仅为 16 个字节。