SortedMap、NavigableMap、TreeMap介绍和使用
SortedMap接口:SortedMap是一个接口,继承自Map接口,它定义了对键值对按照键的自然顺序或自定义顺序进行排序的功能。SortedMap中的键值对是按照键的顺序排列的,因此可以根据键的顺序进行范围查找和遍历操作。SortedMap接口提供了一系列的导航方法和有序操作方法。
NavigableMap接口:NavigableMap是SortedMap接口的子接口,它在SortedMap的基础上增加了一些额外的导航方法,使得对有序键值对的操作更加方便和灵活。NavigableMap接口提供了lowerKey、floorKey、ceilingKey、higherKey等导航方法,以及pollFirstEntry、pollLastEntry等移除并返回最小/最大键值对的方法。
TreeMap类:TreeMap是SortedMap接口的实现类,它使用红黑树数据结构来实现有序映射。TreeMap根据键的自然顺序或自定义比较器对键值对进行排序,并保持键值对的有序性。TreeMap提供了对键值对的插入、查找、删除和范围操作等常用功能。
SortedMap
在实际开发中,我们绝大多数用到HashMap,只有极个别情况下,才会使用其他的Map的拓展集合 。
官方介绍:
进一步提供键的总排序的Map。映射根据其键的自然顺序排序,或者由通常在排序映射创建时提供的Comparator排序。这个顺序在迭代排序映射的集合视图时反映出来(由entrySet、keySet和values方法返回)。
提供了几个额外的操作来利用排序。(这个接口是SortedSet的映射模拟。)插入到排序映射中的所有键都必须实现Comparable接口(或被指定的比较器接受)。此外,所有这样的键必须是相互比较的:k1. compareto (k2)(或comparator.compare(k1, k2))不能对排序映射中的任何键k1和k2抛出ClassCastException。试图违反此限制将导致违规方法或构造函数调用抛出ClassCastException。
注意,如果排序映射要正确实现map接口,那么由排序映射维护的排序(无论是否提供显式比较器)必须与equals保持一致。(参见Comparable接口或Comparator接口了解consistent with equals的精确定义。)这是因为Map接口是根据equals操作定义的,但是排序映射使用它的compareTo(或compare)方法执行所有键比较,因此从排序映射的角度来看,该方法认为相等的两个键是相等的。
树状映射的行为是定义良好的,即使它的顺序与等号不一致;它只是没有遵守Map接口的一般约定。所有通用排序映射实现类都应该提供四个“标准”构造函数。虽然不能通过接口指定必需的构造函数,但不可能强制执行此建议。所有排序映射实现的预期“标准”构造函数是:
- 一个void(无参数)构造函数,它创建一个根据键的自然顺序排序的空排序映射。
- 具有单个Comparator类型参数的构造函数,它创建一个根据指定的比较器排序的空排序映射。
- 具有单个Map类型参数的构造函数,它创建一个具有与其参数相同的键值映射的新映射,并根据键的自然顺序进行排序。
- 具有SortedMap类型的单个参数的构造函数,它创建一个新的排序映射,该映射具有与输入排序映射相同的键值映射和相同的顺序。
注意:一些方法返回具有受限键范围的子映射。这些范围是半开的,也就是说,它们包括低点,但不包括高点(在适用的情况下)。如果需要封闭范围(包括两个端点),并且密钥类型允许计算给定密钥的后继值,则只需请求从lowEndpoint到后继值(highEndpoint)的子范围。
例如,假设m是一个键为字符串的映射。下面的习惯用法获取一个视图,其中包含m中键值在low和high之间的所有键值映射,包括:SortedMap<String, V> sub = m. submap (low, high+"\0");
可以使用类似的技术来生成一个开放范围(不包含端点)。下面的用法获取一个视图,该视图包含m中所有键值在low和high之间且互斥的键值映射:SortedMap<String, V> sub = m. submap (low+"\0", high);
该接口是Java集合框架的成员。
简述
SortedMap就是Java中的一个接口,继承自Map接口,提供了对键值对按照键的自然顺序或者自定义顺序进行排序的功能,SortMap中及那只对是按照键的顺序排序的,因此可以根据键值的顺序进行范围查找和遍历操作。
SortedMap接口的常用实现类是TreeMap,也就是我们标题中的最后一个,使用的是红黑树数据结构来实现有序映射,TreeMap根据键的自然顺序或自定义比较器对键进行排序,并保持键值对的有序性。
SortedMap 示例
public class SortedMapExample {
public static void main(String[] args) {
SortedMap<Integer,String> sortedMap = new TreeMap<>();
sortedMap.put(3,"Apple");
sortedMap.put(1,"Banana");
sortedMap.put(2,"Orange");
System.out.println(sortedMap); //{1=Banana, 2=Orange, 3=Apple}
SortedMap<Integer,String> subMap = sortedMap.subMap(1,3);
System.out.println(subMap); //{1=Banana, 2=Orange}
}
}
我们创建了一个SortedMap对象,使用TreeMap作为实现类。我们向SortedMap中插入了三个键值对,并输出SortedMap的内容,可以看到键值对按照键的自然顺序排列。
我们还使用subMap方法获取了SortedMap的子映射,范围是从键1(包含)到键3(不包含)。输出子映射的内容,可以看到子映射中的键值对也是按照键的顺序排列的。
SortedMap的优缺点
优点:
- 有序性:sortedMap保持键值对的有效性,可以根据键的顺序进行范围查找和遍历操作。
- 提供子映射: SortedMap提供了subMap方法,可以获取原有映射的子映射,方便进行范围操作。
- 可自定义排序:SortedMap可以根据自然顺序或自定义比较器对键进行排序,灵活性较强。
缺点:
- 内存占用:相比于普通的HashMap,SortedMap需要额外的内存来维护有效性,因此可能会占用跟多的内存空间。
- 插入和删除性能略低:由于需要维护有效性,SortedMap在插入和删除元素的时候,相对于普通的HashMap会略微降低性能。
使用场景
- 当需要按照键的顺序进行范围查找或遍历操作时,可以使用SortedMap。
- 当需要根据键的顺序对映射进行排序时,可以使用SortedMap。
- 当需要获取子映射进行范围操作时,可以使用SortedMap。
NavigableMap
官方介绍
SortedMap扩展了导航方法,返回给定搜索目标的最接近匹配项。方法lowerEntry, floorEntry, ceilingEntry, higherEntry返回Map。与键相关联的条目对象分别小于、小于或等于、大于或等于和大于给定键,如果没有这样的键则返回null。类似地,方法lowerKey、floorKey、ceilingKey和higherKey只返回关联的键。所有这些方法都是为定位而设计的,而不是遍历条目。
NavigableMap可以按升序或降序键来访问和遍历。descendingMap方法返回地图的视图,其中所有关系方法和方向方法的含义颠倒。升序操作和视图的性能可能比降序操作和视图的性能快。方法subMap、headMap和tailMap与同名的SortedMap方法的不同之处在于,它们接受描述下界和上界是包含还是排斥的附加参数。
任何NavigableMap的子映射都必须实现NavigableMap接口。该接口还定义了方法firstEntry、pollFirstEntry、lastEntry和pollLastEntry,它们返回或删除最小和最大映射(如果存在的话),否则返回null。入口返回方法的实现期望返回Map。条目对表示生成映射时的快照,因此通常不支持可选的条目。setValue方法。但是请注意,可以使用put方法更改关联映射中的映射。方法subMap(K, K), headMap(K)和tailMap(K)被指定返回SortedMap,以允许SortedMap的现有实现被兼容地改造以实现NavigableMap,但鼓励此接口的扩展和实现覆盖这些方法以返回NavigableMap。类似地,可以重写keySet()以返回NavigableSet。该接口是Java集合框架的成员。
简述
在Java中,NavigableMap是SortedMap接口的子接口,它提供了一系列用于导航和操作有序键值对的方法。NavigableMap在SortedMap的基础上增加了一些额外的导航方法,使得对有序映射的操作更加方便和灵活。
常用的导航方法:
lowerKey(K key)
:返回小于给定键的最大键,如果不存在则返回null。floorKey(K key)
:返回小于等于给定键的最大键,如果不存在则返回null。ceilingKey(K key)
:返回大于等于给定键的最小键,如果不存在则返回null。higherKey(K key)
:返回大于给定键的最小键,如果不存在则返回null。pollFirstEntry()
:移除并返回最小的键值对,如果映射为空则返回null。pollLastEntry()
:移除并返回最大的键值对,如果映射为空则返回null。descendingMap()
:返回一个与原有映射相反顺序的NavigableMap。
NavigableMap的常用实现类是TreeMap,它实现了NavigableMap接口,并使用红黑树数据结构来实现有序映射。通过NavigableMap的导航方法,我们可以方便地进行范围查找、获取最小/最大键值对、移除最小/最大键值对等操作。
示例
public class NavigableMapExample {
public static void main(String[] args) {
NavigableMap<Integer, String> navigableMap = new TreeMap<>();
navigableMap.put(1, "Apple");
navigableMap.put(3, "Banana");
navigableMap.put(5, "Orange");
navigableMap.put(7, "Grapes");
System.out.println(navigableMap); // 输出:{1=Apple, 3=Banana, 5=Orange, 7=Grapes}
System.out.println(navigableMap.lowerKey(4)); // 输出:3
System.out.println(navigableMap.floorKey(4)); // 输出:3
System.out.println(navigableMap.ceilingKey(4)); // 输出:5
System.out.println(navigableMap.higherKey(4)); // 输出:5
System.out.println(navigableMap.pollFirstEntry()); // 输出:1=Apple
System.out.println(navigableMap.pollLastEntry()); // 输出:7=Grapes
System.out.println(navigableMap.descendingMap()); // 输出:{5=Orange, 3=Banana}
}
}
output:
{1=Apple, 3=Banana, 5=Orange, 7=Grapes}
3
3
5
5
1=Apple 7=Grapes
{5=Orange, 3=Banana}
我们创建了一个NavigableMap对象,使用TreeMap作为实现类。我们向NavigableMap中插入了四个键值对,并输出NavigableMap的内容。
然后,我们使用NavigableMap的导航方法进行范围查找和获取最小/最大键值对的操作。我们还使用pollFirstEntry和pollLastEntry方法移除并返回最小/最大的键值对。最后,我们使用descendingMap方法获取与原有映射相反顺序的NavigableMap。
优缺点和使用场景
优点
-
导航功能:NavigableMap提供了一系列导航方法,如lowerKey、floorKey、ceilingKey、higherKey等,使得对有序键值对的范围查找和导航操作更加方便和灵活。
-
有序性:NavigableMap保持键值对的有序性,可以根据键的顺序进行范围查找、遍历和操作。
-
提供子映射:NavigableMap提供了subMap、headMap和tailMap等方法,可以获取原有映射的子映射,方便进行范围操作。
-
可自定义排序:NavigableMap可以根据自然顺序或自定义比较器对键进行排序,灵活性较高。
缺点
-
内存占用:相比于普通的HashMap,NavigableMap需要额外的内存来维护有序性,因此可能占用更多的内存空间。
-
插入和删除性能略低:由于需要维护有序性,NavigableMap在插入和删除元素时,相对于普通的HashMap会略微降低性能。
使用场景
- 当需要对有序键值对进行范围查找、遍历和操作时,可以使用NavigableMap。
- 当需要获取最小/最大键值对或根据键的顺序进行导航操作时,可以使用NavigableMap。
- 当需要获取子映射进行范围操作时,可以使用NavigableMap。
TreeMap
官方介绍
一个基于红黑树的NavigableMap实现。根据键的自然顺序或在创建映射时提供的Comparator对映射进行排序,这取决于使用的是哪个构造函数。这个实现为containsKey、get、put和remove操作提供了保证的log(n)时间成本。算法改编自Cormen、Leiserson和Rivest的《算法导论》。
请注意,如果这个排序映射要正确实现map接口,那么树状映射所维护的排序(与任何排序映射一样)以及是否提供显式比较器都必须与equals一致。(参见Comparable或Comparator对consistent with equals的精确定义。)这是因为Map接口是根据equals操作定义的,但是排序映射使用它的compareTo(或compare)方法执行所有键比较,因此从排序映射的角度来看,该方法认为相等的两个键是相等的。排序映射的行为是定义良好的,即使它的排序与等号不一致;它只是没有遵守Map接口的一般约定。
注意,这个实现是不同步的。如果多个线程并发地访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。(结构修改是添加或删除一个或多个映射的任何操作;仅仅改变与现有键相关联的值不是结构修改。)这通常是通过对一些自然封装映射的对象进行同步来完成的。
如果不存在这样的对象,则应该使用集合对映射进行“包装”。synchronizedSortedMap方法。这最好在创建时完成,以防止意外地对映射进行非同步访问:SortedMap m = Collections。synchronizedSortedMap(新TreeMap(…));这个类的所有“集合视图方法”返回的集合的迭代器方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时间,以除通过迭代器自己的remove方法之外的任何方式修改映射,迭代器将抛出ConcurrentModificationException。
因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意的、不确定的行为的风险。
请注意,不能保证迭代器的快速故障行为,因为一般来说,在存在非同步并发修改的情况下不可能做出任何硬保证。快速失败迭代器在尽最大努力的基础上抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误。所有的地图。该类及其视图中的方法返回的条目对表示生成映射时的快照。他们不支持入盟。setValue方法。(但是请注意,可以使用put更改关联映射中的映射。)
简述
在Java中,TreeMap是SortedMap接口的实现类,它基于红黑树数据结构实现了有序映射。TreeMap根据键的自然顺序或自定义比较器对键值对进行排序,并保持键值对的有序性。
TreeMap的特点和使用方式如下:
- 有序性:TreeMap保持键值对的有序性,可以根据键值的顺序进行范围查找、遍历和操作。
- 自然顺序或自定义比较器:TreeMap可以很久键值的自然顺序(如果键实现了Comparable 接口) 或自定义比较器对键进行排序。
- 快速查找: 用于使用红黑树作为底层数据结构,TreeMap具有快速查找性能,时间复杂度为O(log n)。
- 提供子映射:TreeMap提供了subMap、headMap、tailMap等方法,可以获取原有映射的子映射,方便进行范围操作。
- 不允许为null键: 由于TreeMap是基于键的有序性进行排序的,所以不允许使用null键,但允许使用null值。
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(3, "Apple");
treeMap.put(1, "Banana");
treeMap.put(2, "Orange");
System.out.println(treeMap); // 输出:{1=Banana, 2=Orange, 3=Apple}
System.out.println(treeMap.get(2)); // 输出:Orange
treeMap.remove(1);
System.out.println(treeMap); // 输出:{2=Orange, 3=Apple}
}
}
在上面的示例中,我们创建了一个TreeMap对象,并向其中插入了三个键值对。由于TreeMap会根据键的自然顺序进行排序,因此输出的键值对按照键的顺序排列。
我们使用get方法获取键为2的值,成功输出"Orange"。然后,我们使用remove方法移除键为1的键值对,并输出剩余的键值对。
输出:
{1=Banana, 2=Orange, 3=Apple}
Orange
{2=Orange, 3=Apple}
通过使用TreeMap,我们可以方便地实现对键值对的有序操作,包括插入、查找、删除等。TreeMap的有序性和快速查找特性使得它在某些场景下比普通的HashMap更加适用。需要根据具体的需求权衡其优缺点,选择合适的数据结构。
TreeMap的优缺点和使用场景
优点:
- 有序性:TreeMap保持键值对的有序性,可以根据键的顺序进行范围查找、遍历和操作。
- 快速查找:由于使用红黑树作为底层数据结构,TreeMap具有快速的查找性能,时间复杂度为O(log n)。
- 提供子映射:TreeMap提供了subMap、headMap和tailMap等方法,可以获取原有映射的子映射,方便进行范围操作。
- 自然顺序或自定义比较器:TreeMap可以根据键的自然顺序(如果键实现了Comparable接口)或自定义比较器对键进行排序。
缺点
- 内存占用:相比于普通的HashMap,TreeMap需要额外的内存来维护有序性,因此可能占用更多的内存空间。
- 插入和删除性能略低:由于需要维护有序性,TreeMap在插入和删除元素时,相对于普通的HashMap会略微降低性能。
使用场景
- 当需要对键值对进行有序操作时,可以使用TreeMap。
- 当需要根据键的顺序进行范围查找、遍历和操作时,可以使用TreeMap。
- 当需要获取最小/最大键值对或根据键的顺序进行导航操作时,可以使用TreeMap。
- 当需要获取子映射进行范围操作时,可以使用TreeMap。
常用方法介绍
- put(K key, V value):将指定的键值对插入到TreeMap中。
- get(Object key):根据键获取对应的值。
- remove(Object key):根据键移除对应的键值对。
- containsKey(Object key):判断TreeMap中是否包含指定的键。
- containsValue(Object value):判断TreeMap中是否包含指定的值。
- size():返回TreeMap中键值对的数量。
- isEmpty():判断TreeMap是否为空。
- clear():清空TreeMap中的所有键值对。
- firstKey():返回TreeMap中的最小键。
- lastKey():返回TreeMap中的最大键。
- lowerKey(K key):返回小于给定键的最大键,如果不存在则返回null。
- floorKey(K key):返回小于等于给定键的最大键,如果不存在则返回null。
- ceilingKey(K key):返回大于等于给定键的最小键,如果不存在则返回null。
- higherKey(K key):返回大于给定键的最小键,如果不存在则返回null。
- subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive):返回指定范围内的子映射。
- headMap(K toKey, boolean inclusive):返回小于给定键的部分子映射。
- tailMap(K fromKey, boolean inclusive):返回大于等于给定键的部分子映射。
- descendingMap():返回一个与原有映射相反顺序的NavigableMap。