集合详解之TreeSet集合--排序及API应用

一.TreeSet集合的介绍
TreeSet集合可以确保集合元素处于排序状态
TreeSet集合并不是根据元素的插入顺序进行排序的,而是根据元素实际指的大小进行排序的
与HashSet集合根据HashCode的值来决定元素的存储位置不同的是TreeSet集合是根据红黑树
的数据结构来存储集合元素的.


二.红黑树介绍
红黑树是一种自平衡排序二叉树,树中每个节点的值,都大于或等于在它的左子树中的所有
节点的值,并且小于或等于在它的右子树中的所有节点的值,这确保红黑树运行时可以快速
地在树中查找和定位的所需节点。


排序二叉树是一种特殊结构的二叉树,可以非常方便地对树中所有节点进行排序和检索。
排序二叉树要么是一棵空二叉树,要么是具有下列性质的二叉树:
若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
它的左、右子树也分别为排序二叉树。

三.TreeSet集合支持两种排序方法:自然排序和定制排序.
3.1自然排序
TreeSet集合会调用集合元素的comPareTo(Object object)方法来比较元素之间的大小关系,
然后将元素按升序排列,这种方式就是自然排序.
当把一个对象添加到TreeSet集合时,TreeSet集合调用该对象的comPareTo(Object object)方
法与容器中的其他对象进行比较,然后根据红黑树结构找到他的存储位置.如果两个对象通过
comPareTo(Object object)方法比较相等,新对象将无法添加到TreeSet(Set集合元素不能重复)
集合中.


java提供了一个Comparable接口,该接口里提供了一个comPareTo(Object object)的方法,该方
法返回一个整数,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小.
当一个对象调用该方法与另外一个对象进行比较时,如object1.compareTo(object2),如果该方
法返回0,则这两个对象相等,如果该方法返回一个正整数则表明object1大于object2,如果该方
法返回一个负整数则表明object1小于object2.


错误示例1
package javaDemo;


import java.util.TreeSet;


public class TreeSetDemo2 {
public static void main(String[] args) {
dealData();
}


public static void dealData() {
TreeSet<Student> dataList = new TreeSet<>();
dataList.add(new Student());
}
}
class Student{
private String name;
private int 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;
}
}
运行结果:
Exception in thread "main" java.lang.ClassCastException: javaDemo.Student cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at javaDemo.TreeSetDemo2.dealData(TreeSetDemo2.java:12)
at javaDemo.TreeSetDemo2.main(TreeSetDemo2.java:7)
报异常是因为Student类没有实现Comparable接口.


错误示例2
package javaDemo;


import java.util.TreeSet;


