• 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("姓名	语文成绩	数学成绩	英语成绩");
            // 遍历集合
            for (Student s : ts) {
                System.out.println(s.getName() + "	" + s.getChinese() + "	"
                        + s.getMath() + "	" + 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
     
     
     
  • 相关阅读:
    Spell checker
    Power Network
    ACM Computer Factory
    Asteroids
    Golang: 并发抓取网页内容
    Golang: 抓取网页内容
    Golang: 读取文件并统计内容
    Golang: 接收命令行输入
    React: 有状态组件生成真实DOM结点
    React: 无状态组件生成真实DOM结点
  • 原文地址:https://www.cnblogs.com/yangyquin/p/5058208.html
Copyright © 2020-2023  润新知