Java:Map(四)——传入Comparator对Key排序:TreeMap

对Key进行排序的Map:java.util.TreeMap

有一种Map,它在内部会对Key进行排序,这类Map称之为SortedMap。不过SortedMap接口,它的实现类TreeMap

 SortedMap遍历时以Key的顺序来进行排序。

例如,放入的Key是"apple"、"pear"、"orange",遍历的顺序一定是"apple"、"orange"、"pear",因为String默认按字母排序

复制代码
public class Main {
    public static void main(String[] args) {
        Map<String,Integer> map = new TreeMap<>();
        map.put("orange",1);
        map.put("apple",2);
        map.put("pear",3);
        for(String str : map.keySet())
            System.out.println(str);
    }
}

apple
orange
pear
复制代码

使用TreeMap时,Key必须实现Comparable接口,String、Integer这些类已经实现了这个接口,因此可以直接作为Key。而Value却没有任何要求。

如果作为Keyclass没有实现Comparable接口,那么在创建TreeMap时同时指定一个自定义排序算法

一个例子

复制代码
Map <Person , Integer> map =new TreeMap <> (
    new Comparator<Person> () {
        public int compare(Person p1 , Person p2)
            return p1.name.compareTo(p2.name);
    }
);

map.put(new Person("Tom"),1);
map.put(new Person("Bob"),3);
map.put(new Person("Lily"),2);
for (Person key : map.keySet()) {
System.out.println(key);
}
// {Person: Bob}, {Person: Lily}, {Person: Tom}
System.out.println(map.get(new Person("Bob"))); // 2
复制代码

 例如上述代码中,注意到Comparator接口要求实现一个compare()方法,它负责比较传入的两个元素a、b

  • a<b则返回负数,通常是-1
  • a=b则返回0
  • a>b返回正数,通常是1

TreeMap内部根据比较结果对Key进行排序。

从上述代码执行结果可知,打印的Key确实是按照Comparator定义的顺序排序的。如果要根据Key查找Value,我们可以传入一个new Person( "Bob" )作为Key,它会返回对应的Integer2

另外,注意到Person并未覆写equals()、hashCode(),因为TreeMap不使用equals()、hashCode()

另一个例子

我们定义一个Student类,根据score进行排序,高分在前:

复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<Student, Integer> map = new TreeMap<>(
                new Comparator<Student>() {
                    public int compare(Student p1, Student p2){ 
                        return p1.score > p2.score ? 1 : -1;
            } } ); map.put(
new Student("Tom",77),1); map.put(new Student("Bob",61),2); map.put(new Student("Lily",99),3); for(Student key : map.keySet()) System.out.println(key); System.out.println(map.get(new Student("Bob",61))); } } class Student { public String name; public int score; Student(String name, int score) { this.name = name; this.score = score; } public String toString() { return String.format("{%s: score=%d}", name, score); } }
复制代码

运行结果:

{Bob: score=61}
{Tom: score=77}
{Lily: score=99}
null

for循环中,我们确实得到了按score排序的结果。但是根据相同Key查询时,结果却为null

原因在于,构建cmparator必须严格遵守正、负、0的规则,而在上文我们却没有实现0,即两个值相等

修改

复制代码
Map<Student, Integer> map = new TreeMap<>(
        new Comparator<Student>() {
            public int compare(Student p1, Student p2) {
                if (p1.score==p2.score)
                    return 0;
                return p1.score > p2.score ? 1 : -1;
            }
        }
);
复制代码

或者直接借助Integer.compare( int , int )也能返回正确的比较结果:

public int compare(Student p1 , Student p2){
    return Integer.compare(p1.score,p2.score);
}

小结

  • SortedMap遍历时根据Key的顺序遍历,最常用的实现类是TreeMap
  • 作为SortedMapKey必须实现Comparable接口,或者传入Comparator;这个Comparator决定了如何对Key进行排序;
  • 要严格按照compare()规范实现比较逻辑返回0、正、负,否则,TreeMap不会正常工作。

 

posted @   ShineLe  阅读(351)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示