TreeMap

一、TreeeMap简介

在Map集合框架中,除了HashMap以外,TreeMap也是常用到的集合对象之一。
与HashMap相比,TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序。其中,可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序;
不同于HashMap的哈希映射,TreeMap实现了红黑树的结构,形成了一颗二叉树

TreeMap.java
public class TreeMap<K,V>

    extends AbstractMap<K,V>

    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

{

    //implementation

}

总结上图:   NavigableMap就表示红黑树接口

TreeMap继承于AbstractMap,实现了Map, Cloneable, NavigableMap, Serializable接口。
(1)TreeMap 继承于AbstractMap,而AbstractMap实现了Map接口,并实现了Map接口中定义的方法,减少了其子类继承的复杂度;
(2)TreeMap 实现了Map接口,成为Map框架中的一员,可以包含着key-value形式的元素;
(3)TreeMap 实现了NavigableMap接口红黑树,意味着拥有了更强的元素搜索能力;映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
(4)TreeMap 实现了Cloneable接口,实现了clone()方法,可以被克隆;
(5)TreeMap 实现了Java.io.Serializable接口,支持序列化操作;

(6) 它不同步。用于Collections.synchronizedSortedMap(new TreeMap())在并发环境中工作。

HashMap和TreeMap的两个map都不同步,程序员需要管理地图上的并发访问。

我们可以使用Collections.synchronizedSortedMap(new TreeMap())显式获取树图的同步视图。

Map<Integer, String> syncTreeMap = 
        Collections.synchronizedSortedMap(new TreeMap<Integer, String>()); 

syncTreeMap.put(1,  "A");
syncTreeMap.put(2,  "B" );
syncTreeMap.put(3,  "C");

二、TreeMap具有如下特点:


不允许出现重复的key;
可以插入null键,null值;
可以对元素进行排序;
无序集合(插入和遍历顺序不一致);

实现了红黑树:  每个元素都有一个color属性, true表示黑色,false表示红色;

两个相邻接节点颜色为红色并且树不平衡就要旋转树结构。  (根节点肯定是黑色)

三、TreeMap基本操作

public class TreeMapTest {
    public static void main(String[] agrs){
        //创建TreeMap对象:
        TreeMap<String,Integer> treeMap = new TreeMap<String,Integer>();
        System.out.println("初始化后,TreeMap元素个数为:" + treeMap.size());
 
        //新增元素:
        treeMap.put("hello",1);
        treeMap.put("world",2);
        treeMap.put("my",3);
        treeMap.put("name",4);
        treeMap.put("is",5);
        treeMap.put("huangqiuping",6);
        treeMap.put("i",6);
        treeMap.put("am",6);
        treeMap.put("a",6);
        treeMap.put("developer",6);
        System.out.println("添加元素后,TreeMap元素个数为:" + treeMap.size());
 
        //遍历元素:
        Set<Map.Entry<String,Integer>> entrySet = treeMap.entrySet();
        for(Map.Entry<String,Integer> entry : entrySet){
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println("TreeMap元素的key:"+key+",value:"+value);
        }
 
        //获取所有的key:
        Set<String> keySet = treeMap.keySet();
        for(String strKey:keySet){
            System.out.println("TreeMap集合中的key:"+strKey);
        }
 
        //获取所有的value:
        Collection<Integer> valueList = treeMap.values();
        for(Integer intValue:valueList){
            System.out.println("TreeMap集合中的value:" + intValue);
        }
 
        //获取元素:
        //获取集合内元素key为"huangqiuping"的值
        Integer getValue = treeMap.get("huangqiuping");
        //获取集合内第一个元素
        String firstKey = treeMap.firstKey();
        //获取集合内最后一个元素
        String lastKey =treeMap.lastKey();
        //获取集合内的key小于"huangqiuping"的key
        String lowerKey =treeMap.lowerKey("huangqiuping");
        //获取集合内的key大于等于"huangqiuping"的key
        String ceilingKey =treeMap.ceilingKey("huangqiuping");
        //获取集合的key从"a"到"huangqiuping"的元素
        SortedMap<String,Integer> sortedMap =treeMap.subMap("a","my");
 
        //删除元素:
        //删除集合中key为"huangqiuping"的元素
        Integer removeValue = treeMap.remove("huangqiuping");
        //清空集合元素:
        treeMap.clear(); 
 
        //判断方法:
        //判断集合是否为空
        boolean isEmpty = treeMap.isEmpty();
        //判断集合的key中是否包含"huangqiuping"
        boolean isContain = treeMap.containsKey("huangqiuping");
    }
}

TreeMap排序

(1)使用元素自然排序
在使用自然顺序排序时候,需要区分两种情况:一种是Jdk定义的对象,一种是自己定义的对象;

