这里写目录标题
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