原文链接:HashSet vs. TreeSet vs. LinkedHashSet

在一个set中,是没有重复元素的。这也是使用set最主要的原因之一。Set的实现类有三个:HashSet,TreeSet,LinkedHashSet。什么时候使用哪一种实现类,是一个非常的问题。简单地说,如果我们想要一个快速的set,那么我们应该使用HashSet;如果我们需要一个已经排好序的set,那么TreeSet应该被使用;如果我们想一个可以根据插入顺序来读取的set,那么LinkedHashSet应该被使用。

1.Set接口

Set接口继承了Collection接口。在set中,不允许有重复的元素。每一个元素在set中都是唯一的。我们可以简单地添加元素至一个set中,最后,我们会得到一个自动删除重复元素的set。

HashSet、TreeSet、LinkedHashSet的区别

2.HashSet vs. TreeSet vs. LinkedHashSet 

HashSet 是使用一个哈希表实现的。元素是无序的。add、remove 及contains 方法的时间复杂度是一个常量 O(1)。

TreeSet 是使用一个树结构(算法书籍上的红黑树)来实现的。元素在set中被排好序,但是add、remove及contains方法的时间复杂度为O(log(n))。它提供了几个方法用来处理有序的set,比如first(),last(),headSet(),tailSet()等等。

LinkedHashSet介于HashSet与TreeSet之间。它由一个执行hash表的链表实现,因此,它提供顺序插入。基本方法的时间复杂度为O(1)。

3.TreeSet 例子

[java] view plain copy
  1. TreeSet<Integer> tree = new TreeSet<Integer>();  
  2. tree.add(12);  
  3. tree.add(63);  
  4. tree.add(34);  
  5. tree.add(45);  
  6.    
  7. Iterator<Integer> iterator = tree.iterator();  
  8. System.out.print("Tree set data: ");  
  9. while (iterator.hasNext()) {  
  10.     System.out.print(iterator.next() + " ");  
  11. }  

如下所示,输出是已排好序的:

[java] view plain copy
  1. Tree set data: 12 34 45 63  
现在,我们来定义一个如下的Dog类:

[java] view plain copy
  1. class Dog {  
  2.     int size;  
  3.    
  4.     public Dog(int s) {  
  5.         size = s;  
  6.     }  
  7.    
  8.     public String toString() {  
  9.         return size + "";  
  10.     }  
  11. }  

我们添加一些dog至TreeSet中,就像下面这样:

[java] view plain copy
  1. import java.util.Iterator;  
  2. import java.util.TreeSet;  
  3.    
  4. public class TestTreeSet {  
  5.     public static void main(String[] args) {  
  6.         TreeSet<Dog> dset = new TreeSet<Dog>();  
  7.         dset.add(new Dog(2));  
  8.         dset.add(new Dog(1));  
  9.         dset.add(new Dog(3));  
  10.    
  11.         Iterator<Dog> iterator = dset.iterator();  
  12.    
  13.         while (iterator.hasNext()) {  
  14.             System.out.print(iterator.next() + " ");  
  15.         }  
  16.     }  
  17. }  

编译没问题,但是出现运行时错误:

[java] view plain copy
  1. Exception in thread “main” java.lang.ClassCastException: collection.Dog cannot be cast to java.lang.Comparable  
  2. at java.util.TreeMap.put(Unknown Source)  
  3. at java.util.TreeSet.add(Unknown Source)  
  4. at collection.TestTreeSet.main(TestTreeSet.java:22)  

因为TreeSet是有序的,Dog对象需要实现java.lang.Comparable的compareTo()方法(应该是先实现Comparable再重写compareTo()方法),就像下面这样:

[java] view plain copy
  1. class Dog implements Comparable<Dog>{  
  2.     int size;  
  3.    
  4.     public Dog(int s) {  
  5.         size = s;  
  6.     }  
  7.    
  8.     public String toString() {  
  9.         return size + "";  
  10.     }  
  11.    
  12.     @Override  
  13.     public int compareTo(Dog o) {  
  14.             return size - o.size;  
  15.     }  
  16. }  

输出:

[java] view plain copy
  1. 1 2 3  


4.HashSet 例子

[java] view plain copy
  1. HashSet<Dog> dset = new HashSet<Dog>();  
  2. dset.add(new Dog(2));  
  3. dset.add(new Dog(1));  
  4. dset.add(new Dog(3));  
  5. dset.add(new Dog(5));  
  6. dset.add(new Dog(4));  
  7. Iterator<Dog> iterator = dset.iterator();  
  8. while (iterator.hasNext()) {  
  9.     System.out.print(iterator.next() + " ");  
  10. }  
输出:

[java] view plain copy
  1. 5 3 2 1 4  


注意:顺序是不确定的。

5.LinkedHashSet 例子

[java] view plain copy
  1. LinkedHashSet<Dog> dset = new LinkedHashSet<Dog>();  
  2. dset.add(new Dog(2));  
  3. dset.add(new Dog(1));  
  4. dset.add(new Dog(3));  
  5. dset.add(new Dog(5));  
  6. dset.add(new Dog(4));  
  7. Iterator<Dog> iterator = dset.iterator();  
  8. while (iterator.hasNext()) {  
  9.     System.out.print(iterator.next() + " ");  
  10. }  

输出顺序是确定的,并且是按插入时的顺序。

[java] view plain copy
  1. 2 1 3 5 4  

6.性能测试

以下方法是测试三种类的add()方法的性能。

[java] view plain copy
  1. public static void main(String[] args) {  
  2.    
  3.     Random r = new Random();  
  4.    
  5.     HashSet<Dog> hashSet = new HashSet<Dog>();  
  6.     TreeSet<Dog> treeSet = new TreeSet<Dog>();  
  7.     LinkedHashSet<Dog> linkedSet = new LinkedHashSet<Dog>();  
  8.    
  9.     // start time  
  10.     long startTime = System.nanoTime();  
  11.    
  12.     for (int i = 0; i < 1000; i++) {  
  13.         int x = r.nextInt(1000 - 10) + 10;  
  14.         hashSet.add(new Dog(x));  
  15.     }  
  16.     // end time  
  17.     long endTime = System.nanoTime();  
  18.     long duration = endTime - startTime;  
  19.     System.out.println("HashSet: " + duration);  
  20.    
  21.    
  22.    
  23.    
  24.     // start time  
  25.     startTime = System.nanoTime();  
  26.    
  27.     for (int i = 0; i < 1000; i++) {  
  28.         int x = r.nextInt(1000 - 10) + 10;  
  29.         treeSet.add(new Dog(x));  
  30.     }  
  31.     // end time  
  32.     endTime = System.nanoTime();  
  33.     duration = endTime - startTime;  
  34.     System.out.println("TreeSet: " + duration);  
  35.    
  36.    
  37.    
  38.    
  39.     // start time  
  40.     startTime = System.nanoTime();  
  41.    
  42.     for (int i = 0; i < 1000; i++) {  
  43.         int x = r.nextInt(1000 - 10) + 10;  
  44.         linkedSet.add(new Dog(x));  
  45.     }  
  46.     // end time  
  47.     endTime = System.nanoTime();  
  48.     duration = endTime - startTime;  
  49.     System.out.println("LinkedHashSet: " + duration);  
  50.    
  51. }  

从下面的输出,我们可以清楚地看到HashSet是最快的。

[java] view plain copy
  1. HashSet: 2244768  
  2. TreeSet: 3549314  
  3. LinkedHashSet: 2263320  

相关文章: