Java API —— TreeSet类
2015-12-18 20:59
453 查看
1、TreeSet类
1)TreeSet类概述
使用元素的自然顺序对元素进行排序
或者根据创建 set 时提供的 Comparator 进行排序
具体取决于使用的构造方法。
2)TreeSet是如何保证元素的排序和唯一性的
底层数据结构是红黑树(红黑树是一种自平衡的二叉树)
[b]例子1:[/b]
输出结果:
17
18
19
20
22
23
24
3)TreeSet的add()方法的源码解析
4)TreeSet存储元素自然排序和唯一的图解
例子2:存储自定义对象并保证排序唯一
自定义类:先按年龄排序,年龄相同按姓名自然排序
测试类:(TreeSet无参构造,自然排序)
输出结果:
fengqingy---22
liushishi---22
wanglihong---23
linqingxia---27
linqingxia---29
zhangguorong---29
wuqilong---40
例子3:按照姓名的长度排序
自定义学生类:
测试类:(TreeSet无参构造,自然排序)
输出结果:
fengqingy---22
liushishi---22
wanglihong---23
linqingxia---27
linqingxia---29
zhangguorong---29
wuqilong---40
5)自定义比较器
学生类:
方式一:新建一个接口类MyComparator 实现Comparator接口。
[b]MyComparator接口类:[/b]
测试类:(TreeSet有参构造,调用比较器排序)
方式二:直接创建匿名内部类实现比较器
输出结果:
wuqilong---40
fengqingy---22
liushishi---22
linqingxia---27
linqingxia---29
wanglihong---23
zhangguorong---29
例子4:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
例子5:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
学生类:
测试类:
输出结果:
学生信息录入开始
请输入第1个学生的姓名:
小明
请输入第1个学生的语文成绩:
89
请输入第1个学生的数学成绩:
90
请输入第1个学生的英语成绩:
91
请输入第2个学生的姓名:
小红
请输入第2个学生的语文成绩:
99
请输入第2个学生的数学成绩:
95
请输入第2个学生的英语成绩:
100
请输入第3个学生的姓名:
小青
请输入第3个学生的语文成绩:
95
请输入第3个学生的数学成绩:
96
请输入第3个学生的英语成绩:
99
请输入第4个学生的姓名:
小高
请输入第4个学生的语文成绩:
99
请输入第4个学生的数学成绩:
100
请输入第4个学生的英语成绩:
100
请输入第5个学生的姓名:
小杨
请输入第5个学生的语文成绩:
85
请输入第5个学生的数学成绩:
80
请输入第5个学生的英语成绩:
60
学生信息录入完毕
学习信息从高到低排序如下:
姓名 语文成绩 数学成绩 英语成绩
小高 99 100 100
小红 99 95 100
小青 95 96 99
小明 89 90 91
小杨 85 80 60
1)TreeSet类概述
使用元素的自然顺序对元素进行排序
或者根据创建 set 时提供的 Comparator 进行排序
具体取决于使用的构造方法。
2)TreeSet是如何保证元素的排序和唯一性的
底层数据结构是红黑树(红黑树是一种自平衡的二叉树)
[b]例子1:[/b]
package treesetdemos; import java.util.TreeSet; /** * Created by gao on 15-12-17. */ /* * TreeSet:能够对元素按照某种规则进行排序。 * 排序有两种方式 * A:自然排序 * B:比较器排序 * * TreeSet集合的特点:排序和唯一 * * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。 */ public class TreeDemo01 { public static void main(String[] args) { // 创建集合对象 // 自然顺序进行排序 TreeSet<Integer> ts = new TreeSet<Integer>(); // 创建元素并添加 // 20,18,23,22,17,24,19,18,24 ts.add(20); ts.add(18); ts.add(23); ts.add(22); ts.add(17); ts.add(24); ts.add(19); ts.add(18); ts.add(24); // 遍历 for(Integer i : ts){ System.out.println(i); } } }
输出结果:
17
18
19
20
22
23
24
3)TreeSet的add()方法的源码解析
interface Collection {...} interface Set extends Collection {...} interface NavigableMap { } class TreeMap implements NavigableMap { public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // split comparator and comparable paths Comparator<? super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; } } class TreeSet implements Set { private transient NavigableMap<E,Object> m; public TreeSet() { this(new TreeMap<E,Object>()); } public boolean add(E e) { return m.put(e, PRESENT)==null; } } 真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。 所以,你要想重写该方法,就必须是先实现 Comparable接口。这个接口表示的就是自然排序。
4)TreeSet存储元素自然排序和唯一的图解
例子2:存储自定义对象并保证排序唯一
自定义类:先按年龄排序,年龄相同按姓名自然排序
package treesetdemos; /** * @author Administrator * */ /* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 */ public class Student implements Comparable<Student>{ private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int compareTo(Student s) { // return 0; // return 1; // return -1; // 这里返回什么,其实应该根据我的排序规则来做 // 按照年龄排序,主要条件 int num = this.age - s.age; // 次要条件 // 年龄相同的时候,还得去看姓名是否也相同 // 如果年龄和姓名都相同,才是同一个元素 int num2 = num == 0 ? this.name.compareTo(s.name) : num; return num2; } }
测试类:(TreeSet无参构造,自然排序)
package treesetdemos; import java.util.TreeSet; /** * Created by gao on 15-12-17. */ /* * TreeSet存储自定义对象并保证排序和唯一。 * * A:你没有告诉我们怎么排序 * 自然排序,按照年龄从小到大排序 * B:元素什么情况算唯一你也没告诉我 * 成员变量值都相同即为同一个元素 */ public class TreeSetDemo02 { public static void main(String[] args) { // 创建集合对象 TreeSet<Student> ts = new TreeSet<Student>(); // 创建元素 // Student s1 = new Student("linqingxia", 27); Student s2 = new Student("zhangguorong", 29); Student s3 = new Student("wanglihong", 23); Student s4 = new Student("linqingxia", 27); Student s5 = new Student("liushishi", 22); Student s6 = new Student("wuqilong", 40); Student s7 = new Student("fengqingy", 22); Student s8 = new Student("linqingxia", 29); // 添加元素 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); ts.add(s7); ts.add(s8); // 遍历 for (Student s : ts) { System.out.println(s.getName() + "---" + s.getAge()); } } }
输出结果:
fengqingy---22
liushishi---22
wanglihong---23
linqingxia---27
linqingxia---29
zhangguorong---29
wuqilong---40
例子3:按照姓名的长度排序
自定义学生类:
package treesetdemos; /** * Created by gao on 15-12-17. */ public class Student02 implements Comparable<Student02> { private String name; private int age; public Student02() { super(); } public Student02(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int compareTo(Student02 o) { // 主要条件 姓名的长度 int num = this.name.length() - o.name.length(); // 姓名的长度相同,不代表姓名的内容相同 int num2 = num == 0 ? this.name.compareTo(o.name) : num; // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄 int num3 = num2 == 0 ? this.age - o.age : num2; return num3; } }
测试类:(TreeSet无参构造,自然排序)
package treesetdemos; import java.util.TreeSet; /** * Created by gao on 15-12-17. */ /* * 需求:请按照姓名的长度排序 */ public class TreeSetDemo03 { public static void main(String[] args) { // 创建集合对象 TreeSet<Student02> ts = new TreeSet<Student02>(); // 创建元素 // Student02 s1 = new Student02("linqingxia", 27); Student02 s2 = new Student02("zhangguorong", 29); Student02 s3 = new Student02("wanglihong", 23); Student02 s4 = new Student02("linqingxia", 27); Student02 s5 = new Student02("liushishi", 22); Student02 s6 = new Student02("wuqilong", 40); Student02 s7 = new Student02("fengqingy", 22); Student02 s8 = new Student02("linqingxia", 29); // 添加元素 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); ts.add(s7); ts.add(s8); // 遍历 for (Student02 s : ts) { System.out.println(s.getName() + "---" + s.getAge()); } } }
输出结果:
fengqingy---22
liushishi---22
wanglihong---23
linqingxia---27
linqingxia---29
zhangguorong---29
wuqilong---40
5)自定义比较器
学生类:
package comparabledemos; /** * @author Administrator * */ public class Student { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
方式一:新建一个接口类MyComparator 实现Comparator接口。
[b]MyComparator接口类:[/b]
package comparabledemos; import java.util.Comparator; /** * Created by gao on 15-12-18. */ public class MyComparator implements Comparator<Student> { @Override public int compare(Student s1, Student s2) { // int num = this.name.length() - s.name.length(); // this -- s1 // s -- s2 // 姓名长度 int num = s1.getName().length() - s2.getName().length(); // 姓名内容 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num; // 年龄 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2; return num3; } }
测试类:(TreeSet有参构造,调用比较器排序)
package comparabledemos; import java.util.TreeSet; /** * Created by gao on 15-12-18. */ /* * 需求:请按照姓名的长度排序 * * TreeSet集合保证元素排序和唯一性的原理 * 唯一性:是根据比较的返回是否是0来决定。 * 排序: * A:自然排序(元素具备比较性) * 让元素所属的类实现自然排序接口 Comparable * B:比较器排序(集合具备比较性) * 让集合的构造方法接收一个比较器接口的子类对象 Comparator */ public class MyComparableDemo { public static void main(String[] args) { // 创建集合对象 // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序 // public TreeSet(Comparator comparator) //比较器排序 TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()); // 创建元素 Student s1 = new Student("linqingxia", 27); Student s2 = new Student("zhangguorong", 29); Student s3 = new Student("wanglihong", 23); Student s4 = new Student("linqingxia", 27); Student s5 = new Student("liushishi", 22); Student s6 = new Student("wuqilong", 40); Student s7 = new Student("fengqingy", 22); Student s8 = new Student("linqingxia", 29); // 添加元素 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); ts.add(s7); ts.add(s8); // 遍历 for (Student s : ts) { System.out.println(s.getName() + "---" + s.getAge()); } } }
方式二:直接创建匿名内部类实现比较器
package comparabledemos; import java.util.Comparator; import java.util.TreeSet; /** * Created by gao on 15-12-18. */ /* * 需求:请按照姓名的长度排序 * * TreeSet集合保证元素排序和唯一性的原理 * 唯一性:是根据比较的返回是否是0来决定。 * 排序: * A:自然排序(元素具备比较性) * 让元素所属的类实现自然排序接口 Comparable * B:比较器排序(集合具备比较性) * 让集合的构造方法接收一个比较器接口的子类对象 Comparator */ public class MyComparableDemo { public static void main(String[] args) { // 创建集合对象 // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序 // public TreeSet(Comparator comparator) //比较器排序 //TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()); // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象 // 而匿名内部类就可以实现这个东西 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){ @Override public int compare(Student s1, Student s2) { // 姓名长度 int num = s1.getName().length() - s2.getName().length(); // 姓名内容 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num; // 年龄 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2; return num3; } }); // 创建元素 Student s1 = new Student("linqingxia", 27); Student s2 = new Student("zhangguorong", 29); Student s3 = new Student("wanglihong", 23); Student s4 = new Student("linqingxia", 27); Student s5 = new Student("liushishi", 22); Student s6 = new Student("wuqilong", 40); Student s7 = new Student("fengqingy", 22); Student s8 = new Student("linqingxia", 29); // 添加元素 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); ts.add(s7); ts.add(s8); // 遍历 for (Student s : ts) { System.out.println(s.getName() + "---" + s.getAge()); } } }
输出结果:
wuqilong---40
fengqingy---22
liushishi---22
linqingxia---27
linqingxia---29
wanglihong---23
zhangguorong---29
例子4:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
package comparabledemos; import java.util.HashSet; import java.util.Random; /** * Created by gao on 15-12-18. */ /* * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。 * * 分析: * A:创建随机数对象 * B:创建一个HashSet集合 * C:判断集合的长度是不是小于10 * 是:就创建一个随机数添加 * 否:不搭理它 * D:遍历HashSet集合 */ public class HashSetDemo { public static void main(String[] args) { // 创建随机数对象 Random r = new Random(); // 创建一个Set集合 HashSet<Integer> hs = new HashSet<Integer>(); // 判断集合的长度是不是小于10 while (hs.size() < 10) { int x = r.nextInt(20) + 1; hs.add(x); } // 遍历Set集合 for (int x : hs) { System.out.println(x); } } }
例子5:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
学生类:
package comparabledemos; /** * @author Administrator * */ public class Student { // 姓名 private String name; // 语文成绩 private int chinese; // 数学成绩 private int math; // 英语成绩 private int english; public Student() { super(); } public Student(String name, int chinese, int math, int english) { this.name = name; this.chinese = chinese; this.math = math; this.english = english; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getChinese() { return chinese; } public void setChinese(int chinese) { this.chinese = chinese; } public int getMath() { return math; } public void setMath(int math) { this.math = math; } public int getEnglish() { return english; } public void setEnglish(int english) { this.english = english; } public int getSum(){ return this.chinese + this.english + this.math; } }
测试类:
package comparabledemos; import java.util.Comparator; import java.util.Scanner; import java.util.TreeSet; /** * Created by gao on 15-12-18. */ /* * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台 * * 分析: * A:定义学生类 * B:创建一个TreeSet集合 * C:总分从高到底如何实现呢? * D:键盘录入5个学生信息 * E:遍历TreeSet集合 */ public class TreeSetDemo { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { @Override // 创建一个TreeSet集合 public int compare(Student s1, Student s2) { // 总分从高到低(注意这里是s2减s1) int num = s2.getSum() - s1.getSum(); // 总分相同的不一定语文相同 int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num; // 总分相同的不一定数序相同 int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2; // 总分相同的不一定英语相同 int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3; // 姓名还不一定相同 int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) : num4; return num5; } }); System.out.println("学生信息录入开始"); // 键盘录入5个学生信息 for(int x = 1; x <= 5; x++){ Scanner sc = new Scanner(System.in); System.out.println("请输入第" + x + "个学生的姓名:"); String name = sc.nextLine(); System.out.println("请输入第" + x + "个学生的语文成绩:"); String chineseString = sc.nextLine(); System.out.println("请输入第" + x + "个学生的数学成绩:"); String mathString = sc.nextLine(); System.out.println("请输入第" + x + "个学生的英语成绩:"); String englishString = sc.nextLine(); // 把数据封装到学生对象中 Student s = new Student(); s.setName(name); s.setChinese(Integer.parseInt(chineseString)); s.setMath(Integer.parseInt(mathString)); s.setEnglish(Integer.parseInt(englishString)); // 把学生对象添加到集合 ts.add(s); } System.out.println("学生信息录入完毕"); System.out.println("学习信息从高到低排序如下:"); System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩"); // 遍历集合 for (Student s : ts) { System.out.println(s.getName() + "\t" + s.getChinese() + "\t" + s.getMath() + "\t" + s.getEnglish()); } } }
输出结果:
学生信息录入开始
请输入第1个学生的姓名:
小明
请输入第1个学生的语文成绩:
89
请输入第1个学生的数学成绩:
90
请输入第1个学生的英语成绩:
91
请输入第2个学生的姓名:
小红
请输入第2个学生的语文成绩:
99
请输入第2个学生的数学成绩:
95
请输入第2个学生的英语成绩:
100
请输入第3个学生的姓名:
小青
请输入第3个学生的语文成绩:
95
请输入第3个学生的数学成绩:
96
请输入第3个学生的英语成绩:
99
请输入第4个学生的姓名:
小高
请输入第4个学生的语文成绩:
99
请输入第4个学生的数学成绩:
100
请输入第4个学生的英语成绩:
100
请输入第5个学生的姓名:
小杨
请输入第5个学生的语文成绩:
85
请输入第5个学生的数学成绩:
80
请输入第5个学生的英语成绩:
60
学生信息录入完毕
学习信息从高到低排序如下:
姓名 语文成绩 数学成绩 英语成绩
小高 99 100 100
小红 99 95 100
小青 95 96 99
小明 89 90 91
小杨 85 80 60
相关文章推荐
- JavaSE-向数据库保存图片并且读取
- Axis2 java调用.net webservice接口的问题(郑州就维)
- 【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】
- 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁
- 设置eclipse默认编码为UTF-8 Set default encoding to utf-8 in eclipse
- Spring in action(Spring实战) 第四版中文翻译
- struts2所必须的jar包
- java复制那些事
- java学习之内部类
- Java 异常处理
- 使用JDB调试Java程序
- Java基础知识总结
- JAVA中getclass用法
- java中double、float类型计算精度丢失问题
- Eclipse全屏及插件下载
- java 利用spring JavaMailSenderImpl发送邮件,支持普通文本、附件、html、velocity模板
- Java中static关键字总结
- JAVA语法基础之数组
- java中instanceof用法
- java中Ping++退款