public class TreeSetDemo2 {
public static void main(String[] args) {
dealData();
}


public static void dealData() {
TreeSet<Object> dataList = new TreeSet<>();
// dataList.add(new Student());
dataList.add("1");
dataList.add(1);
}
}
运行结果:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.lang.Integer.compareTo(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at javaDemo.TreeSetDemo2.dealData(TreeSetDemo2.java:14)
at javaDemo.TreeSetDemo2.main(TreeSetDemo2.java:7)
分析:
大部分类在实现compareTo(Object object)方法时都需要将被比较的对象object强转成相同的类型,
因为只有相同的类的两个实例才会比较大小.当试图把一个对象添加到TreeSet集合中时,TreeSet集合
就会调用该对象compareTo(Object object)方法与集合中的其他元素进行比较,这就要求集合中的其
他元素与该元素是同一个类的实例.
也就是说向TreeSet集合中添加的是同一个类的对象,否则就引发异常.


3.2定制排序
如果需要实现定制排序,如降序排序,则需要通过Comparator接口的帮助.该接口里面包含一个int compare(T o1,T o2)的方法;
该方法用于比较o1与o2的大小,返回0表示二者相等,返回正整数表明o1大于o2,返回负整数表明o1小于o2.
定制排序的代码实现
package javaDemo;


import java.util.Comparator;
import java.util.TreeSet;


public class TreeSetCustomSortWay {
public static void main(String[] args) {
// 创建一个实现Comparator接口的对象
Comparator<Child> comparator = new Comparator<Child>() {


@Override
public int compare(Child lhs, Child rhs) {
// 指明按什么 排序
if (lhs.getAge() != rhs.getAge()) {
return rhs.getAge() - lhs.getAge();
} else if (lhs.getBirthDay().getYear() != rhs.getBirthDay().getYear()) {
return rhs.getBirthDay().getYear() - lhs.getBirthDay().getYear();
} else if (lhs.getBirthDay().getMonth() != rhs.getBirthDay().getMonth()) {
return rhs.getBirthDay().getMonth() - lhs.getBirthDay().getMonth();
} else if (lhs.getBirthDay().getDay() != rhs.getBirthDay().getDay()) {
return rhs.getBirthDay().getDay() - lhs.getBirthDay().getDay();
}
return 0;
}
};
// 将Comparator对象作为形参加入到TreeSet构造函数中
TreeSet<Child> data = new TreeSet<>(comparator);
Child child1 = new Child("zhangsan", 27, new BirthDay(1989, 12, 12));
Child child2 = new Child("zhangsan", 27, new BirthDay(1989, 10, 12));
Child child3 = new Child("zhangsan", 27, new BirthDay(1989, 10, 11));
Child child4 = new Child("zhangsan", 26, new BirthDay(1990, 10, 11));
Child child5 = new Child("zhangsan", 24, new BirthDay(1992, 10, 11));
Child child6 = new Child("zhangsan", 27, new BirthDay(1989, 10, 11));
data.add(child1);
data.add(child2);
data.add(child3);
data.add(child4);
data.add(child5);
data.add(child6);
System.out.println(data);
}
}


class Child {


public Child(String name, int age, BirthDay birthDay) {
super();
this.name = name;
this.age = age;
this.birthDay = birthDay;
}


private String name;
private int age;
private BirthDay birthDay;


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


public BirthDay getBirthDay() {
return birthDay;
}


public void setBirthDay(BirthDay birthDay) {
this.birthDay = birthDay;
}


@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (o.getClass() != getClass()) {
return false;
}
Child other = (Child) o;
if (age != other.getAge()) {
return false;
}
if (birthDay == null) {
if (other.getBirthDay() != null) {
return false;
}
} else {
if (other.getBirthDay() == null) {
return false;
}
if (birthDay != other.getBirthDay()) {
return false;
}
}
if (name == null) {
if (other.getName() != null) {
return false;
}
} else {
if (other.getName() == null) {
return false;
}
if (name != other.getName()) {
return false;
}
}
return true;
}


@Override
public int hashCode() {
final int prim = 31;
int result = 1;
result = prim * result + age;
result = prim * result + (birthDay == null ? 0 : birthDay.hashCode());
result = prim * result + (name == null ? 0 : name.hashCode());
return result;
}


@Override
public String toString() {
return "Child[name=" + name + ",age:" + age + ",birthday:" + birthDay + "]";
}
}


class BirthDay {
private int year;
private int month;
private int day;


public BirthDay(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = day;
}


public int getYear() {
return year;
}


public void setYear(int year) {
this.year = year;
}


public int getMonth() {
return month;
}


public void setMonth(int month) {
this.month = month;
}


public int getDay() {
return day;
}


public void setDay(int day) {
this.day = day;
}


@Override
public int hashCode() {
final int prim = 31;
int result = 1;
result = prim * result + year;
result = prim * result + month;
result = prim * result + day;
return result;
}


@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (getClass() != o.getClass()) {
return false;
}
BirthDay other = (BirthDay) o;
if (year != other.getYear()) {
return false;
} else if (month != other.getMonth()) {
return false;
} else if (day != other.getDay()) {
return false;
}
return true;
}


@Override
public String toString() {
return "BirthDay[year:" + year + ",month:" + month + ",day:" + day + "]";
}
}

四.TreeSet集合的方法应用及结果分析
package javaDemo;


import java.util.TreeSet;


