TreeSet底层add及例题 day14

package com.shujia.day14;

import java.util.TreeSet;

/*
    Collection:
        - List(元素有序且可以发生重复,有索引的概念)
            - ArrayList(底层数据结构是数组,查询快,增删慢,线程不安全,效率高)
            - Vector(底层数据结构是数组,查询快,增删慢,线程安全,效率低,即便安全,我们今后也不用)
            - LinkedList(底层数据结构是双链表,增删快,查询慢,线程不安全,效率高)
        - Set(元素唯一且无序)
            - HashSet(底层数据结构是哈希表,线程不安全,效率高,要求元素类中要重写hashCode和equals方法,才能保证唯一)
                - LinkedHashSet(底层数据结构是哈希表和双链表,哈希表保证了元素的唯一性,双链表保证了元素的有序)
            - TreeSet(底层数据结构是红黑树)
                两种排序方式:
                    1. 自然排序
                        使用无参构造方法创建TreeSet集合对象,要求元素类实现Comparable<元素类>接口,重写compareTo方法
                    2. 比较器排序
                        使用有参构造方法创建TreeSet集合对象,将实现了Comparator接口且重写compare方法的对象当作构造方法的参数使用
红黑树左边小于根右边大于根,无论是自然排序还是比较器排序,添加元素的顺序分别由重写的compareTo方法和重写compare方法决定

    
 */

使用TreeSet存储自定义学生对象,按照年龄从小到大排序,且去重

  1. 自然排序 是通过compareTo方法进行比较的,而compareTo方法在Comparable<元素类>接口中,所以要实现Comparable<元素类>接口
    第一个元素为根,从第二个元素开始用compareTo方法比较元素,返回0不添加
    实现类
package com.shujia.day14;

import java.util.TreeSet;

/*
    使用TreeSet存储自定义学生对象,按照年龄从小到大排序,且去重

    若创建TreeSet对象是无参构造方法的话,底层创建TreeMap无参构造方法创建的,comparator = null;走的自然排序

 */
public class TreeSetDemo2 {
    public static void main(String[] args) {
        //创建TreeSet的集合对象
        TreeSet<Student2> set1 = new TreeSet<>();

        //创建元素对象
        Student2 s1 = new Student2("魏一民", 18);
        Student2 s2 = new Student2("陈真", 18);
        Student2 s3 = new Student2("李建国", 16);
        Student2 s4 = new Student2("魏一民", 18);
        Student2 s5 = new Student2("小虎", 15);

        //添加元素
        set1.add(s1);
        set1.add(s2);
        set1.add(s3);
        set1.add(s4);
        set1.add(s5);

        //遍历集合
        for (Student2 student2 : set1) {
            System.out.println(student2);
        }

    }
}

学生对象

package com.shujia.day14;

public class Student2 implements Comparable<Student2> {
    private String name;
    private int age;

    public Student2() {
    }

    public Student2(String name, int age) {
        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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student2 o) {
        //这个方法的返回值,决定待插入的元素的顺序,是左边还是右边还是不添加
        //这里的逻辑需要我们自己编写
        //显式条件:按照年龄从小到大排序
        //k.compareTo(t.key)
        // this -- k
        // o --  t.key
        int i = this.age - o.age;
        //隐式条件 当年龄一样的时候,比较姓名
        return (i == 0) ? this.name.compareTo(o.name) : i;
    }
}

2.比较器排序

实现类

package com.shujia.day14;

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

/*
    TreeSet的比较器排序
    通过观察源码发现.要想使用比较器排序,就得保证TreeMap中的comparator参数不是null,
    要想保证TreeMap中的comparator参数不是null,就得使用TreeMap有参构造方法来创建,就要保证在创建TreeSet对象的时候
    ,传入一个实现了Comparator的对象
 */

//class ComparatorImpl implements Comparator<Student3>{
//    @Override
//    public int compare(Student3 o1, Student3 o2) {
//        //cpr.compare(key, t.key);
//        // o1 - key - 待插入的元素
//        // o2 - t.key - 根的元素
//        //需求:按照年龄从小到大排序,并去重
//        int i = o2.getAge() - o1.getAge();
//        return (i==0)?o1.getName().compareTo(o2.getName()):i;
//    }
//}

public class TreeSetDemo3 {
    public static void main(String[] args) {
//        TreeSet<Student3> set1 = new TreeSet<>(new ComparatorImpl());

        TreeSet<Student3> set1 = new TreeSet<>(new Comparator<Student3>() {
            @Override
            public int compare(Student3 o1, Student3 o2) {
                //cpr.compare(key, t.key);
                // o1 - key - 待插入的元素
                // o2 - t.key - 根的元素
                //需求:按照年龄从小到大排序,并去重
                int i = o2.getAge() - o1.getAge();
                return (i == 0) ? o1.getName().compareTo(o2.getName()) : i;
            }
        });

        //创建元素对象
        Student3 s1 = new Student3("魏一民", 18);
        Student3 s2 = new Student3("陈真", 18);
        Student3 s3 = new Student3("李建国", 16);
        Student3 s4 = new Student3("魏一民", 18);
        Student3 s5 = new Student3("小虎", 15);

        //添加元素
        set1.add(s1);
        set1.add(s2);
        set1.add(s3);
        set1.add(s4);
        set1.add(s5);

        //遍历集合
        for (Student3 student : set1) {
            System.out.println(student);
        }
    }
}

学生对象

package com.shujia.day14;

public class Student3 {
    private String name;
    private int age;

    public Student3() {
    }

    public Student3(String name, int age) {
        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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Treeset中的add方法源代码解析

// 结论1: TreeSet调用的add方法底层是调用了TreeMap中的put方法进行添加元素的


/*
    //创建一个TreeSet对象
    TreeSet<String> set1 = new TreeSet<>();
*/
class TreeSet{
    private transient NavigableMap<E,Object> m; // null
    private static final Object PRESENT = new Object();

    public TreeSet() {
        this(new TreeMap<E,Object>()); // this(...)
    }

    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

    //set1.add("hello");
    //set1.add("world");
    public boolean add(E e) {
        // E - String
        // e - "world"
        // PRESENT - new Object();
        return m.put(e, PRESENT)==null;
    }
}

class TreeMap{
    private transient Entry<K,V> root; // null

    public TreeMap() {
        comparator = null;
    }

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }


    public V put(K key, V value) {
        // key - "world"
        // value - new Object()
        Entry<K,V> t = root; // 第一个元素添加的时候,树连根都没有,是null

        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; // null


        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();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key; // Student2
            do {
                parent = t; // "hello"
                cmp = k.compareTo(t.key); // "world".compareTo("hello")
                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;
    }
}
posted @   ていせい  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示