set不包含重复的元素,这也是使用set的一个主要原因,set有三个常用的实现,分别是HashSet、TreeSet和LinkedList。总之,对于这三个实现,何时使用是一个重要的问题,如果你需要一个快速的set,你应该使用hashSet;如果需要使用一个排序好的set,那么应该是TreeSet;如果需要一个保持插入顺序的set,那么LinkedHashSet是一个不错的选择。

Set接口


set接口扩展自collection接口,在set中,是不允许有重复元素存在的,在set中的元素必须是独一无二的,你可以随意的将任一元素添加到set中,set会自动将重复的元素移除。





java LinkedHashSet 和set的区别 linkedhashset和treeset_JAVA基础


HashSet、TreeSet和LinkedHashSet比较


HashSet是用hash table 实现的,它其中的元素是无序的,add、remove和contains方法的时间复杂度都是O(1)。


TreeSet是使用tree 结构实现的(算法书中的红黑树)。它其中的元素是有序的,但是add、remove和contains方法的时间复杂度是 O(log (n)),TreeSet提供了frist()、last()、headset()和tailset()等方法来处理这个有序的set。


LinkedHashSet是介于TreeSet和HashSet之间的,它利用hash table 实现的,同时使用了Link  List,所以它提供了插入的顺序,基本方法的时间复杂度是O(1)。


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. " ");  
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. new TreeSet<Dog>();  
      7. new Dog(2));  
      8. new Dog(1));  
      9. new Dog(3));  
      10.    
      11.         Iterator<Dog> iterator = dset.iterator();  
      12.    
      13. while (iterator.hasNext()) {  
      14. " ");  
      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. 22)


      因为TreeSet是排序的,这个Dog对象需要实现java.lang.Comparable`s 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


      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. " ");  
      10. }


      输出结果:


      [java]  view plain  copy



      1. 5 3 2 1 4


      注意:这个顺序是不确定的。


      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. " ");  
        10. }


        输出的结果就是它插入的顺序:


        [java]  view plain  copy


          1. 2 1 3 5 4


          性能测试


          下边的三个类的方法测试都是基于add()方法的:



          [java]  view plain  copy


          1. public static void main(String[] args) {  
          2.    
          3. new Random();  
          4.    
          5. new HashSet<Dog>();  
          6. new TreeSet<Dog>();  
          7. 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. new Dog(x));  
          15.     }  
          16. // end time  
          17. long endTime = System.nanoTime();  
          18. long duration = endTime - startTime;  
          19. "HashSet: " + duration);  
          20.    
          21. // start time  
          22.     startTime = System.nanoTime();  
          23. for (int i = 0; i < 1000; i++) {  
          24. int x = r.nextInt(1000 - 10) + 10;  
          25. new Dog(x));  
          26.     }  
          27. // end time  
          28.     endTime = System.nanoTime();  
          29.     duration = endTime - startTime;  
          30. "TreeSet: " + duration);  
          31.    
          32. // start time  
          33.     startTime = System.nanoTime();  
          34. for (int i = 0; i < 1000; i++) {  
          35. int x = r.nextInt(1000 - 10) + 10;  
          36. new Dog(x));  
          37.     }  
          38. // end time  
          39.     endTime = System.nanoTime();  
          40.     duration = endTime - startTime;  
          41. "LinkedHashSet: " + duration);  
          42.    
          43. }


          从这个输出的结果来看,HashSet是最快的:


          [java]  view plain  copy


          1. HashSet: 2244768  
          2. TreeSet: 3549314  
          3. LinkedHashSet: 2263320


          这个测试并不精准,但是可以看出因为TreeSet是排序的所以它是最慢的。



          java LinkedHashSet 和set的区别 linkedhashset和treeset_JAVA基础_02




          下边是原文的一些评论,这里一并翻译出来:



          如果你想访问set中的任意元素,无疑TreeSet是最快的,因为TreeSet已经排序好了无需再遍历整个数组或者是链表。所有的linked实现的结构在访问任意元素傻上都很慢,但是在移动和替换元素上是很快的。


          HashSet是大多内存要求的,如果你有大量的RAM,并且在你的set中的读写的性能相对合理的话,那么HashSet是个不错的选择。