(比较器)详解java中TreeMap和TreeSet排序——Comparable和Comparator

TreeMap和SortedSet之间的关系

前提知识:
在Collection集合中,Set接口无序不可重复
继承Set接口的SortedSet接口它的特点继承了Set也是无序不可重复,但是SortedSet可以自动排序
实现SortedSet接口的TreeSet底层是TreeMap,采用的是二叉树结构,会自动排序

TreeMap传入的是键值对k-v,做比较的时候是按照k的比较来进行自平衡二叉树的插入
TreeSet传入的是k,v值是一个固定的object对象

进入HashSet的add源代码

 TreeSet<School> t=new TreeSet<>();
        t.add(s);

里面是TreeSet的put方法。

    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

无参构造
仔细看在new TreeSet的时候,它底层代码为

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

有参构造

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

这里的参数为一个比较器 下文将介绍。

总之即构造了一个TreeMap内存空间
即 此时的put为TreeMap里的put

关于TreeMap中put方法

而实际上 TreeMap的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
        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;
    }

当添加元素为String,Interger等基本类型时

上述为在添加元素时,底层代码就自动为你排序了,这时我们要做的就是输出。
仅对无序的数字和字符串输入,检查输出会不会排序

package SortedMap01;
import java.util.TreeSet;

public class Sorted {
    public static void main(String[] args) {
        TreeSet<Integer> t=new TreeSet<>();
        t.add(123);
        t.add(101);
        t.add(23);
        t.add(155);
        t.add(0);

        for (Integer x:t) {
            System.out.println(x);
        }
        System.out.println("*******************");
        TreeSet<String> s=new TreeSet<>();
        s.add("a");
        s.add("g");
        s.add("x");
        s.add("g");
        s.add("abvf");
        s.add("张三");
        for (String sx:s) {
            System.out.println(sx);
        }
    }
}


在这里插入图片描述

添加元素为自定义类时

那么对自定义的类,添加到TreeSet中会自动排序吗?

package SortedMap01;

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

public class SortedMapTest01 {
    public static void main(String[] args) {
        Person p=new Person(17);
        Person p2=new Person(37);
        Person p3=new Person(92);
        Person p4=new Person(99);
        //System.out.println(p);
        TreeSet<Person> s=new TreeSet<>();
        s.add(p);
        s.add(p2);
        s.add(p3);
        s.add(p4);
        for (Person out:s) {
            System.out.println(out);
        }
    }
}
class Person{
    private int age;

    public Person(int age) {
        this.age = age;
    }
}

在这里插入图片描述
在这里插入图片描述

可见,哪怕输入是int,也不会进行排序,还会出错,报错为没有Compareable。

那上面String 和int为啥不报错?

点进源码看看
Integer类中

public final class Integer extends Number implements Comparable<Integer> {....}

说明Integer实现了Comparable接口

看看Comparable接口有啥

public int compareTo(T o)

Integer类中实现了该方法

 public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