public class TreeSetDemo {
public static void main(String[] args) {
dealTreeSet();
dealTreeSet2();
dealTreeSet3();
dealTreeSet4();
}


/**
* Integer型数据
*/
public static void dealTreeSet() {
TreeSet<Object> treeSetData = new TreeSet<>();
treeSetData.add(1);
treeSetData.add(0);
treeSetData.add(-2);
treeSetData.add(2);
treeSetData.add(10);
treeSetData.add(8);
treeSetData.add(3);
treeSetData.add(9);
treeSetData.add(4);
treeSetData.add(-1);
System.out.println("TreeSet集合的元素为:" + treeSetData);
dealData(treeSetData);
// 被比较的是集合中的元素
System.out.println("TreeSet集合小于2的元素集合:" + treeSetData.lower(2));
// 被比较的不是集合中的元素
System.out.println("TreeSet集合小于5的元素集合:" + treeSetData.lower(5));
// 被比较的是集合中的元素
System.out.println("TreeSet集合大于5的元素集合:" + treeSetData.higher(5));
System.out.println("TreeSet集合大于2的元素集合:" + treeSetData.higher(2));
System.out.println("TreeSet集合中处于2到5的元素:" + treeSetData.subSet(2, 5));
System.out.println("TreeSet集合中处于2到8的元素:" + treeSetData.subSet(2, 8));
System.out.println("TreeSet集合中headSet()方法" + treeSetData.headSet(5));
System.out.println("TreeSet集合中headSet()方法" + treeSetData.headSet(8));
System.out.println("TreeSet集合中tailSet()方法" + treeSetData.tailSet(5));
System.out.println("TreeSet集合中tailSet()方法" + treeSetData.tailSet(8));


}


/**
* String型数据
*/
public static void dealTreeSet2() {
TreeSet<Object> treeSetData = new TreeSet<>();
treeSetData.add("java");
treeSetData.add("safe");
treeSetData.add("android");
treeSetData.add("androidw");
treeSetData.add("anquan");
System.out.println("TreeSet集合2的元素为:" + treeSetData);
dealData(treeSetData);
}


/**
* Boolean型数据
*/
public static void dealTreeSet3() {
TreeSet<Object> treeSetData = new TreeSet<>();
treeSetData.add(true);
treeSetData.add(false);
System.out.println("TreeSet集合3的元素为:" + treeSetData);
dealData(treeSetData);
}


/**
* Boolean型数据
*/
public static void dealTreeSet4() {
TreeSet<Object> treeSetData = new TreeSet<>();
treeSetData.add(true);
treeSetData.add(false);
System.out.println("TreeSet集合4的元素为:" + treeSetData);
dealData(treeSetData);
}


/**
* 输出集合第一个和最后一个元素

* @param treeSetData
*/
public static void dealData(TreeSet<Object> treeSetData) {
System.out.println("集合第一个元素:" + treeSetData.first());
System.out.println("集合最后一个元素:" + treeSetData.last());
}


}


运行结果:
TreeSet集合的元素为:[-2, -1, 0, 1, 2, 3, 4, 8, 9, 10]  //该结果说明TreeSet集合元素处于排序状态
集合第一个元素:-2   //返回集合中第一个元素
集合最后一个元素:10   //返回集合中最后一个元素
TreeSet集合小于2的元素:1                               //返回集合中位于指定元素之前的元素
TreeSet集合小于5的元素:4                               //该结果说明TreeSet集合的lower()方法参数可以不是集合中的元素
TreeSet集合大于2的元素:3   //返回集合中位于指定元素之后的元素
TreeSet集合大于5的元素合:8   //该结果说明TreeSet集合的higher()方法参数可以不是集合中的元素
TreeSet集合中处于2到5的元素集合:[2, 3, 4]              //返回该set集合的子集合,该结果说明subSet()方法参数可以不是集合中的元素
TreeSet集合中处于2到8的元素集合:[2, 3, 4]   //返回该set集合的子集合,该结果说明subSet()方法包含左边不包含右边
TreeSet集合中headSet()方法[-2, -1, 0, 1, 2, 3, 4]   //返回该set集合的子集合,由小于参数的元素组成,该方法的参数可以不是集合中的元素
TreeSet集合中headSet()方法[-2, -1, 0, 1, 2, 3, 4]   //返回该set集合的子集合,由小于参数的元素组成,并且不包含该参数
TreeSet集合中tailSet()方法[8, 9, 10]   //返回该set集合的子集合,由小于参数的元素组成,该方法的参数可以不是集合中的元素
TreeSet集合中tailSet()方法[8, 9, 10]   //返回该set集合的子集合,由小于参数的元素组成,并且包含该参数
TreeSet集合2的元素为:[android, androidw, anquan, java, safe]
集合第一个元素:android
集合最后一个元素:safe
TreeSet集合3的元素为:[false, true]
集合第一个元素:false
集合最后一个元素:true
TreeSet集合4的元素为:[false, true]
集合第一个元素:false
集合最后一个元素:true


