当前位置:   article > 正文

TreeSet集合的使用_treeset的原理是什么?使用需要注意什么?

treeset的原理是什么?使用需要注意什么?

一、TreeSet的原理

      TreeSet会对集合里的元素按照指定的顺序进行排序,它的底层数据结构依据的是红-黑二叉树

    1.1什么是红-黑二叉树?

             就是二叉树的每个结点的左右孩子结点的值具有一定规律,即“左小右大”

    1.2根据什么确定集合里元素的唯一性?

             因为TreeSet会对集合里的元素进行指定顺序的排序,所以,排序需要依据元素自身具备的比较性,如果元素自身不具备比较性,也就是说我们自己创建的实体类并没有具备比较性,那么就会出现ClassCastException异常

可以看到,出现此异常的原因就是,自己创建的Student类没有复写Comparable接口的compareTo方法,当集合添加该元素时,集合并不知道排序的规则,自而会报异常。

            所以,我们需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存储。

二、TreeSet的使用

2.1创建实体类Student(实现Comparable接口复写compareTo方法)

     细节:

        在进行比较时,如何判断是同一个元素?比如,学生的学号、姓名和年龄都一样,就视为同一个人,在判断时,需要分清主要条件和次要条件,当主要条件相同时,再判断次要条件,可根据次要条件进行排序

  1. public class Student implements Comparable{
  2. private String stuClass; //班级
  3. private String stuName; //姓名
  4. private Integer stuAge; //年龄
  5. public Student() {
  6. }
  7. public Student(String stuClass, String stuName, Integer stuAge) {
  8. this.stuClass = stuClass;
  9. this.stuName = stuName;
  10. this.stuAge = stuAge;
  11. }
  12. public String getStuClass() {
  13. return stuClass;
  14. }
  15. public void setStuClass(String stuClass) {
  16. this.stuClass = stuClass;
  17. }
  18. public String getStuName() {
  19. return stuName;
  20. }
  21. public void setStuName(String stuName) {
  22. this.stuName = stuName;
  23. }
  24. public Integer getStuAge() {
  25. return stuAge;
  26. }
  27. public void setStuAge(Integer stuAge) {
  28. this.stuAge = stuAge;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Student{" +
  33. "stuClass='" + stuClass + '\'' +
  34. ", stuName='" + stuName + '\'' +
  35. ", stuAge=" + stuAge +
  36. '}';
  37. }
  38. /*
  39. 判断是否为同一个学生,先看是否为同一个班级,再看名字是否相同,最后看年龄是否一样,
  40. 因此,班级为主要条件,姓名、年龄为次要条件
  41. (可能这个例子不太好,主要是为了说明问题)
  42. */
  43. @Override
  44. public int compareTo(Object o) {
  45. Student student = (Student)o;
  46. int num = this.stuClass.compareTo(student.stuClass);
  47. int num1= num == 0 ? this.stuName.compareTo(student.stuName):num;
  48. return num1 ==0 ? this.stuAge.compareTo(student.stuAge):num1;
  49. }
  50. }

2.2存入集合中

  1. public static void main( String[] args )
  2. {
  3. Student stu1 = new Student("IT1903", "IT3", 19);
  4. Student stu2 = new Student("IT1902", "IT2", 19);
  5. Student stu3 = new Student("IT1901", "IT1", 19);
  6. Student stu4 = new Student("IT1902", "IT3", 19);
  7. Student stu5 = new Student("IT1904", "IT1", 20);
  8. Student stu6 = new Student("IT1904", "IT1", 21);
  9. Student stu7 = new Student("IT1904", "IT1", 21);
  10. TreeSet<Student> treeSet = new TreeSet<>();
  11. treeSet.add(stu1);
  12. treeSet.add(stu2);
  13. treeSet.add(stu3);
  14. treeSet.add(stu4);
  15. treeSet.add(stu5);
  16. treeSet.add(stu6);
  17. treeSet.add(stu7);
  18. System.out.println("集合大小:"+treeSet.size());
  19. for(Student student:treeSet) System.out.println(student);
  20. }

2.3结果

2.4分析:

第一步:  Student stu1 = new Student("IT1903", "IT3", 19);

//add(stu1)时,为第一个元素,因此把这个元素作为二叉树的根节点

第二步:   Student stu2 = new Student("IT1902", "IT2", 19);

//add(stu2)时,通过compareTo方法比较,在比较stuClass时,IT1903>IT1902,返回1,待插元素小于已有元素,该元素就作为该stu1结点的左孩子结点

第三步: Student stu3 = new Student("IT1901", "IT1", 19);

//add(stu3)时,和stu1比较,发现小于stu1,接着和stu2比较,发现也小于,于是做stu2的左孩子结点

第四步:Student stu4 = new Student("IT1902", "IT3", 19);

//小于stu1,和stu2中的stuName比较时,大于stu2,做stu2的右孩子结点

第五步:Student stu5 = new Student("IT1904", "IT1", 20);

//大于stu1,做stu1的右孩子结点

第六步:Student stu6 = new Student("IT1904", "IT1", 21);

//大于stu1,大于stu5,做stu5的右孩子结点

第七步:Student stu7 = new Student("IT1904", "IT1", 21);

//大于stu1,大于stu5,和stu6做比较时发现,return 0;该元素重复,不存

2.5存储结构

从运行结果可知,当遍历TreeSet集合时,就是根据此二叉树进行遍历的。

三、TreeSet集合排序有两种方式,Comparable和Comparator

在上边使用了Comparable方式

3.1使用Comparator

3.2创建比较器

自定义一个新类,让该类实现Comparator接口,覆盖compare方法

  1. public class MyComparator implements Comparator {
  2. @Override
  3. public int compare(Object o1, Object o2) {
  4. Student stu1 = (Student)o1;
  5. Student stu2 = (Student)o2;
  6. int num = stu1.getStuClass().compareTo(stu2.getStuClass());
  7. int num1 = num == 0?stu1.getStuName().compareTo(stu2.getStuName()):num;
  8. return num1 == 0?stu1.getStuAge().compareTo(stu2.getStuAge()):num1;
  9. }
  10. }

3.3在实例化TreeSet集合时,将该比较器作为参数传入到集合的构造方法中

  1. public static void main( String[] args )
  2. {
  3. Student stu1 = new Student("IT1903", "IT3", 19);
  4. Student stu2 = new Student("IT1902", "IT2", 19);
  5. Student stu3 = new Student("IT1901", "IT1", 19);
  6. Student stu4 = new Student("IT1902", "IT3", 19);
  7. Student stu5 = new Student("IT1904", "IT1", 20);
  8. Student stu6 = new Student("IT1904", "IT1", 21);
  9. Student stu7 = new Student("IT1904", "IT1", 21);
  10. //TreeSet<Student> treeSet = new TreeSet<>();
  11. TreeSet<Student> treeSet = new TreeSet<>(new MyComparator());
  12. treeSet.add(stu1);
  13. treeSet.add(stu2);
  14. treeSet.add(stu3);
  15. treeSet.add(stu4);
  16. treeSet.add(stu5);
  17. treeSet.add(stu6);
  18. treeSet.add(stu7);
  19. System.out.println("集合大小:"+treeSet.size());
  20. for(Student student:treeSet) System.out.println(student);
  21. }

3.4结果

依然可以实现!!!

四、Comparable和Comparator的区别

   Comparable:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。

   Comparator:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。

第二种方式较为灵活。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/766075
推荐阅读
  

闽ICP备14008679号