HashSet 与 TreeSet

17 Mar 2025 | 4 分钟阅读

在 Java 中,整个集合框架都建立在一组标准接口之上。提供了这些接口的几个标准实现(如 LinkedList、HashSet 和 TreeSet),我们可以直接使用。在本节中,我们将首先通过适当的示例讨论 **HashSet** 和 **TreeSet**。此外,还将讨论 **HashSet 和 TreeSet 之间的区别和相似之处**。

HashSet vs TreeSet

下图显示了 集合框架 中 HashSet 和 TreeSet 的层次结构。

HashSet vs TreeSet

HashSet

HashSet 是 Java 集合框架的通用类。它扩展了 AbstractSet 并实现了 Set 接口。它创建使用 **哈希表** 进行存储的集合。哈希表通过使用 **哈希** 机制来存储信息。

哈希使用信息内容来确定一个称为 **哈希码 (hash code)** 的唯一值。它用作存储与键相关联数据的索引。键到哈希码的转换是自动执行的。哈希的好处在于,即使对于大型集合,它也能使 add、contain、remove 和 size 操作的执行时间保持恒定。其操作搜索、插入和删除的时间复杂度为 **O(1)**。

HashSet 类不提供任何额外的显式方法。它使用其超类和接口的方法。需要注意的是,它不保证元素的顺序。

让我们通过一个 Java 程序来理解 HashSet。

HashSetExample.java

输出

HashSet vs TreeSet

在上面的输出中,我们观察到两点。第一点是元素没有按自然顺序排序,第二点是重复元素 **Chicago** 已被删除。

TreeSet

TreeSet 是 Java 集合框架的一个类,它扩展了 AbstractSet 并实现了 Set、NavigableSet 和 SortedSet 接口。它创建使用树进行存储的集合。

TreeSet 是 Java 集合框架的通用类。它实现了 Set 接口。它在内部使用 **TreeMap** 来存储 TreeSet 元素。默认情况下,它按自然顺序(升序)对元素进行排序。排序顺序取决于我们提供的 Comparator。如果没有提供 Comparator,它会按自然顺序对元素进行排序。

与 HashSet 相比,它的性能较慢,因为 TreeSet 在每次插入和删除操作后都会对元素进行排序。

它使用 **compareTo()** 或 **compare()** 方法来比较元素。需要注意的是,TreeSet 的实现不是同步的。这意味着它不是线程安全的。如果多个线程并发访问 TreeSet 并且一个线程尝试修改 TreeSet,则必须在外部进行同步。

它不允许存储 null 元素。如果我们尝试插入 null 元素,它会抛出 **NullPointerException**。它比 HashSet 需要更多的内存,因为它还维护用于排序元素的比较器。

其操作搜索、插入和删除的时间复杂度为 **O(log n)**,这比 HashSet 高得多。它使用 **自平衡二叉搜索树 (Red-Black Tree)** 来实现 TreeSet。

让我们通过一个 Java 程序来理解 TreeSet。

TreeSetExample.java

输出

HashSet vs TreeSet

在上面的输出中,我们观察到两点。第一点是元素按自然顺序排序,第二点是重复元素 **Asus** 已被删除。

我们已经深入理解了 HashSet 和 TreeSet。现在,我们将讨论它们之间的区别。

HashSet 与 TreeSet 之间的区别

参数HashSetTreeSet
排序它不保证对数据进行排序。它保证对数据进行排序。排序取决于提供的 Comparator。
Null 对象在 HashSet 中,**只能有一个元素** 可以为 null。它不允许 null 元素。
比较它使用 **hashCode()** 或 **equals()** 方法进行比较。它使用 **compare()** 或 **compareTo()** 方法进行比较。
性能它**比** TreeSet **快**。与 HashSet 相比,它**较慢**。
实施内部使用 **HashMap** 来存储其元素。内部使用 **TreeMap** 来存储其元素。
数据结构HashSet 由哈希表支持。TreeSet 由红黑树支持。
存储的值它只允许**异构**值。它只允许**同构**值。

HashSet 和 TreeSet 之间存在一些相似之处

  • 这两个类都实现了 Set 接口。
  • 它们不允许重复值。
  • HashSet 和 TreeSet 都不是线程安全的。
  • 它们不同步,但如果我们想使它们同步,可以使用 Collections.synchronizedSet() 方法。
  • 这两个类中使用的迭代器本质上是快速失败的。如果我们尝试修改一个迭代器,一旦它被创建,它就会抛出 **ConcurrentModificationException**。
  • 它们都使用浅拷贝技术,通过使用 clone() 方法来创建对象的克隆。

哪个更好用?

如果你希望元素按排序顺序排列,则使用 TreeSet,否则使用 HashSet,因为它的性能比 TreeSet 快。


下一个主题null