最后注意,TreeSet集合的这几个方法的参数都指的不是集合元素的角标,而是元素.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Java中,Set是一种集合数据结构,它不允许重复元素,并且没有固定的顺序。然而,Java中的TreeSet是一种基于红黑树数据结构的Set实现,它可以自定义排序规则。 TreeSet是一个有序的集合,它维护了一个基于元素值的红黑树结构。默认情况下,TreeSet按照元素的自然顺序进行排序。例如,如果元素是整数,则按照从小到大的顺序排列;如果元素是字符串,则按照字典顺序进行排序。 但是,TreeSet也可以使用自定义的Comparator接口实现来指定排序规则。Comparator接口定义了一个compare()方法,它接受两个参数并返回一个int值。如果第一个参数小于第二个参数,则返回负整数;如果第一个参数大于第二个参数,则返回正整数;如果两个参数相等,则返回0。 例如,我们可以创建一个按照字符串长度进行排序TreeSet,如下所示: ```java TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } }); treeSet.add("hello"); treeSet.add("world"); treeSet.add("java"); ``` 在这个例子中,我们创建了一个TreeSet并使用了一个自定义的Comparator实现。这个Comparator实现比较两个字符串的长度,并按照长度从小到大的顺序排序。 最终,这个TreeSet中的元素将按照长度从小到大的顺序排列,输出结果为: ``` [java, hello, world] ``` ### 回答2: 在使用Java集合类中的TreeSet时,我们默认使用其自然排序规则对元素进行排序。但有时候,我们需要根据自定义的规则对元素进行排序,这时我们可以使用TreeSet提供的自定义排序方法——Comparator。 Comparator是一个接口,其定义了两个方法,分别是compare()和equals()。其中,compare()方法接收两个参数,分别是要比较的对象x和y,这两个对象需要实现Comparator接口;equals()方法用于比较两个对象是否相等。 假设有一个存放Person对象的TreeSet集合,我们需要根据Person的年龄属性进行升序排序,可以通过以下步骤实现: 1. 定义一个Person类,包含name和age两个属性,以及相应的getter和setter方法; 2. 在Person类中实现Comparator接口,并重写compare()方法,在方法中对年龄属性进行比较; 3. 创建一个TreeSet集合,并在构造函数中传入自定义的Comparator对象; 4. 将多个Person对象添加到TreeSet集合中。 具体的代码实现如下: ``` import java.util.*; class Person implements Comparator<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public int getAge() { return this.age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public int compare(Person p1, Person p2) { if (p1.getAge() > p2.getAge()) { return 1; } else if (p1.getAge() < p2.getAge()) { return -1; } else { return 0; } } } public class TreeSetDemo { public static void main(String[] args) { TreeSet<Person> set = new TreeSet<Person>(new Person()); set.add(new Person("张三", 28)); set.add(new Person("李四", 20)); set.add(new Person("王五", 25)); for (Person p : set) { System.out.println(p.getName() + " " + p.getAge()); } } } ``` 在代码中,我们定义了一个Person类,它实现了Comparator接口,并重写了compare()方法,根据Person对象的age属性进行比较。在主方法中,我们创建了一个TreeSet集合,并在其中添加了多个Person对象,它们会被按照年龄的升序排序。最后,我们通过foreach循环遍历集合中的所有元素,并输出它们的name和age属性。 需要注意的是,在使用自定义比较器时,如果想要保证集合中没有重复元素,我们还需要在Person类中重写equals()方法,并根据name和age两个属性进行比较。 ### 回答3: 在使用Java集合类中的TreeSet时,数据默认情况下是按照自然顺序进行排序的。但是在某些情况下,我们可能希望按照自己定义的规则进行排序。这时,就需要使用TreeSet的自定义排序规则。 自定义排序规则需要我们实现Comparator接口中的compare方法。该方法用于对实现了Comparable接口的对象进行比较。因此,我们需要在自定义类中实现该接口,并重写其中的compare方法。 接下来,我们以Student类为例,介绍如何实现TreeSet的自定义排序规则。假设我们希望按照学生的分数进行从高到低的排序。 首先,在Student类中实现Comparable接口 public class Student implements Comparable<Student>{ private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public int compareTo(Student o) { return o.score - this.score; } } 在该类中,我们通过重写compareTo方法,实现了按照学生分数进行排序的规则。 接下来,在使用TreeSet时,我们需要传入一个Comparator对象,该对象用于指定TreeSet中元素的排序规则。示例代码如下: TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getScore() - o1.getScore(); } }); 在该代码中,我们通过匿名类的方式实现了Comparator接口,并重写了其中的compare方法。通过该方法,我们指定了从高到低的排序规则。 通过以上的示例代码,我们可以看出,自定义排序规则的具体实现可以根据具体情况进行调整。而在该实现中,我们需要注意以下几点: 1. 实现Comparable接口,用于指定对象的默认排序规则。 2. 实现Comparator接口,在特定情况下自定义排序规则。 3. 在使用TreeSet时,需要传入一个Comparator对象,用于指定排序规则。 以上就是Java集合类之set的treeset之自定义排序规则的详细介绍。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值