public class SortedTest implements Comparable<SortedTest> {
    private int age;
    public SortedTest(int age){
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //自定义对象,实现compareTo(T o)方法:
    public int compareTo(SortedTest sortedTest) {
        int num = this.age - sortedTest.getAge();
        //为0时候,两者相同:
        if(num==0){
            return 0;
        //大于0时,传入的参数小:
        }else if(num>0){
            return 1;
        //小于0时,传入的参数大:
        }else{
            return -1;
        }
    }
}
 
public class TreeMapTest {
    public static void main(String[] agrs){
        //自然顺序比较
        naturalSort();
    }
     //自然排序顺序:
    public static void naturalSort(){
        //第一种情况:Integer对象
        TreeMap<Integer,String> treeMapFirst = new TreeMap<Integer, String>();
        treeMapFirst.put(1,"huangqiuping");
        treeMapFirst.put(6,"huangqiuping");
        treeMapFirst.put(3,"huangqiuping");
        treeMapFirst.put(10,"huangqiuping");
        treeMapFirst.put(7,"huangqiuping");
        treeMapFirst.put(13,"huangqiuping");
        System.out.println(treeMapFirst.toString());
 
        //第二种情况:SortedTest对象
        TreeMap<SortedTest,String> treeMapSecond = new TreeMap<SortedTest, String>();
        treeMapSecond.put(new SortedTest(10),"huangqiuping");
        treeMapSecond.put(new SortedTest(1),"huangqiuping");
        treeMapSecond.put(new SortedTest(13),"huangqiuping");
        treeMapSecond.put(new SortedTest(4),"huangqiuping");
        treeMapSecond.put(new SortedTest(0),"huangqiuping");
        treeMapSecond.put(new SortedTest(9),"huangqiuping");
        System.out.println(treeMapSecond.toString());
    }
}

在自然顺序比较中,需要让被比较的元素实现Comparable接口,否则在向集合里添加元素时报:"java.lang.ClassCastException: com.huangqiuping.collection.map.SortedTest cannot be cast to java.lang.Comparable"异常;

这是因为在调用put()方法时,会将传入的元素转化成Comparable类型对象,所以当你传入的元素没有实现Comparable接口时,就无法转换,遍会报错;

(2)使用自定义比较器排序

使用自定义比较器排序,需要在创建TreeMap对象时,将自定义比较器对象传入到TreeMap构造方法中;

自定义比较器对象,需要实现Comparator接口,并实现比较方法compare(To1,To2);

使用自定义比较器排序的话,被比较的对象无需再实现Comparable接口了;

public class SortedTest {
    private int age;
    public SortedTest(int age){
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class SortedTestComparator implements Comparator<SortedTest> {
    //自定义比较器:实现compare(To1,To2)方法:
    public int compare(SortedTest sortedTest1, SortedTest sortedTest2) {
        int num = sortedTest1.getAge() - sortedTest2.getAge();
        if(num==0){//为0时候,两者相同:
            return 0;
        }else if(num>0){//大于0时,后面的参数小:
            return 1;
        }else{//小于0时,前面的参数小:
            return -1;
        }
    }
}

TreeMap常用方法

我们应该学习的关于TreeMap的重要方法如下:

  1. void clear():它从地图中删除所有键值对。
  2. void size():返回此映射中存在的键值对的数量。
  3. void isEmpty():如果此映射不包含键 - 值映射,则返回true。
  4. boolean containsKey(Object key):'true'如果地图中存在指定的键,则返回。
  5. 布尔的containsValue(对象键):它返回'true'如果一个指定的值被映射到地图上的至少一个键。
  6. Object get(Object key):它检索value指定的映射key,如果此映射不包含键的映射,则返回null。
  7. Object remove(Object key):它从地图中删除指定键的键值对(如果存在)。
  8. 比较器比较器():它返回用于对此映射中的键进行排序的比较器,如果此映射使用其键的自然顺序,则返回null。
  9. Object firstKey():它返回树映射中当前的第一个(最少)键。
  10. Object lastKey():它返回树映射中当前的最后一个(最大)键。
  11. Object ceilingKey(Object key):返回大于或等于给定键的最小键,如果没有这样的键则返回null。
  12. Object higherKey(Object key):返回严格大于指定键的最小键。
  13. NavigableMap descendingMap():它返回此映射中包含的映射的逆序视图

四、TreeMap有五种类型的构造函数:

  1. TreeMap():使用其键的自然顺序创建一个新的空树图。
  2. TreeMap(比较器c):创建一个新的空树图,根据给定的比较器排序。
  3. TreeMap(地图):创建一个新的树图,其中包含与给定地图相同的映射,根据其键的自然顺序排序。
  4. TreeMap(SortedMap map):创建一个新的树图,其中包含相同的映射并使用与指定的有序映射相同的顺序

五、 TreeMap用例

无论是使用默认排序还是使用比较器自定义排序,TreeMap都提供了一种有效的方法来以排序的方式存储和检索其中包含的信息。这使得它成为在需要按排序顺序显示信息的场景中使用的出色工具。例如,员工信息基于他们在任何移动应用程序中的年龄或电话号码。

另一个有用的用例可以是字典,其中信息以分类的方式被记录和显示。

实际上,它们对于需要对信息进行排序以及需要快速随机访问的任何地方都很有用。如果不需要随机访问,则使用有序集或列表。

六、TreeMap性能

TreeMap 为大多数操作提供log(n)的性能,如add(),remove()和contains()。对于相同的操作,HashMap以恒定时间性能O(1)执行。这样,HashMap比TreeMap表现更好。

TreeMap在内存管理方面具有更好的性能,因为它不在内部维护一个数组来存储键值对。在HashMap中,数组大小是在初始化或调整大小时确定的,如果当时通常需要的话。它浪费了记忆。TreeMap没有这样的问题。

-------------------------------------------------------------------------------------

zhaoyq 2022-03-03

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值