1. 程式人生 > >TreeSet集合的理解(自然排序和比較器排序)

TreeSet集合的理解(自然排序和比較器排序)

TreeSet集合

TreeSet集合是Set集合的一個子實現類,它是基於TreeMap中的NavigableSet介面實現的

TreeSet集合是預設通過自然排序將集合中的元素進行排序

TreeSet有兩種排序方式:

1)自然排序

2)比較器排序

讓我們先來看看一個例題:

package com.TreeSetDome;
 
import java.util.TreeSet;
 
public class TreeSetDome {
 
public static void main(String[] args) {
TreeSet<Integer> set=new TreeSet<Integer>();
set.add(17);
set.add(25);
set.add(23);
set.add(14);
set.add(17);
set.add(30);
for(Integer s:set) {
System.out.println(s);
}
}
}
執行結果:
14
17
23
25
30

根據上述結果可以看出TreeSet集合是自然排序和去重的,為什麼會達到這樣的效果呢?

TreeSet集合的無參構造就是屬於自然排序

TreeSet<Integer> set=new TreeSet<Integer>();

這是因為TreeSet集合依賴於TreeMap的紅黑樹結構實現的,下面讓我們根據上述例題去看看紅黑樹結構的理解:

set.add(17);

set.add(25);

set.add(23);

set.add(14);

set.add(17);

set.add(30);

17先進行儲存,所以將17作為根節點,與後面的元素進行比較,25進來後與17相比,比17大,所以成為17的右孩子,放在

17的右邊,23進來比17大所以要放在17的右邊,但是和25比較比他小,所以放在25的左邊,接下來1417小放在17的左邊,17進來與17的值一樣不理睬,繼續下個30,比17大比25大,放在右邊25 的右邊,繪成圖就是二叉圖方式,結構一定是自平衡的

使用TreeSet進行自定義函式的排序,對年齡由小到大進行排序

package com.TreeSetDome;
 
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;
}
 
//因為上面Student類實現了comparable介面,所以必須重寫comparaTo方法才能達到排序的效果
@Override
public int compareTo(Student s) {
// return 0;
/**
 * 因為這是我們自定義的類,系統並沒有告訴我們如何進行排序
 * 所以需要我們自己手動進行排序
 * 需求:按年齡由小到大進行排序
 */
//年齡進行排序,由小到大
int num=this.age-s.age;
//當年齡大小相等時,比較名字
int num2=num==0?this.name.compareTo(s.getName()):num;
return num2;
}

}

package com.TreeSetDome;
 
import java.util.TreeSet;
 
public class StudentDome {
 
public static void main(String[] args) {
//建立TreeSet集合物件
TreeSet<Student> set=new TreeSet<Student>();
//建立學生物件,這裡的學生姓名不要寫成漢字,因為每個漢字的位元組大小不一樣
Student s1=new Student("dilireba",27);
Student s2=new Student("gaowen",25);
Student s3=new Student("zhaoxingxing",24);
Student s4=new Student("wuxuanyi",23);
Student s5=new Student("dilireba",27);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//增強for迴圈
for(Student st:set) {
System.out.println(st.getName()+"---"+st.getAge());
}
}
}
執行結果:
wuxuanyi---23
zhaoxingxing---24
gaowen---25
dilireba---27

由上例可以看出我們在學生類上實線了comparable介面,並且在學生類中重寫了comparaTo方法,當我們沒有進行以上的這些操作時,執行時就會出現這樣的錯誤,

Exception in thread "main" java.lang.ClassCastException: com.TreeSetDome.Student cannot be cast to java.lang.Comparable

因為沒有實現comparable介面,所以會出現以上的這個異常,但是為什麼在前面新增數字的時候並不需要實現comparable介面呢?這是新增數字時我們確定了型別為Integer型別,它本身就已經實現了comparable介面,不需要我們再去新增,具體可以去API中觀看,所以今後在使用TreeSet建立自定義類排序的時候,一定要自己去實現comparable介面,和重寫comparaTo方法

上述中我們重寫的ComparaTo方法是按照年齡來排序的,接下來讓我們按照姓名的長度以及年齡的大小來排序:

@Override
public int compareTo (Student s) {
/**
 * 因為這是我們自定義的類,系統並沒有告訴我們如何進行排序
 * 所以需要我們自己手動進行排序
 * 需求:按姓名的長度來排序,然後再以年齡的大小來排序
 */
//按姓名的長短來排序,由小到大排序
int num=this.getName().length()-s.getName().length();
//再去比較的姓名的內容是否一致
int num2=num==0?this.getName().compareTo(s.getName()):num;
//名字一致,有時候並不是同一個人 還得再去比較年齡的大小
int  num3=num2==0?this.age-s.age:num2;
return num3;
這是重寫的comparaTo方法,我新添加了一個學生變數Student s6=new Student("dilireba",25);
 
執行結果:
gaowen---25
dilireba---25
dilireba---27
wuxuanyi---23
zhaoxingxing---24

上面我們介紹了自然排序法,自然排序法主要就是運用TreeSet的無參構造,通過實現comparable介面中的comparaTo方法去進行自然排序,接下來讓我們看看比較器排序,看看二者的不同

package com.TreeSet;
 
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;
}

}

package com.TreeSet;
 
import java.util.Comparator;
import java.util.NavigableMap;
 
public class ComparatorDome implements Comparator<Student>{
 
@Override
/**
 * 因為測試類中TreeSet集合的引用引數是介面,所以需要建立這個子實現類去實現這個介面
 * 這裡的s1就相當於自然排序中的this,s2相當於s
 * 先按名字的長度,當長度一致時,再按年齡的大小進行排序
 */
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;
}
 
}

package com.TreeSet;
 
import java.util.TreeSet;
 
public class StudentDome {
 
 
public static void main(String[] args) {
//建立TreeSet集合物件,運用比較器排序
//Comparator是一個介面,所以我們得建立一個子實現類去實現它
TreeSet<Student> set=new TreeSet<Student>(new ComparatorDome());
//建立學生物件
Student s1=new Student("dilireba",27);
Student s2=new Student("gaowen",25);
Student s3=new Student("zhaoxingxing",24);
Student s4=new Student("wuxuanyi",23);
Student s5=new Student("dilireba",25);
Student s6=new Student("dilireba",25);
//將學生物件新增到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
//增強for迴圈遍歷
for(Student s:set) {
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
執行結果:
gaowen---25
dilireba---25
dilireba---27
wuxuanyi---23
zhaoxingxing---24

除了建立子實現類去實現Comparator介面,我們還可以在測試類中通過匿名內部類的方式去測試,就不用單獨去建立一個子實現類了

在這裡學生類我就不寫了,上面有,直接寫測試類中的匿名內部類了

package com.TreeSet;
 
import java.util.Comparator;
import java.util.TreeSet;
 
public class StudentDome {
 
 
public static void main(String[] args) {
//建立TreeSet集合物件,運用比較器排序
//Comparator是一個介面,所以我們得建立一個子實現類去實現它
//匿名內部類的使用
TreeSet<Student> set=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("dilireba",27);
Student s2=new Student("gaowen",25);
Student s3=new Student("zhaoxingxing",24);
Student s4=new Student("wuxuanyi",23);
Student s5=new Student("dilireba",25);
Student s6=new Student("dilireba",25);
//將學生物件新增到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
//增強for迴圈遍歷
for(Student s:set) {
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
執行結果:
gaowen---25
dilireba---25
dilireba---27
wuxuanyi---23
zhaoxingxing---24