1.TreeSet介紹
TreeSet集合底層採用紅黑樹算法,會對存儲的元素默認使用自然排序(從小到大).
注意: 必須保證TreeSet集合中的元素對象是相同的數據類型,否則報錯.
2.TreeSet的排序規則
自然排序(從小到大):TreeSet調用集合元素的compareTo方法來比較元素的大小關係,然後將集合元素按照升序排列(從小到大).
注意:要求TreeSet集合中元素得實現java.util.Comparable接口.
各種數據類型自然排序規則
java.util.Comparable接口:可比較的.
覆蓋 public int compareTo(Object o)方法,在該方法中編寫比較規則.
在該方法中,比較當前對象(this)和參數對象o做比較(嚴格上說比較的是對象中的數據,比如按照對象的年齡排序).
this > o: 返回正整數. 1
this < o: 返回負整數. -1
this == o: 返回0. 此時認爲兩個對象爲同一個對象.
--------------------------------------
在TreeSet的自然排序中,認爲如果兩個對象做比較的compareTo方法返回的是0,則認爲是同一個對象.
從上圖可知,基本上很多類都實現了這個接口,我們來看一下String類源碼,可以看出String已經實現Comparable,並覆蓋compareTo方法
舉例:
import java.util.Set;
import java.util.TreeSet;
public class SetDemo4 {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("a");
set.add("A");
set.add("abc");
set.add("B");
System.out.println(set);//打印結果,已經排好序了[A, B, a, abc],按照字符串的Unicode值排序
}
}
在這裏我們如果要想自己定義的類在TreeSet中也能實現自然排序,那麼就要根據上面的步驟來實現:
舉個例子:首先定義一個Student類,這個類要實現Comparable接口,然後覆蓋CompareTo方法,自定義自己需要排序的規則,比如我們這裏按照學生的姓名的長度進行自然排序:
class Student implements Comparable<Student>{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
/**
* 覆蓋compareTo方法
* 根據學生的姓名長度排序
*/
public int compareTo(Student stu) {
if (this.getName().length()>stu.getName().length()) {
return 1;
}else if (this.getName().length()<stu.getName().length()) {
return -1;
}else {
return 0; //長度相同
}
}
}
測試:打印結果,姓名長度由短到長來排序的
import java.util.Set;
import java.util.TreeSet;
public class SetDemo4 {
public static void main(String[] args) {
Set<Student> set = new TreeSet<>();
set.add(new Student(1, "聶小倩"));
set.add(new Student(1, "西門吹雪"));
set.add(new Student(1, "哥"));
set.add(new Student(1, "孫斌"));
System.out.println(set);
//打印結果看下面,說明是按照名字長度從小到大的自然順序來排序的
//[Student [id=1, name=哥], Student [id=1, name=孫斌], Student [id=1, name=聶小倩], Student [id=1, name=西門吹雪]]
}
}
定製排序(比如從大到小,按照名字的長短來排序):
在TreeSet構造器中傳遞java.lang.Comparator對象.並覆蓋public int compare(Object o1, Object o2)再編寫比較規則.
在TreeSet構造函數中,有一個構造函數可以傳入一個比較器對象,他是一個接口,我們需要提供實現類,並覆蓋compare方法再編寫比較規則.
同樣的,我們舉個例子,也是按照學生姓名長度排序:
首先也是定義一個學生類:
class Student{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
然後定義比較器類:
import java.util.Comparator;
//比較器類
class NameLengthComparator implements Comparator<Student> {
/**
* 覆蓋compare方法
* 比較規則:同樣是根據學生的姓名長度排序
*/
public int compare(Student s1, Student s2) {
if (s1.getName().length() > s2.getName().length()) {
return 1;
} else if (s1.getName().length() < s2.getName().length()) {
return -1;
} else {
return 0;
}
}
}
測試:
import java.util.Set;
import java.util.TreeSet;
public class SetDemo5 {
public static void main(String[] args) {
//創建set對象的時候要傳入比較器類對象
Set<Student> set = new TreeSet<>(new NameLengthComparator());
set.add(new Student(1, "聶小倩"));
set.add(new Student(1, "西門吹雪"));
set.add(new Student(1, "哥"));
set.add(new Student(1, "孫斌"));
System.out.println(set);
}
}
打印結果:
[Student2 [id=1, name=哥], Student2 [id=1, name=孫斌], Student2 [id=1, name=聶小倩], Student2 [id=1, name=西門吹雪]]
既然是定製排序,你可以修改排序規則,按照從長到短來排序,只需要修改比較器類的實現規則
import java.util.Comparator;
//比較器類
class NameLengthComparator implements Comparator<Student> {
/**
* 覆蓋compare方法
* 比較規則:同樣是根據學生的姓名長度排序
*/
public int compare(Student s1, Student s2) {
if (s1.getName().length() < s2.getName().length()) {
return 1;
} else if (s1.getName().length() > s2.getName().length()) {
return -1;
} else {
return 0;
}
}
}
將if中的>和<修改一下就行了對於TreeSet集合來說,要麼使用自然排序,要麼使用定製排序.
判斷兩個對象是否相等的規則:
自然排序: compareTo方法返回0;
定製排序: compare方法返回0;