Java集合框架:TreeMap

TreeMap定义

package java.util;
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
}
public interface NavigableMap<K,V> extends SortedMap<K,V>{}

  TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。
  TreeMap中同时也包含了如下几个重要的属性:

//比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制
private final Comparator<? super K> comparator;
//TreeMap红-黑节点,为TreeMap的内部类
private transient Entry<K,V> root = null;
//容器大小
private transient int size = 0;
//TreeMap修改次数
private transient int modCount = 0;
//红黑树的节点颜色–红色
private static final boolean RED = false;
//红黑树的节点颜色–黑色
private static final boolean BLACK = true;

  对于实体节点Entry是TreeMap的内部类,它有几个重要的属性:

//键
K key;
//值
V value;
//左孩子
Entry<K,V> left = null;
//右孩子
Entry<K,V> right = null;
//父亲
Entry<K,V> parent;
//颜色
boolean color = BLACK;

  关于红黑树的实现可以搜索一些相关资料,我觉得参考资料3就不错,博主就不赘述了。


TreeMap特点

  1. TreeMap是非线程安全的。
    可以采用这种方式将TreeMap设置为同步的:Map m = Collections.synchronizedSortedMap(new TreeMap(…));
  2. TreeMap是用键来进行升序顺序来排序的。通过Comparable 或 Comparator来排序
    TreeMap是SortedMap接口的基于红黑树的实现。此类保证了映射按照升序顺序排列关键字, 根据使用的构造方法不同,可能会按照键的类的自然顺序进行排序,或者按照创建时所提供的比较器(自定义)进行排序。
    先举个案例说明一下:
Map<Integer,Integer> map = new TreeMap<>();
        map.put(1, null);
        map.put(10, 1);
        map.put(3, 2);
        map.put(2, 3);
