Java集合(十一)TreeSet解读

发布于:2022-11-28 ⋅ 阅读:(625) ⋅ 点赞:(0)

 我们查看treeset的构造器的时候,发现TreeSet的构造器除了那种无参构造器之外,还提供了另外四种。其中TreeSet(Comparator<E>)可以传比较器。

public interface Comparator<T> {
 int compare(T o1, T o2);

Comparator是一个接口,他有一个方法叫compare,我们可以在他的compare方法指定他的一个排序规则。

我们在设计代码过程中用到的compareTo方法的源码如下所示:

 public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

就是把value值取出来,然后进行循环比较,如果发现不相等,就返回c1-c2,然后谁的ACCIS码值大,就返回大于0的值,否则返回小于0的值。然后根据返回的值进行排序。

我们设计代码如下所示:

package com.rgf.set;

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

@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
        //2.我们希望添加的元素按照字符串大小来排序
        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //并指定排序规则

        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //调用String的compareTo方法,进行字符串大小比较
                return ((String)o1).compareTo((String)o2);
            }
        });
        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");

        System.out.println("treeSet="+treeSet);
    }
}

运行界面如下所示:

 这种排序是从大到小排,我们也可以将他拍成从小到大排:

 return ((String)o2).compareTo((String)o1);

运行之后如下所示:

 我们下来进行源码的分析:

我们在 TreeSet treeSet = new TreeSet(new Comparator() {代码处进行断点的设置:

 我们点击Force Step进入之后,在退出来。

我们可以通过f9直接跳出来,我们也可以进去后再退出来,我们进行如下所示:

 这个构造器接收了一个comparator,这个接口的实现对象。

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

我们继续进去如下所示:他把这个对象传给了如下所示:

 这个comparator(比较器)传给了底层的TreeMap,

我们继续进行下一步,我们进入了add方法:

 我们继续进行下一步:

我们再次进入了TreeMap里面了,进入了TreeMap里面的put方法。

 我们继续进行下一步:

  


//我们将comparator赋给了cpr,comparator为我们传进去的comparator。 
Comparator<? super K> cpr = comparator;
//在调用treeSet.add("tom"),在底层会执行到
        if (cpr != null) {//是有比较器的,比较器不为空。cpr,就是我们的匿名内部类(对象)
            do {
                parent = t;
                //动态绑定到我们的匿名内部类(对象)compare方法
                cmp = cpr.compare(key, t.key); 
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else  //如果相等,即返回0,这个key就没有加入
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                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;
    }

我们继续进行下一步之后,确实进入到如下所示:

 我们进行设计重复值如下所示:

package com.rgf.set;

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

@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
        //2.我们希望添加的元素按照字符串大小来排序
        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //并指定排序规则

        TreeSet treeSet = new TreeSet(new Comparator() {
            //实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
            @Override
            public int compare(Object o1, Object o2) {
                //调用String的compareTo方法,进行字符串大小比较
                return ((String)o2).compareTo((String)o1);
            }
        });
        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");
        treeSet.add("a");
        

        System.out.println("treeSet="+treeSet);
        //1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
    }
}

我们运行界面如下所示:

 我们发现运行结果里面没有重复值a,我们进行debug,如下所示:

我们进入add方法:

 在进入put方法:

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
//比较器赋值给cpr.
        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();
            @SuppressWarnings("unchecked")
                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;
    }

 再次继续之后,我们发现退出来了:

所以相同的值是没有进去的。

如果我们修改按照长度大小排序:

 我们修改代码如下所示:

//按照长度大小排序:
                return ((String)o2).length()-((String)o1).length();

运行界面如下所示:

如果长度大小从小到大,代码修改如下所示:

//按照长度大小排序:
                return ((String)o1).length()-((String)o2).length();

运行界面如下所示:

我们在添加如如下代码的时候,添加不进去:

package com.rgf.set;

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

@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
        //2.我们希望添加的元素按照字符串大小来排序
        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //并指定排序规则

        TreeSet treeSet = new TreeSet(new Comparator() {
            //实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
            @Override
            public int compare(Object o1, Object o2) {
                //调用String的compareTo方法,进行字符串大小比较
                //按照长度大小排序:
                return ((String)o1).length()-((String)o2).length();
            }
        });
        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");
        treeSet.add("rgf");//加入不进去。相同长度会覆盖前面的。一个大小
        //我们所设置的规则为长度相等就是相同的元素。
        //这里不进行替换,这相当于是key,key不允许重复,
        //重新了comparetor,所以他的长度就是key,已经有一个key是3了所以加不进去。


        System.out.println("treeSet="+treeSet);
        //1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
    }
}

 运行界面如下所示:

 我们将规则进行改变后,如下所示:

package com.rgf.set;

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

@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
        //2.我们希望添加的元素按照字符串大小来排序
        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //并指定排序规则

        TreeSet treeSet = new TreeSet(new Comparator() {
            //实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
            @Override
            public int compare(Object o1, Object o2) {
                //调用String的compareTo方法,进行字符串大小比较
                //按照长度大小排序:
                return ((String)o2).compareTo((String)o1);
            }
        });
        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");
        treeSet.add("rgf");//加入不进去。相同长度会覆盖前面的。一个大小
        //我们所设置的规则为长度相等就是相同的元素。
        //这里不进行替换,这相当于是key,key不允许重复,
        //重新了comparetor,所以他的长度就是key,已经有一个key是3了所以加不进去。


        System.out.println("treeSet="+treeSet);
        //1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
    }
}

运行界面如下所示:

我们发现成功添加了进去。 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到