SortedSet<T> 与 HashSet<T>

Posted

技术标签:

【中文标题】SortedSet<T> 与 HashSet<T>【英文标题】:SortedSet<T> vs HashSet<T> 【发布时间】:2011-06-05 02:19:21 【问题描述】:

我的问题是,当我们拥有SortedSet&lt;T&gt; 时,HashSet&lt;T&gt; 的需要是什么!所有 HashSet 的方法都在 SortedSet 中可用,而且 SortedSet 的优势在于它已经以排序的方式提供了集合!即使这样 HashSet 也存在。那它有什么用呢?

【问题讨论】:

HashSet 如果您希望项目未排序且唯一?来自 MSDN > HashSet 类提供 > 高性能集合操作。集合 > 是不包含 > 重复元素的集合,并且其元素 > 没有特定顺序。 msdn.microsoft.com/en-us/library/bb359438.aspx 如果你有一组一开始就没有良好排序的东西怎么办?例如,您将如何在三个空间中创建一组 排序 点?你会按什么排序? 在使用 HashSet&lt;T&gt; 时需要知道的一个有用(有时)的事情:即使在 64 位应用程序中,它也可以存储多达 ~4800 万个 Guids 或 longs 或 ~95数百万ints,然后抛出OutOfMemoryExceptionSortedSet&lt;T&gt; 似乎有更高的容量限制。如果出于某种原因您需要在内存中保留数亿个项目,HashSet&lt;T&gt; 可能不是一个好的选择。 @Vladimir:根据文档,“对于非常大的 HashSet 对象,您可以通过设置 配置元素在运行时环境中为 true。" 【参考方案1】:

HashSet&lt;T&gt;SortedSet&lt;T&gt; 都在实现 interface ISet&lt;T&gt;,这是一个包含独特元素的数据结构。

它们之间的主要区别在于它们用于存储数据的底层数据结构。 HashSet&lt;T&gt; 使用哈希表,而SortedSet&lt;T&gt; 使用红黑树,这是一种平衡二叉树。

使用哈希表的HashSet&lt;T&gt; 执行基本操作(即添加、删除、搜索)的速度比SortedSet&lt;T&gt; 快,因为HashSet&lt;T&gt; 的复杂度为 O(1),这意味着它将执行独立于在恒定时间段内输入数据的大小,而SortedSet&lt;T&gt; 的复杂度为 log(N),这意味着取决于输入的大小,它将执行对数的基本操作。例如,如果输入数据的大小为 1,000,则程序分 10 步执行基本操作,如果输入数据为 1,000,000,则程序分 20 步执行基本操作。

结论:使用HashSet&lt;T&gt;如果您不需要对元素进行排序否则使用SortedSet&lt;T&gt;。这意味着使用HashSet&lt;T&gt;首选,除非您需要排序。

【讨论】:

这是这个问题下的最佳答案。非常有用,谢谢分享。【参考方案2】:

这是关于为工作选择正确的工具。取决于您使用收藏的方式。

This page 有一个很好的表格,详细说明了各种集合类之间的差异。

以下是该表中关于您所询问的集合的摘录:

集合订购连续存储?直接访问?查找效率 操纵效率 SortedSet Sorted No Via Key Key:O(log n) O(log n) HashSet Unordered Yes Via Key Key:O(1) O(1)

【讨论】:

我看到您链接到的文章将基于 Hashtable 的类型(Dictionary&lt;TKey,TValue&gt;HashSet&lt;T&gt;)列为“连续” - 但它们不会将密钥连续存储在其内部(即通常sparse) 键数组,而 SortedDictionarySortedSet 使用密集树,所以我很惊讶这篇文章没有涉及不同数量的键的 SortedSet 与 HashSet 的内存使用情况。 @Svisstack 从技术上讲,在哈希集中查找是 O(m),其中 m 是哈希函数的平均哈希冲突率。对于一个完全均匀分布的散列函数,这导致查找为 O(1),对于一个总是碰撞的完全错误的散列函数,这将使查找 O(n),其中 n 是集合的大小。您通常只使用具有良好散列函数的类型的散列集,在大多数实际情况下使其成为 O(1)。是什么让你认为它是 O(log(n))? @Svisstack “你不能假设你的散列函数很好”好吧,你可以。大多数人都这样做。如果你不能正确地散列对象你不应该在基于散列的集合中使用它。有些人会在这个符号上加上一个星号,表示它假设一个好的散列,因为你是对的,它在陈述 O(1) 时做出的假设,即使它是一个有效的假设。 “如果你有碰撞,那么你基本上有 Set” 不,那么你有一个列表。通过它进行搜索需要线性搜索,即 O(m),其中 m 是该哈希桶中的项目数。 @Svisstack 很少 很少有数据结构被设计成在项目数超过 int.MaxValue 时能够正常工作,甚至根本不能正常工作。说如果你有比 int.MaxValue 更多的项目操作不再是 O(1) 是非常没有意义的,因为它从一开始就不是受支持的用例,所以它不是一个有用的考虑点。诸如HashSetListDictionary 之类的东西实际上会崩溃,因为数组不允许那么大,而且它们都由一个大数组支持。 @Svisstack "如果我们想在这个世界上那样,将一个项目放入哈希集中,您将拥有相同的包含时间,就像您将最大随机项目放入同一个哈希集中一样。"是的。 这是绝对正确的,假设该项目具有明确定义的散列函数。这就是哈希集如此有用的原因。检查一个项目是否在集合中需要大约相同的时间,而不管集合中有多少项目。它对您何时可以执行此操作有限制(该项目需要有效地进行哈希处理),但这是通常可以实现的条件。【参考方案3】:

如果您不需要排序,则不应使用进行排序的类,因为这意味着您的应用程序将完成比它需要的更多的工作。 (换句话说,这将使您的应用程序更快)。

【讨论】:

更重要的是,算法会跑得更快。散列是 O(1),而排序集可能使用二叉搜索树,在平均情况下是 O(log n) - 性能要差得多。 Set 用于唯一项目,List 可能包含重复条目。 msdn.microsoft.com/en-us/library/bb359438.aspx 用于 HashSet 文档。它说:集合是一个集合,它包含没有重复元素,并且其元素没有特定的顺序。 它是算法计算强度的粗略指标。见en.wikipedia.org/wiki/Big_O_notation @Novice:通俗地说,在O(1) 中运行的算法意味着无论输入的大小如何,它都在相同的时间内运行。否则,时间取决于输入n 的大小,并表示为n 的函数。例如,线性的:O(n),二次的:O(n^2) 等。big-O wiki 页面可能很难阅读,this 总结得很好。 @BlueMonkMN,与您的旧错误版本相比,在线版本 (MSDN) 显然已修复。 SortedSet&lt;&gt; 在 O(log n) 时间内执行查找,HashSet&lt;&gt; 在 O(1) 时间内执行查找,List&lt;&gt; 在 O(n) 时间内执行。

以上是关于SortedSet<T> 与 HashSet<T>的主要内容,如果未能解决你的问题,请参考以下文章

如何为用户定义的类型专门化 std::hash<T>?

bzoj4917Hash Killer IV 乱搞

BZOJ4917Hash Killer IV 乱搞

Redis 数据结构

春眠不觉晓,Redis数据类型知多少?String,List,Set,SortedSet,Hash,Bitmap,HyperLogLogs

B.4 集