Java API —— TreeSet類


1、TreeSet類
   1)TreeSet類概述
        使用元素的自然順序對元素進行排序
        或者根據創建 set 時提供的 Comparator 進行排序
        具體取決於使用的 構造方法。 
    2)TreeSet是如何保證元素的排序和唯一性的
        底層數據結構是紅黑樹(紅黑樹是一種自平衡的二叉樹)
 
例子1:
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接口。

MyComparator接口類:
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

 

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM