我一直很喜欢树,O(n*log(n))和它们的整洁。然而,我所认识的每个软件工程师都尖锐地问过我为什么要使用TreeSet。从CS的背景来看,我不认为你使用什么很重要,我也不关心在哈希函数和桶(在Java的情况下)上搞得一团糟。
在哪些情况下,我应该在树集上使用HashSet ?
我一直很喜欢树,O(n*log(n))和它们的整洁。然而,我所认识的每个软件工程师都尖锐地问过我为什么要使用TreeSet。从CS的背景来看,我不认为你使用什么很重要,我也不关心在哈希函数和桶(在Java的情况下)上搞得一团糟。
在哪些情况下,我应该在树集上使用HashSet ?
当前回答
大多数人使用HashSet的原因是操作(平均)是O(1)而不是O(log n)。如果集合包含标准项,你就不会像以前那样“乱搞哈希函数”。如果集合包含自定义类,则必须实现hashCode才能使用HashSet(尽管Effective Java演示了如何使用),但如果使用TreeSet,则必须使其具有可比性或提供比较器。如果类没有特定的顺序,这可能是一个问题。
我有时会使用TreeSet(或者实际上是TreeMap)用于非常小的集合/映射(< 10项),尽管我没有检查这样做是否有任何真正的好处。对于大型机组,差异可能相当大。
现在,如果您需要排序,那么TreeSet是合适的,尽管即使如此,如果更新频繁,对排序结果的需求并不频繁,有时将内容复制到列表或数组中并对它们排序会更快。
其他回答
明明可以吃橘子,为什么要吃苹果?
Seriously guys and gals - if your collection is large, read and written to gazillions of times, and you're paying for CPU cycles, then the choice of the collection is relevant ONLY if you NEED it to perform better. However, in most cases, this doesn't really matter - a few milliseconds here and there go unnoticed in human terms. If it really mattered that much, why aren't you writing code in assembler or C? [cue another discussion]. So the point is if you're happy using whatever collection you chose, and it solves your problem [even if it's not specifically the best type of collection for the task] knock yourself out. The software is malleable. Optimise your code where necessary. Uncle Bob says Premature Optimisation is the root of all evil. Uncle Bob says so
即使在11年后,也没有人想到提到一个非常重要的区别。
你认为如果HashSet等于TreeSet,那么反过来也成立吗?看看这段代码:
TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.add("a");
hashSet.add("A");
System.out.println(hashSet.equals(treeSet));
System.out.println(treeSet.equals(hashSet));
尝试猜测输出,然后徘徊在代码片段下面,看看真正的输出是什么。准备好了吗?给你:
假 真正的
没错,如果比较器与等号不一致,它们就不具有等价关系。原因是TreeSet使用比较器来确定等价性,而HashSet使用等号。在内部,它们使用HashMap和TreeMap,所以你应该预料到上述map也会有这种行为。
最初的回答
1.HashSet允许空对象。
2.树集不允许空对象。如果你试图添加空值,它将抛出一个NullPointerException。
3.HashSet比TreeSet快得多。
e.g.
TreeSet<String> ts = new TreeSet<String>();
ts.add(null); // throws NullPointerException
HashSet<String> hs = new HashSet<String>();
hs.add(null); // runs fine
HashSet是O(1)来访问元素,所以这当然很重要。但是保持集合中对象的顺序是不可能的。
如果维护顺序(根据值而不是插入顺序)对您很重要,TreeSet是有用的。但是,正如您所注意到的,您正在以顺序换取访问元素的更慢时间:基本操作为O(log n)。
来自TreeSet的javadocs:
该实现为基本操作(添加、删除和包含)提供了log(n)的时间成本。
TreeSet是两个排序集合之一(另一个是 TreeMap)。它使用红黑树结构(但你知道),并保证 元素会按照自然的顺序,按升序排列。可选地, 您可以使用构造函数构造TreeSet,该构造函数允许您为集合提供您的 自己制定顺序规则(而不是依赖于定义的顺序) 通过使用Comparable或Comparator)
LinkedHashSet是HashSet的有序版本 在所有元素之间维护一个双链接列表。使用这个类而不是HashSet 当你关心迭代顺序时。迭代HashSet时 顺序是不可预测的,而LinkedHashSet允许您迭代元素 按照它们被插入的顺序