//        map.put(null, 3);

        for(Entry<Integer, Integer> entry:map.entrySet())
        {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

  输出结果:

1:null
2:3
3:2
10:1

  也可以采用自定义的类,引用《Comparable与Comparator浅析》中的Person1举例:

public class Person1 implements Comparable<Person1>
{
    private int age;
    private String name;

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

    @Override
    public int compareTo(Person1 o)
    {
        return this.age-o.age;
    }

    @Override
    public String toString()
    {
        return name+":"+age;
    }
}

   测试代码:

  Map<Person1,Integer> map = new TreeMap<>();
        Person1 person1 = new Person1("zzh",18);
        Person1 person2 = new Person1("jj",17);
        Person1 person3 = new Person1("qq",19);
        map.put(person1, 1);
        map.put(person2, 2);
        map.put(person3, 3);
        for(Entry<Person1, Integer> entry:map.entrySet())
        {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

  测试结果:

jj:17:2
zzh:18:1
qq:19:3

  只要自定义键的类实现了Comparable接口就可以使用TreeMap的排序功能,也可以通过Comparator接口实现(关于Comparable和Comparator的区别可以翻看《Comparable与Comparator浅析》),如下:
  首先引用类Person2:

public final class Person2
{
    private int age;
    private String name;

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

    @Override
    public String toString()
    {
        return name+":"+age;
    }

    //getter and setter方法省略....
}

  测试代码:

Map<Person2,Integer> map2 = new TreeMap<>(new Comparator<Person2>(){
            @Override
            public int compare(Person2 o1, Person2 o2)
            {
                if(o1 == null || o2 == null)
                    return 0;
                return o1.getAge()-o2.getAge();
            }
        });
        Person2 p1 = new Person2("zzh",18);
        Person2 p2 = new Person2("jj",17);
        Person2 p3 = new Person2("qq",19);
        map2.put(p1, 1);
        map2.put(p2, 2);
        map2.put(p3, 3);
        for(Entry<Person2, Integer> entry:map2.entrySet())
        {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

  输出结果:

 jj:17:2
zzh:18:1
qq:19:3

  可以看到Person2中并没有实现Comparable接口,但是想要和Person1一样能够和TreeMap合作,只需要在创建TreeMap的构造函数中声明一个Comparator接口的实现,譬如上面的例子所示。
3. 由所有此类的“collection 视图方法”所返回的迭代器都是快速失败的
  这点和HashMap一样,所谓快速失败就是在并发集合中,其进行迭代操作时,若有其他线程对其结构性的修改,这是迭代器会立马感知到,并且立刻抛出ConcurrentModificationException异常,而不是等待迭代完成之后才告诉你已经出错。注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。 快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。 因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
4. 和HashMap一样,如果插入重复的元素,后面的元素会覆盖前面的
5. 键不可以为null(如果比较器对null做了处理,就可以为null),但是值可以为null
  如上面的案例中,加入:

    Person2 p4 = new Person2(null,19);
    map2.put(p4, 4);

  在打印map2的时候就不会报错。
6. TreeMap对containsKey、get、put 和 remove 操作提供了保证的 log(n) 时间开销
  TreeMap提供了很多方法方便大小使用,譬如containsKey, get, put,remove,entrySet等Map通用的方法,也包括fisrtEntry, firstKey, cellingKey, lowerKey等方法,由于篇幅较大,不便赘述,使用前最好翻看一下API或者源码熟悉一下。


HashMap与TreeMap的区别

  1. 实现方式
    HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。
    (1)HashMap(): 构建一个空的哈希映像
    (2)HashMap(Map m): 构建一个哈希映像,并且添加映像m的所有映射
    (3)HashMap(int initialCapacity): 构建一个拥有特定容量的空的哈希映像
    (4)HashMap(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的哈希映像
    TreeMap:基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
    (1)TreeMap():构建一个空的映像树
    (2)TreeMap(Map m): 构建一个映像树,并且添加映像m中所有元素
    (3)TreeMap(Comparator c): 构建一个映像树,并且使用特定的比较器对关键字进行排序
    (4)TreeMap(SortedMap s): 构建一个映像树,添加映像树s中所有映射,并且使用与有序映像s相同的比较器排序
  2. 用途
    HashMap:适用于在Map中插入、删除和定位元素。
    TreeMap:适用于按自然顺序或自定义顺序遍历键(key)。
    HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.


参考资料
1. 《Comparable与Comparator浅析
2. 《Java中HashMap和TreeMap的区别深入理解
3. 《Java提高篇(二七)—–TreeMap

时间: 2024-09-27 21:37:35

Java集合框架:TreeMap的相关文章

java集合框架10——TreeMap和源码分析(一)

版权声明:尊重博主原创文章,转载请注明出处哦~http://blog.csdn.net/eson_15/article/details/51217741 目录(?)[+] 前面讨论完了HashMap和HashTable的源码,这一节我们来讨论一下TreeMap.先从整体上把握TreeMap,然后分析其源码,深入剖析TreeMap的实现. 1. TreeMap简介         TreeMap是一个有序的key-value集合,它内部是通过红-黑树实现的,如果对红-黑树不太了解,请先参考下这篇博

Java集合源码剖析:Java集合框架

Java集合工具包位于Java.util包下,包含了很多常用的数据结构,如数组.链表.栈.队列.集合.哈希表等.学习Java集合框架下大致可以分为如下五个部分:List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Arrays.Collections). Java集合类的整体框架如下: 从上图中可以看出,集合类主要分为两大类:Collection和Map. Collection是List.Set等集合高度抽象出来的接口,它包含了这些集合的基本操作,它主

java | 集合框架

集合框架 集合代表了一组对象,Java中的集合框架定义了一套规范,用来表示.操作集合,使具体操作与实现细节解耦. 而这些操作无非就是增.删.改.查! 集合和数组的区别: 1.数组的长度固定,集合长度可变. 2.数组只能存储相同类型的数据(基本类型/引用类型),集合可存储各种类型的数据. Java集合框架接口 Java集合框架的顶层接口包括: 一.Collection接口: 1.实现Collection接口的集合有List.Set.Queue(Java队列实现). 2.List:排列有序,可以有重

[Java] 集合框架的层次结构和使用规则梳理

在Java语言中,Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的类).所有抽象出来的数据结构和操作(算法)统称为Java集合框架(JavaCollectionFramework). Java程序员在具体应用时,不必考虑数据结构和算法实现细节,只需要用这些类创建出来一些对象,然后直接应用就可以了,这样就大大提高了编程效率. 概述 什么是框架?  类库的集合 什么是集合? 存放数据的容器 集合框架用来干什么? 用来表示和操作的统一的架构 集合框架包含了两部分:一

Java集合框架学习总结

<Java集合框架学习总结> 以下介绍经常使用的集合类,这里不介绍集合类的使用方法,只介绍每个集合类的用途和特点,然后通过比较相关集合类的不同特点来让我们更深入的了解它们.   Collection接口 1.Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements). 2.所有实现Collection接口的类都必须提供两个标准的构造函数:1.无参数的构造函数用于创建一个空的Collection,2.Collection

Java集合框架实现自定义排序

Java集合框架针对不同的数据结构提供了多种排序的方法,虽然很多时候我们可以自己实现排序,比如数组等,但是灵活的使用JDK提供的排序方法,可以提高开发效率,而且通常JDK的实现要比自己造的轮子性能更优化. 1.使用Arrays对数组进行排序 Java API对Arrays类的说明是:此类包含用来操作数组(比如排序和搜索)的各种方法. (1)使用Arrays排序 Arrays使用非常简单,直接调用sort()即可: 1 2 3 4 5 6 7 8 9 10 11 int[] arr = new i

Java集合框架:总结

最近博主对于Java集合框架这个系列做了一个整理,主要包括: Map系:HashMap, LinkedHashMap, TreeMap, WeakHashMap, EnumMap; List系:ArrayList, LinkedList, Vector, Stack; Set系:HashSet, LinkedHashSet, TreeSet; 工具类:Collections,Arrays 不过并没有对多线程(ConcurrentHashMap,BlockingQueue等)集合框架进行整理,以后

关于Java集合框架面试题(含答案)下_java

21.HashMap和HashTable有何不同? (1)HashMap允许key和value为null,而HashTable不允许. (2)HashTable是同步的,而HashMap不是.所以HashMap适合单线程环境,HashTable适合多线程环境. (3)在Java1.4中引入了LinkedHashMap,HashMap的一个子类,假如你想要遍历顺序,你很容易从HashMap转向LinkedHashMap,但是HashTable不是这样的,它的顺序是不可预知的. (4)HashMap

java集合框架01——总体框架一览

 Java集合框架是java提供的工具包,在java.util.*中,这个包中包含了常用的数据结构:集合.数组.链表.栈.队列.映射等.java集合框架主要可以分为四个部分:List列表.Set集合.Map映射和工具类(Iterator迭代器.Enumeration枚举类.Arrays和Collections).         java集合框架示意图如下:     从图中可以看出,java中集合框架有两条分支:Collection和Map.     1. Collection是一个接口,它包含

详谈java集合框架_java

1.为什么使用集合框架 当我们并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象--可以使用Java集合框架 2.Java集合框架包含的内容 接口:(父类)Collection接口下包含List(子类 )接口和Set(子类) 接口 List接口下又包含(ArrayList集合实现类和LinkedList集合实现类) Set接口下又包含(HashSet集合实现类和TreeSet集合实现类) 接口:(父类)Map接口下包含(HashMap集合实现类和TreeMap 集合实现类) *Coll