分享

HashSet、TreeSet和LinkedHashSet的区别

 未名馆heuwst 2018-09-15

 Set集合不包含重复的元素,这是使用Set的主要原因。有三种常见的Set实现——HashSet, TreeSet和LinkedHashSet。什么时候使用它们,使用哪个是个重要的问题。总体而言,如果你需要一个访问快速的Set,你应该使用HashSet;当你需要一个排序的Set,你应该使用TreeSet;当你需要记录下插入时的顺序时,你应该使用LinedHashSet。

1. Set接口

Set接口继承了Collection接口。Set集合中不能包含重复的元素,每个元素必须是唯一的。你只需将元素加入set中,重复的元素会自动移除。

2. HashSet vs. TreeSet vs. LinkedHashSet

HashSet是采用hash表来实现的。其中的元素没有按顺序排列,add()、remove()以及contains()等方法都是复杂度为O(1)的方法。

TreeSet是采用树结构实现(红黑树算法)。元素是按顺序进行排列,但是add()、remove()以及contains()等方法都是复杂度为O(log (n))的方法。它还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet()等等。

LinkedHashSet介于HashSet和TreeSet之间。它也是一个hash表,但是同时维护了一个双链表来记录插入的顺序。基本方法的复杂度为O(1)。

3. TreeSet的例子

  1. TreeSet tree = new TreeSet();
  2. tree.add(12);
  3. tree.add(63);
  4. tree.add(34);
  5. tree.add(45);
  6. Iterator iterator = tree.iterator();
  7. System.out.print("Tree set data: ");
  8. while (iterator.hasNext()) {
  9. System.out.print(iterator.next() + " ");
  10. }

输出如下:Tree set data: 12 34 45 63

现在让我们定义一个Dog类:

  1. class Dog {
  2. int size;
  3. public Dog(int s) {
  4. size = s;
  5. }
  6. public String toString() {
  7. return size + "";
  8. }
  9. }

我们将“dog”添加到TreeSet中:
  1. import java.util.Iterator;
  2. import java.util.TreeSet;
  3. public class TestTreeSet {
  4. public static void main(String[] args) {
  5. TreeSet dset = new TreeSet();
  6. dset.add(new Dog(2));
  7. dset.add(new Dog(1));
  8. dset.add(new Dog(3));
  9. Iterator iterator = dset.iterator();
  10. while (iterator.hasNext()) {
  11. System.out.print(iterator.next() + " ");
  12. }
  13. }
  14. }

编译正常,但是运行时出错:
  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()方法才行:

  1. class Dog implements Comparable{
  2. int size;
  3. public Dog(int s) {
  4. size = s;
  5. }
  6. public String toString() {
  7. return size + "";
  8. }
  9. @Override
  10. public int compareTo(Dog o) {
  11. return size - o.size;
  12. }
  13. }

输出: 1 2 3

4. HashSet的例子

  1. HashSet dset = new HashSet();
  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 iterator = dset.iterator();
  8. while (iterator.hasNext()) {
  9. System.out.print(iterator.next() + " ");
  10. }

输出:5 3 2 1 4
注意输出顺序是不确定的。

5. LinkedHashSet的例子

  1. LinkedHashSet dset = new LinkedHashSet();
  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 iterator = dset.iterator();
  8. while (iterator.hasNext()) {
  9. System.out.print(iterator.next() + " ");
  10. }

输出的顺序时确定的,就是插入的顺序。

2 1 3 5 4

6. 性能测试

下面的代码测试了以上三个类的add()方法的性能。

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

从输出看来,HashSet是最快的:

HashSet: 2244768
TreeSet: 3549314
LinkedHashSet: 2263320

*这个测试并不是非常精确,但足以反映基本的情况。

原文链接: Programcreek 翻译: ImportNew.com 唐小娟
译文链接: http://www./8773.html
转载请保留原文出处、译者和译文链接。]




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多