JavaSE基础 TreeSet集合(红黑树数据结构)

xiaoxiao2021-02-28  42

本文主要介绍TreeSet集合的基本使用方法

TreeSet之自然排序

返回0代表元素相同, 返回1代表不同

自然排序(元素具备比较性):让元素所属的类实现自然排序接口 Comparable

先看一个简单的例子,TreeSet集合,存入整数,进行排序

1import java.util.TreeSet; 2 3/* 4 * TreeSet:能够对元素按照某种规则进行排序。 5 * 排序有两种方式 6 * A:自然排序 7 * B:比较器排序 8 * 9 * TreeSet集合的特点:排序和唯一 10 * 11 * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。 12 */ 13public class TreeSetDemo { 14 public static void main(String[] args) { 15 // 创建集合对象 16 // 自然顺序进行排序 17 TreeSet<Integer> ts = new TreeSet<Integer>(); 18 19 // 创建元素并添加 20 // 20,18,23,22,17,24,19,18,24 21 ts.add(20); 22 ts.add(18); 23 ts.add(23); 24 ts.add(22); 25 ts.add(17); 26 ts.add(24); 27 ts.add(19); 28 ts.add(18); 29 ts.add(24); 30 31 // 遍历 32 for (Integer i : ts) { 33 System.out.println(i); 34 } 35 } 36}

输出结果:

此处能够对整数进行排序,是因为Integer类实现了Comparable接口. Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

再来看一个例子,在TreeSet中,存入学生对象的数据,并根据学生的年龄从小到大进行排序

创建一个学生类,实现自然排序Comparable接口,传入的泛型为Student 1/* 2 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 3 */ 4public class Student implements Comparable<Student> { 5 private String name; 6 private int age; 7 8 public Student() { 9 super(); 10 } 11 12 public Student(String name, int age) { 13 super(); 14 this.name = name; 15 this.age = age; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 34 @Override 35 public int compareTo(Student s) { 36 // return 0; 37 // return 1; 38 // return -1; 39 40 // 这里返回什么,其实应该根据我的排序规则来做 41 // 按照年龄排序,主要条件 42 int num = this.age - s.age; 43 // 次要条件 44 // 年龄相同的时候,还得去看姓名是否也相同 45 // 如果年龄和姓名都相同,才是同一个元素 46 int num2 = num == 0 ? this.name.compareTo(s.name) : num; 47 return num2; 48 } 49} 编写测试类 1import java.util.TreeSet; 2 3/* 4 * TreeSet存储自定义对象并保证排序和唯一。 5 * 6 * A:你没有告诉我们怎么排序 7 * 自然排序,按照年龄从小到大排序 8 * B:元素什么情况算唯一你也没告诉我 9 * 成员变量值都相同即为同一个元素 10 */ 11public class TreeSetDemo2 { 12 public static void main(String[] args) { 13 // 创建集合对象 14 TreeSet<Student> ts = new TreeSet<Student>(); 15 16 // 创建元素 17 Student s1 = new Student("linqingxia", 27); 18 Student s2 = new Student("zhangguorong", 29); 19 Student s3 = new Student("wanglihong", 23); 20 Student s4 = new Student("linqingxia", 27); 21 Student s5 = new Student("liushishi", 22); 22 Student s6 = new Student("wuqilong", 40); 23 Student s7 = new Student("fengqingy", 22); 24 25 // 添加元素 26 ts.add(s1); 27 ts.add(s2); 28 ts.add(s3); 29 ts.add(s4); 30 ts.add(s5); 31 ts.add(s6); 32 ts.add(s7); 33 34 // 遍历 35 for (Student s : ts) { 36 System.out.println(s.getName() + "---" + s.getAge()); 37 } 38 } 39}

运行结果:

可以看到,成功将学生的信息按照年龄从小到大输出了,并把重复的学生信息去除了

再更改需求添加学生数据,并根据学生的姓名长度,从小到大排序

创建一个学生类,实现自然排序Comparable接口,传入的泛型为Student,重写compareTo方法 1public class Student implements Comparable<Student> { 2 private String name; 3 private int age; 4 5 public Student() { 6 super(); 7 } 8 9 public Student(String name, int age) { 10 super(); 11 this.name = name; 12 this.age = age; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 public int getAge() { 24 return age; 25 } 26 27 public void setAge(int age) { 28 this.age = age; 29 } 30 31 @Override 32 public int compareTo(Student s) { 33 // 主要条件 姓名的长度 34 int num = this.name.length() - s.name.length(); 35 // 姓名的长度相同,不代表姓名的内容相同 36 int num2 = num == 0 ? this.name.compareTo(s.name) : num; 37 // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄 38 int num3 = num2 == 0 ? this.age - s.age : num2; 39 return num3; 40 } 41} 编写测试类 1/* 2 * 需求:请按照姓名的长度排序 3 */ 4public class TreeSetDemo { 5 public static void main(String[] args) { 6 // 创建集合对象 7 TreeSet<Student> ts = new TreeSet<Student>(); 8 9 // 创建元素 10 Student s1 = new Student("linqingxia", 27); 11 Student s2 = new Student("zhangguorong", 29); 12 Student s3 = new Student("wanglihong", 23); 13 Student s4 = new Student("linqingxia", 27); 14 Student s5 = new Student("liushishi", 22); 15 Student s6 = new Student("wuqilong", 40); 16 Student s7 = new Student("fengqingy", 22); 17 Student s8 = new Student("linqingxia", 29); 18 19 // 添加元素 20 ts.add(s1); 21 ts.add(s2); 22 ts.add(s3); 23 ts.add(s4); 24 ts.add(s5); 25 ts.add(s6); 26 ts.add(s7); 27 ts.add(s8); 28 29 // 遍历 30 for (Student s : ts) { 31 System.out.println(s.getName() + "---" + s.getAge()); 32 } 33 } 34}

运行结果:

可以看到,成功按照姓名的长度排序,由长到短输出了.

TreeSet之比较器排序

比较器排序(集合具备比较性):让集合的构造方法接收一个比较器接口的子类对象 Comparator

还是上一步的要求:添加学生数据,并根据学生的姓名长度,从小到大排序.改为比较器排序做.

创建学生类 1public class Student { 2 private String name; 3 private int age; 4 5 public Student() { 6 super(); 7 } 8 9 public Student(String name, int age) { 10 super(); 11 this.name = name; 12 this.age = age; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 public int getAge() { 24 return age; 25 } 26 27 public void setAge(int age) { 28 this.age = age; 29 } 30} 创建一个比较器接口的子类对象 1import java.util.Comparator; 2 3public class MyComparator implements Comparator<Student> { 4 5 @Override 6 public int compare(Student s1, Student s2) { 7 // int num = this.name.length() - s.name.length(); 8 // this -- s1 9 // s -- s2 10 // 姓名长度 11 int num = s1.getName().length() - s2.getName().length(); 12 // 姓名内容 13 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num; 14 // 年龄 15 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2; 16 return num3; 17 } 18 19} 编写测试类 1import java.util.TreeSet; 2 3/* 4 * 需求:请按照姓名的长度排序 5 * 6 * TreeSet集合保证元素排序和唯一性的原理 7 * 唯一性:是根据比较的返回是否是0来决定。 8 * 排序: 9 * A:自然排序(元素具备比较性) 10 * 让元素所属的类实现自然排序接口 Comparable 11 * B:比较器排序(集合具备比较性) 12 * 让集合的构造方法接收一个比较器接口的子类对象 Comparator 13 */ 14public class TreeSetDemo { 15 public static void main(String[] args) { 16 // 创建集合对象 17 //TreeSet<Student> ts = new TreeSet<Student>(); //自然排序 18 // public TreeSet(Comparator comparator) //比较器排序 19 TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()); 20 21 22 23 // 创建元素 24 Student s1 = new Student("linqingxia", 27); 25 Student s2 = new Student("zhangguorong", 29); 26 Student s3 = new Student("wanglihong", 23); 27 Student s4 = new Student("linqingxia", 27); 28 Student s5 = new Student("liushishi", 22); 29 Student s6 = new Student("wuqilong", 40); 30 Student s7 = new Student("fengqingy", 22); 31 Student s8 = new Student("linqingxia", 29); 32 33 // 添加元素 34 ts.add(s1); 35 ts.add(s2); 36 ts.add(s3); 37 ts.add(s4); 38 ts.add(s5); 39 ts.add(s6); 40 ts.add(s7); 41 ts.add(s8); 42 43 // 遍历 44 for (Student s : ts) { 45 System.out.println(s.getName() + "---" + s.getAge()); 46 } 47 } 48}

运行结果:

成功按照名字长度排序输出

上题中,匿名内部类的写法:如果一个方法的参数是接口,那么真正要的是接口的实现类的对象,而匿名内部类就可以实现这个东西

1public class TreeSetDemo { 2 public static void main(String[] args) { 3 4 // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象 5 // 而匿名内部类就可以实现这个东西 6 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { 7 @Override 8 public int compare(Student s1, Student s2) { 9 // 姓名长度 10 int num = s1.getName().length() - s2.getName().length(); 11 // 姓名内容 12 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) 13 : num; 14 // 年龄 15 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2; 16 return num3; 17 } 18 }); 19 20 // 创建元素 21 Student s1 = new Student("linqingxia", 27); 22 Student s2 = new Student("zhangguorong", 29); 23 Student s3 = new Student("wanglihong", 23); 24 Student s4 = new Student("linqingxia", 27); 25 Student s5 = new Student("liushishi", 22); 26 Student s6 = new Student("wuqilong", 40); 27 Student s7 = new Student("fengqingy", 22); 28 Student s8 = new Student("linqingxia", 29); 29 30 // 添加元素 31 ts.add(s1); 32 ts.add(s2); 33 ts.add(s3); 34 ts.add(s4); 35 ts.add(s5); 36 ts.add(s6); 37 ts.add(s7); 38 ts.add(s8); 39 40 // 遍历 41 for (Student s : ts) { 42 System.out.println(s.getName() + "---" + s.getAge()); 43 } 44 } 45}

运行结果:

可以看到,使用匿名内部类,可以同样按照姓名的长度输出,匿名内部类的写法看似复杂,但熟练之后,及其方便,不用新建一个类了.

TreeSet应用题

键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台 分析: A:定义学生类 B:创建一个TreeSet集合 C:总分从高到底如何实现呢? D:键盘录入5个学生信息

E:遍历TreeSet集合

//创建学生类创建学生类 1public class Student { 2 // 姓名 3 private String name; 4 // 语文成绩 5 private int chinese; 6 // 数学成绩 7 private int math; 8 // 英语成绩 9 private int english; 10 11 public Student(String name, int chinese, int math, int english) { 12 super(); 13 this.name = name; 14 this.chinese = chinese; 15 this.math = math; 16 this.english = english; 17 } 18 19 public Student() { 20 super(); 21 } 22 23 public String getName() { 24 return name; 25 } 26 27 public void setName(String name) { 28 this.name = name; 29 } 30 31 public int getChinese() { 32 return chinese; 33 } 34 35 public void setChinese(int chinese) { 36 this.chinese = chinese; 37 } 38 39 public int getMath() { 40 return math; 41 } 42 43 public void setMath(int math) { 44 this.math = math; 45 } 46 47 public int getEnglish() { 48 return english; 49 } 50 51 public void setEnglish(int english) { 52 this.english = english; 53 } 54 55 public int getSum() { 56 return this.chinese + this.math + this.english; 57 } 58} 编写测试类,采用匿名内部类,实现Comparator的写法 1import java.util.Comparator; 2import java.util.Scanner; 3import java.util.TreeSet; 4 5public class TreeSetDemo { 6 public static void main(String[] args) { 7 // 创建一个TreeSet集合 8 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { 9 @Override 10 public int compare(Student s1, Student s2) { 11 // 总分从高到低 12 int num = s2.getSum() - s1.getSum(); 13 // 总分相同的不一定语文相同 14 int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num; 15 // 总分相同的不一定数序相同 16 int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2; 17 // 总分相同的不一定英语相同 18 int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3; 19 // 姓名还不一定相同呢 20 int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) 21 : num4; 22 return num5; 23 } 24 }); 25 26 System.out.println("学生信息录入开始"); 27 // 键盘录入5个学生信息 28 for (int x = 1; x <= 5; x++) { 29 Scanner sc = new Scanner(System.in); 30 System.out.println("请输入第" + x + "个学生的姓名:"); 31 String name = sc.nextLine(); 32 System.out.println("请输入第" + x + "个学生的语文成绩:"); 33 String chineseString = sc.nextLine(); 34 System.out.println("请输入第" + x + "个学生的数学成绩:"); 35 String mathString = sc.nextLine(); 36 System.out.println("请输入第" + x + "个学生的英语成绩:"); 37 String englishString = sc.nextLine(); 38 39 // 把数据封装到学生对象中 40 Student s = new Student(); 41 s.setName(name); 42 s.setChinese(Integer.parseInt(chineseString)); 43 s.setMath(Integer.parseInt(mathString)); 44 s.setEnglish(Integer.parseInt(englishString)); 45 46 // 把学生对象添加到集合 47 ts.add(s); 48 } 49 System.out.println("学生信息录入完毕"); 50 51 System.out.println("学习信息从高到低排序如下:"); 52 System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩"); 53 // 遍历集合 54 for (Student s : ts) { 55 System.out.println(s.getName() + "\t" + s.getChinese() + "\t" 56 + s.getMath() + "\t" + s.getEnglish()); 57 } 58 } 59}

运行结果

可以看到成功按照学生总成绩,由大到小排序

转载请注明原文地址: https://www.6miu.com/read-2624970.html

最新回复(0)