public static int compare(int x, int y) {
     return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

所以它这返回的是相等0,小于-1,大于1

构造方法无比较器,实现比较器方法

既然Integer实现compare方法就能比较排序,那我对我自己写的Person也实现Comparable接口的方法看看。
Comparable是在java.lang包下的
需要在某个类中直接实现它的compareTo方法。

package SortedMap01;
import java.util.TreeSet;

public class SortedMapTest01 {
    public static void main(String[] args) {
        Person p=new Person(17);
        Person p2=new Person(37);
        Person p3=new Person(92);
        Person p4=new Person(99);
        //System.out.println(p);
        TreeSet<Person> s=new TreeSet<>();
        s.add(p);
        s.add(p2);
        s.add(p3);
        s.add(p4);
        for (Person out:s) {
            System.out.println(out);
        }
    }
}
class Person implements Comparable<Person>{// implements Comparable<Person>
    private int age;

    public Person(int age) {
        this.age = age;
    }

   // @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    //@Override
    public int compareTo(Person o) {//c.compareTo(c2)  c c就是this,c2就是o,c和c2进行比较
        return this.age-o.age;
    }
}

在这里插入图片描述
这里是从小到大排序,如果想从大到小,改成compareTo 那 return改成 o.age-this.age; 即可

好了,现在问题 又来啦,我这里添加的是int类型,当然好比较了,如果是String类型呢?
前面提到String类型有实现Compare接口
所以比较String的时候调用其实现的compareTo方法即可。

package SortedMap01;

import java.util.Scanner;
import java.util.TreeSet;

public class Sort02 {
    public static void main(String[] args) {
        School<String,Integer> s=new School<>("张三",30);
        School<String,Integer> s2=new School<>("李四",23);
        School<String,Integer> s3=new School<>("李四",21);
        School<String,Integer> s4=new School<>("李",30);
        School<String,Integer> s5=new School<>("李四1",23);
        School<String,Integer> s6=new School<>("李四1",23);
        School<String,Integer> s7=new School<>("李四1",26);
        School<String,Integer> s8=new School<>("李四1",29);
        School<String,Integer> s9=new School<>("李四1",33);

        TreeSet<School> t=new TreeSet<>();
        t.add(s);
        t.add(s2);
        t.add(s3);
        t.add(s4);
        t.add(s5);
        t.add(s6);
        t.add(s7);
        t.add(s8);
        t.add(s9);


        for (School x:t) {
            System.out.println(x);
        }
    }
}

class School<E,T> implements Comparable<School>{
    private String name;
    private int age;

    public School(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(School o) {
       /* if(this.age==o.age)//根据年龄排序
            return this.name.compareTo(o.name);
        else
            return this.age-o.age;*/
       /*School{name='李四', age=23}
        School{name='李四1', age=23}
        School{name='李四', age=24}
        School{name='张三', age=30}
        School{name='李', age=30}
        */
       if( (this.name.compareTo(o.name))==0)
        {
           return this.age-o.age;
        }
        else{
           return this.name.compareTo(o.name);
        }
    }

    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

按照名字(字典)排序
在这里插入图片描述

往构造方法中传入一个比较器

构造方法中传入比较器时
需要写一个class 继承java.util包下的Comparator
且它的compare方法中是对两个自定义对象做比较

package SortedMap01;
import java.util.Comparator;
import java.util.TreeSet;

public class SortedMapTest01 {
    public static void main(String[] args) {
        Person p=new Person(17);
        Person p2=new Person(37);
        Person p3=new Person(92);
        Person p4=new Person(99);
        //System.out.println(p);
        TreeSet<Person> s=new TreeSet<>(new PersoncompareTo());
        s.add(p);
        s.add(p2);
        s.add(p3);
        s.add(p4);
        for (Person out:s) {
            System.out.println(out);
        }
    }
}
class Person{// implements Comparable<Person>
    public int age;

    public Person(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
}

//比较器实现的是Comparator  在java.util包下
class PersoncompareTo implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.age-o2.age;
    }
}

在这里插入图片描述
比较器有分Comparable和Comparator
**Comparable接口:**所在类实现这个接口中的compareTo方法
**Comparator接口:**从新定义一个类Compareclass(自定义),实现Comparator接口,并选择泛型为指定类,
重写int compare(T o1, T o2);方法,并且在new一个TreeSet的时候 ,构造器中传入这个自定义类

TreeSet<Person> s=new TreeSet<>(new PersoncompareTo());
//源码:public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

Arrays.sort()的使用

对于一维数组排序

int[] arr1={8,9,6,5,7,9,1,2,9};

A升序

Arrays.sort(arr1)

B降序

Arrays.sort(Integer[] arr,Collections.reverseOrder()); 

要求使用封装类Integer Character

自定义一维数组排序

Arrays.sort(arrInt,new Comparator<Integer>(){
      @Override
      public int compare(Integer o1,Integer o2){
          return (int)o2-o1;
      }
  });

要求使用封装类Integer Character

自定义二维数组排序

Arrays.sort(arrTwo,new Comparator<int[]>(){
   @Override
   public int compare(int[] p1,int[] p2){
       return p1[0]-p2[0];//升序
       //return o2[0]-o1[0];//降序

       /*if(p1[1]>p2[1]){  这种情况适用于 两个数值差值过大的情景下  如超过了int规定数值的范围
           return 1;
       }else if(p1[1] < p2[1]){
           return -1;
       }else{
           return 0;
       }*/
   }

});

前面减后面是升序 ,后面减前面是降序 谁当差值哪个方向就大
如果差值过大,就进行比较 返回 1 -1 0

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值