Hashset vs Treeset
我一直很喜欢树木,那些很好的
在哪种情况下,我应该在
HashSet比TreeSet快得多(对于大多数操作,例如add,remove和contains,常量时间与日志时间相比),但不提供像TreeSet这样的排序保证。
HashSet的
- 该类为基本操作提供恒定的时间性能(添加,删除,包含和大小)。
- 它不能保证元素的顺序会随着时间的推移而保持不变
-
迭代性能取决于HashSet的初始容量和加载因子。
- 接受默认加载因子是非常安全的,但您可能希望指定的初始容量大约是您希望该组增长的大小的两倍。
TreeSet中
- 保证基本操作的log(n)时间成本(添加,删除和包含)
-
保证set的元素将被排序(升序,自然或您通过其构造函数指定的那个)(实现
SortedSet ) - 不提供迭代性能的任何调整参数
-
提供一些方便的方法来处理有序集合,如
first() ,last() ,headSet() 和tailSet() 等
重点:
- 两者都保证元素的无重复收集
- 通常,将元素添加到HashSet然后将集合转换为TreeSet以进行无重复的排序遍历通常会更快。
- 这些实现都不是同步的。也就是说,如果多个线程同时访问一个集合,并且至少有一个线程修改了该集合,则必须在外部进行同步。
-
LinkedHashSet在某种意义上介于
HashSet 和TreeSet 之间。实现为具有贯穿其的链表的哈希表,但是,它提供了插入顺序迭代,这与TreeSet保证的排序遍历不同。
因此,使用选择完全取决于您的需求,但我觉得即使您需要有序集合,您仍然应该更喜欢HashSet来创建Set,然后将其转换为TreeSet。
-
例如
SortedSet s = new TreeSet (hashSet);
尚未提到的
这与
当从硬盘驱动器读取的延迟成本是从缓存或RAM读取的成本的数千倍,并且当数据确实是通过本地访问时,
如果维护订单(在值而非插入订单方面)对您很重要,则
来自
This implementation provides guaranteed log(n) time cost for the basic operations (
add ,remove andcontains ).
基于@shevchyk地图上可爱的视觉答案,这是我的看法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ╔══════════════╦═════════════════════╦═══════════════════╦═════════════════════╗ ║ Property ║ HashSet ║ TreeSet ║ LinkedHashSet ║ ╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣ ║ ║ no guarantee order ║ sorted according ║ ║ ║ Order ║ will remain constant║ to the natural ║ insertion-order ║ ║ ║ over time ║ ordering ║ ║ ╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣ ║ Add/remove ║ O(1) ║ O(log(n)) ║ O(1) ║ ╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣ ║ ║ ║ NavigableSet ║ ║ ║ Interfaces ║ Set ║ Set ║ Set ║ ║ ║ ║ SortedSet ║ ║ ╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣ ║ ║ ║ not allowed ║ ║ ║ Null values ║ allowed ║ 1st element only ║ allowed ║ ║ ║ ║ in Java 7 ║ ║ ╠══════════════╬═════════════════════╩═══════════════════╩═════════════════════╣ ║ ║ Fail-fast behavior of an iterator cannot be guaranteed ║ ║ Fail-fast ║ impossible to make any hard guarantees in the presence of ║ ║ behavior ║ unsynchronized concurrent modification ║ ╠══════════════╬═══════════════════════════════════════════════════════════════╣ ║ Is ║ ║ ║ synchronized ║ implementation is not synchronized ║ ╚══════════════╩═══════════════════════════════════════════════════════════════╝ |
1.HashSet允许空对象。
2.TreeSet不允许null对象。如果您尝试添加null值,它将抛出NullPointerException。
3.HashSet比TreeSet快得多。
例如
1 2 3 4 5 | TreeSet<String> ts = new TreeSet<String>(); ts.add(null); // throws NullPointerException HashSet<String> hs = new HashSet<String>(); hs.add(null); // runs fine |
大多数使用
我有时会使用
现在,如果你需要排序,那么
如果您没有插入足够的元素来导致频繁的重新散列(或者碰撞,如果您的HashSet无法调整大小),HashSet肯定会为您提供持续时间访问的好处。但是在具有大量增长或缩减的集合上,使用Treesets实际上可能会获得更好的性能,具体取决于实现。
如果记忆为我服务,摊销时间可以接近O(1),功能红黑树。 Okasaki的书会有比我能说的更好的解释。 (或者看他的出版物清单)
当然,HashSet实现要快得多 - 开销较少,因为没有排序。 http://java.sun.com/docs/books/tutorial/collections/implementations/set.html提供了对Java中各种Set实现的良好分析。
那里的讨论还指出了树与哈希问题的一个有趣的"中间立场"方法。 Java提供了一个LinkedHashSet,它是一个HashSet,其中有一个"面向插入"的链表,也就是说,链表中的最后一个元素也是最近插入Hash的。这使您可以避免无序散列的不正常,而不会导致TreeSet的成本增加。
TreeSet是两个排序集合之一(另一个是
TreeMap的)。它使用红黑树结构(但你知道),并保证
根据自然顺序,元素将按升序排列。 (可选)
你可以用一个构造函数构造一个TreeSet,让你给你的集合
对订单应该是什么的自己的规则(而不是依赖于定义的顺序
通过元素'类)使用Comparable或Comparator
和LinkedHashSet是HashSet的有序版本
在所有元素中维护一个双向链表。使用此类而不是HashSet
当你关心迭代顺序时。当你遍历一个HashSet时
order是不可预测的,而LinkedHashSet允许你遍历元素
按插入顺序排列
为什么在你可以吃橘子的时候有苹果?
严肃的家伙和女孩 - 如果你的收藏很大,读取和写入数以千计的时间,并且你支付CPU周期,那么只有你需要它才能更好地选择收集。然而,在大多数情况下,这并不重要 - 在这里和那里几毫秒都没有人类注意到。如果它真的很重要,为什么不用汇编程序或C编写代码? [提出另一个讨论]。所以关键是如果你很高兴使用你选择的任何系列,并且它解决了你的问题[即使它不是特别是任务的最佳类型的集合]自己敲门。该软件具有可塑性。必要时优化您的代码。鲍勃叔叔说过早优化是万恶之源。鲍勃叔叔这么说
基于技术考虑,特别是围绕性能,已经给出了很多答案。
据我说,
但我宁愿说首先应该从概念上考虑选择。
如果对于需要操作的对象,自然顺序没有意义,那么不要使用
它是一个有序集,因为它实现了
请注意
此链接可能是有关此问题的良好信息来源。
消息编辑(完全重写)当订单无关紧要时,就是这样。两者都应该给出Log(n) - 看看它们是否比另一个快5%以上是有用的。 HashSet可以在循环中给出O(1)测试,以揭示它是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import java.util.HashSet; import java.util.Set; import java.util.TreeSet; public class HashTreeSetCompare { //It is generally faster to add elements to the HashSet and then //convert the collection to a TreeSet for a duplicate-free sorted //Traversal. //really? O(Hash + tree set) > O(tree set) ?? Really???? Why? public static void main(String args[]) { int size = 80000; useHashThenTreeSet(size); useTreeSetOnly(size); } private static void useTreeSetOnly(int size) { System.out.println("useTreeSetOnly:"); long start = System.currentTimeMillis(); Set<String> sortedSet = new TreeSet<String>(); for (int i = 0; i < size; i++) { sortedSet.add(i +""); } //System.out.println(sortedSet); long end = System.currentTimeMillis(); System.out.println("useTreeSetOnly:" + (end - start)); } private static void useHashThenTreeSet(int size) { System.out.println("useHashThenTreeSet:"); long start = System.currentTimeMillis(); Set<String> set = new HashSet<String>(); for (int i = 0; i < size; i++) { set.add(i +""); } Set<String> sortedSet = new TreeSet<String>(set); //System.out.println(sortedSet); long end = System.currentTimeMillis(); System.out.println("useHashThenTreeSet:" + (end - start)); } } |