TreeSet 和TreeMap排序问题

List集合排序

Set子接口与list子接口的不同,那就是list子接口是可以保存重复的数据的,而Set子接口是不能保存重复的数据的。

 

首先我们知道List集合排序方式直接使用Collections工具类中的sort方法中默认是升序

sort方法有两种重载的形式:

sort(List list) :

                    要求传入的待排序容器中存放的对象所属的类必须实现Comparable接口以实现元素的比较。
 

sort(List list, Comparator c)

                  不强制要求待排序容器中存放的对象所属的类必须实现Comparable接口,但是要求传入第二个参数,这个参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法。
 

Comparable:内部比较器(默认比较器)
            重写compareTo(Object t1,Object t2);    内部【默认】比较规则
            排序的规则,就是compare方法中的代码;
            t1-t2  升序(自然顺序)
            t2-t1  降序(倒叙)

         Comparator:外部比较器
            重写int compare(T t1, T t2)  【自定义】的比较规则
            t1-t2  升序(自然顺序)
            t2-t1  降序(倒叙)

            【外部比较器的优先级高于内部比较器】

 

TreeMap排序

TreeMap采用一种被称为“红黑树”的排序二叉树来保存Map中的的每个Entry——每个Entry都被当做红黑树的一个节点来对待;

TreeMap的插入就是一个“排序二叉树”算法:每当程序添加新节点时,总是从树的根节点开始比较,即将根节点当成当前节点,如果新增节点大于当前节点且当前节点的右节点存在,则以右节点作为当前节点;如果新增节点小于当前节点且当前节点的左节点存在,则以左节点作为当前节点;如果新增节点等于当前节点,则新增节点覆盖当前节点;直到某个节点的左右节点不存在,并结束循环;将新增的节点作为该节点的子节点,如果新增的节点大于该节点,则添加成该节点的右节点,如果新增的节点小于该节点,则添加成该节点的左节点;TreeMap 根据Key来获取value。

根据键值大小 默认方式给存入的元素进行升序排序

TreeMap map=new TreeMap<>();
 map.put(1,34);
 map.put(4,24);
 map.put(2,94);
 map.put(7,54);
 map.put(4,1);
 //去重了和根据键值进行默认升序排序
System.out.println(map);//{1=34, 2=94, 4=1, 7=54}

 

 利用TreeMap的有参构造方法实现排序
外部比较器重写Comparator方法 返回1 实现了存取顺序一致且不去重
TreeMap map=new TreeMap<>(new Comparator() {
    @Override
    public int compare(Integer o1, Integer o2) {
        //实现了 存取顺序一致
        // return 1;      //{1=34, 4=24, 2=94, 7=54, 4=1}
        //实现了 存取顺序相反
          return -1;        //{4=1, 7=54, 2=94, 4=24, 1=34}
    }
});
 map.put(1,34);
 map.put(4,24);
 map.put(2,94);
 map.put(7,54);
 map.put(4,1);
 //不去重了和存取顺序一致
System.out.println(map);

外部比较器重写Comparator方法 不去重且实现升序或者降序排列

TreeMap map=new TreeMap<>(new Comparator() {
    @Override
    public int compare(Integer o1, Integer o2) {
        //o1-o1=0的话返回0 代表不存入树结构中 这是就删除了重复的元素 也是去重的原理
        // 所以我们如同需要重复元素我们必须让他不返回0 返回其他即可
        //若不等于0 则返回o1.compareTo(o2)  升序
        //若不等于0 则返回o2.compareTo(o1)  降序
        // return o1-o2==0?1:o2.compareTo(o1);//  {7=54, 4=24, 4=1, 2=94, 1=34}
        // return o1-o2==0?1:o1.compareTo(o2);//  {1=34, 2=94, 4=24, 4=1, 7=54}
    }
});
 map.put(1,34);
 map.put(4,24);
 map.put(2,94);
 map.put(7,54);
 map.put(4,1);
 //不去重了和存取顺序一致
System.out.println(map);


TreeSet排序

底层原理:

            实际上TreeSet还是用TreeMap来保存set元素。所以原理和上面介绍的TreeMap一致

            只是Set 是单列集合  Map 是双列集合。 

1、HashSet与TreeSet接口的一点不同,HashSet  保存的数据是无序的,TreeSet保存的数据是有序的,所以如果要想保存的数据有序应该使用TreeSet子类。

2、利用TreeSet保存自定义类对象的时候,自定义所在的类一定要实现Comparable接口,如果没有实现这个接口那么就无法区分大小关系,而且在TreeSet中如果要进行排序,那么就要将所有的字段都进行比较,就是说在TreeSet中是依靠comparato()方法返回的是不是0来判断是不是重复元素的。

3、如果是HashSet子类,那么其判断重复数据的方式不是依靠的comparable接口而是Object类之中的两个方法:(1)取得对象的哈希码 hashCode();(2)对象比较:equals(); 这俩个方法均不需要自己编写,在eclipse里面可以使用右键source 选择自动生成。就像生成Getter 和Setter 方法一样。

TreeSet treeSet =new TreeSet<>(new Comparator() {
    @Override
    public int compare(Integer o1, Integer o2) {
        //o1-o1=0的话返回0 代表不存入树结构中 这是就删除了重复的元素 也是去重的原理
        // 所以我们如同需要重复元素我们必须让他不返回0 返回其他即可
        //若不等于0 则返回o1.compareTo(o2)  升序
        //若不等于0 则返回o2.compareTo(o1)  降序
        //return o1-o2==0?1:o1.compareTo(o2);//[67, 45, 34, 34, 12, 11, 9]
          return o1-o2==0?1:o2.compareTo(o1); //[9, 11, 12, 34, 34, 45, 67]
    }   
});
   Collections.addAll(treeSet,12,34,11,45,34,67,9);
   System.out.println(treeSet);

总结:TreeSet 依靠的是Comparable 来区分重复数据;
HashSet 依靠的是hashCode()、equals()来区分重复数据
Set 里面不允许保存重复数据

 

 

你可能感兴趣的:(javaweb)