TreeMap 集合
- 1. 概述
- 2. 方法
- 3. 遍历方式
- 4. 排序方式
- 5. 代码示例1
- 6. 代码示例2
- 7. 代码示例3
- 8. 注意事项
其他集合类
父类 Map
集合类的遍历方式
TreeSet 集合
具体信息请查看 API 帮助文档
1. 概述
TreeMap 是 Java 中的一个集合类,它实现了 SortedMap 接口。它是基于红黑树的数据结构实现的,它能够保持其中的元素处于有序状态。
-
TreeMap 集合中的元素是以键值对的形式存储的,其中的键用于排序和唯一性的保证,而值则用于存储具体的数据。
-
TreeMap 根据键的自然顺序或者自定义的比较器来进行排序,使得在遍历 TreeMap 集合时能够有序地访问其中的元素。
TreeMap 集合的特点:
-
TreeMap 中的键必须是可比较的,要么实现了 Comparable 接口,要么在构造 TreeMap 时提供了自定义的比较器。
-
TreeMap 中的键是唯一的,不允许重复的键存在。
-
TreeMap 是基于红黑树实现的,因此在插入、删除和查找操作的时间复杂度均为 O(logn),具有较高的效率。
-
TreeMap 中的元素是有序的,可以根据键来进行排序。
-
TreeMap 不是线程安全的,如果需要在多线程环境下使用,需要进行额外的同步处理。
2. 方法
TreeMap
集合是Map
集合的子类,因此Map
集合的方法TreeMap
集合都能使用。
Map集合
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
3. 遍历方式
与共有的 集合遍历方式 一样
4. 排序方式
TreeMap
集合和TreeSet
集合一样,底层都是红黑树,因此排序方式一样
TreeSet 集合排序方式详解
-
默认排序规则/自然排序
-
比较器排序
5. 代码示例1
- 代码示例
需求:键:整数表示id;值:字符串表示商品名称
要求:按照id的升序排列,按照id的降序排列
package text.text02;
/*TreeMap基本应用:
需求:键:整数表示id值:字符串表示商品名称
要求:按照id的升序排列,按照id的降序排列
*/import java.util.Comparator;
import java.util.TreeMap;public class text52 {public static void main(String[] args) {//自然排序(升序排列)System.out.println("方法一:自然排序");method1(); //{1001=平板, 1002=汽车, 1003=手机, 1004=飞机, 1005=电脑}//比较器排序(降序排列)System.out.println("方法二:比较器排序");method2(); //{1005=电脑, 1004=飞机, 1003=手机, 1002=汽车, 1001=平板}}//自然排序(Java底层默认的自然排序就是按照升序排列)public static void method1() {//创建集合并添加数据TreeMap<Integer, String> tm = new TreeMap<>();tm.put(1003, "手机");tm.put(1005, "电脑");tm.put(1001, "平板");tm.put(1002, "汽车");tm.put(1004, "飞机");System.out.println(tm);}//比较器排序(当Java底层默认的自然排列不能满足需求时,采用比较器排列)public static void method2() {//创建集合(在创建对象的时候指定比较器规则)TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});//添加数据tm.put(1003, "手机");tm.put(1005, "电脑");tm.put(1001, "平板");tm.put(1002, "汽车");tm.put(1004, "飞机");System.out.println(tm);}
}
- 输出结果
-
方法一:自然排序
-
方法二:比较器排序
-
6. 代码示例2
- 代码示例
需求:键:学生对象;值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人
package text.text02;import java.util.*;/*
需求:键:学生对象值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人*/
public class text53 {public static void main(String[] args) {//自然排序System.out.println("方法一:自然排序");method1();//比较器排序System.out.println("方法二:比较器排序");method2();}//自然排序 (Java底层默认的自然排序就是按照升序排列,自定义对象时,需要在Javabean类中实现Comparable接口并重写里面的CompareTo方法)public static void method1() {//创建学生对象Student8 student1 = new Student8("zhangsan", 10);Student8 student2 = new Student8("lisi", 10);Student8 student3 = new Student8("wangwu", 11);Student8 student4 = new Student8("liubei", 9);Student8 student5 = new Student8("guanyu", 13);Student8 student6 = new Student8("guanyu", 13);//创建集合对象TreeMap<Student8, String> tm = new TreeMap<>();//添加数据tm.put(student1, "陕西");tm.put(student2, "湖南");tm.put(student3, "河北");tm.put(student4, "江苏");tm.put(student5, "北京");tm.put(student6, "湖南");//遍历输出集合Set<Map.Entry<Student8, String>> entries = tm.entrySet();for (Map.Entry<Student8, String> entry : entries) {Student8 key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);}}//比较器排序(当Java底层默认的自然排列不能满足需求时,采用比较器排列,在创建对象时,指定比较规则)public static void method2() {//创建学生对象Student8 student1 = new Student8("zhangsan", 10);Student8 student2 = new Student8("lisi", 10);Student8 student3 = new Student8("wangwu", 11);Student8 student4 = new Student8("liubei", 9);Student8 student5 = new Student8("guanyu", 13);Student8 student6 = new Student8("guanyu", 13);//创建集合对象TreeMap<Student8, String> tm = new TreeMap<>(new Comparator<Student8>() {@Override//按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人public int compare(Student8 o1, Student8 o2) {//o1:表示当前要添加的元素//o2:表示已经在红黑树存在的元素//返回值://负数:表示当前要添加的数据是小的,存左边//正数:表示当前要添加的数据是大的,存右边//0:表示当前要添加的元素已经存在,舍弃int i = o1.getAge() - o2.getAge();i = i == 0 ? o1.getName().compareTo(o2.getName()) : i;return i;}});//添加数据tm.put(student1, "陕西");tm.put(student2, "湖南");tm.put(student3, "河北");tm.put(student4, "江苏");tm.put(student5, "北京");tm.put(student6, "湖南");//遍历输出集合Set<Map.Entry<Student8, String>> entries = tm.entrySet();for (Map.Entry<Student8, String> entry : entries) {Student8 key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);}}
}//学生对象
class Student8 implements Comparable<Student8> {private String name;private int age;public Student8() {}public Student8(String name, int age) {this.name = name;this.age = age;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student8 student8 = (Student8) o;return age == student8.age && Objects.equals(name, student8.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}public String toString() {return "Student8{name = " + name + ", age = " + age + "}";}@Override//按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人public int compareTo(Student8 o) {//this:表示当前要添加的元素//o:表示已经在红黑树中的元素//返回值://负数:表示当前要添加的数据是小的,存左边//正数:表示当前要添加的数据是大的,存右边//0:表示当前要添加的元素已经存在,舍弃int i = this.getAge() - o.getAge();i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
- 输出结果
-
方法一:自然排序
-
方法二:比较器排序
-
7. 代码示例3
- 代码示例
统计个数:
需求:字符串“aababcabcdabcde”,请统计字符串中每一个字符出现的次数,并按照如下格式输出。
输出结果:a(5)b(4)c(3)d(2)e(1)
package text.text02;import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeMap;/*
统计个数:
需求:字符串“aababcabcdabcde”,请统计字符串中每一个字符出现的次数,并按照如下格式输出。输出结果:a(5)b(4)c(3)d(2)e(1)新的统计思想:利用Map集合进行统计 (键:表示要统计的内容;值:表示次数)如果题目中没有要求对结果进行排序,默认使用HashMap如果题目中要求对结果进行排序,则使用TreeMap*/
public class text54 {public static void main(String[] args) {//创建数组存储每一个字符char[] arr = {'a', 'b', 'c', 'd', 'e'};//定义一个变量用于记录字符串String str = "aababcabcdabcde";//创建集合TreeMap<Character, Integer> tm = new TreeMap<>();for (int i = 0; i < str.length(); i++) {//如果双列集合中存在该字符,则获取双列集合中该字符的次数并将次数+1if (tm.containsKey(str.charAt(i))) {//获取双列集合中该字符的次数Integer value = tm.get(str.charAt(i));//将次数+1value++;//用新次数覆盖原次数tm.put(str.charAt(i), value);}//如果双列集合中存在该字符,则添加该字符并将次数改为1else {tm.put(str.charAt(i), 1);}}//遍历集合//1.利用StringBuilder修改输出格式//创建StringBuilder对象StringBuilder sb = new StringBuilder();Set<Map.Entry<Character, Integer>> entries = tm.entrySet();for (Map.Entry<Character, Integer> entry : entries) {//获取集合里的键Character key = entry.getKey();//获取集合里的值Integer value = entry.getValue();//将数据按照需求格式添加进StringBuilder集合sb.append(key).append("(").append(value).append(")");}System.out.println("1.利用StringBuilder修改输出格式:");System.out.println(sb); //a(5)b(4)c(3)d(2)e(1)//2.利用StringJoiner修改输出格式//创建StringJoiner对象StringJoiner sj = new StringJoiner("", "", "");Set<Character> set = tm.keySet();for (Character key : set) {Integer value = tm.get(key);//将数据按照需求格式添加进StringJoiner集合sj.add(key + "").add("(").add(value + "").add(")");//+" "是为了将key和value转换成字符串}System.out.println("2.利用StringJoiner修改输出格式:");System.out.println(sj); //a(5)b(4)c(3)d(2)e(1)}
}
- 输出结果
-
1.利用StringBuilder修改输出格式:
-
2.利用StringJoiner修改输出格式:
-
8. 注意事项
-
键的唯一性:TreeMap 中的键是唯一的,不允许重复的键存在。如果尝试插入一个已经存在的键,新的值将会覆盖旧的值。如果需要存储允许重复键的情况,可以考虑使用其他集合类如 ArrayList 或者 HashMap。
-
键的可比较性:TreeMap 要求集合中的键必须是可比较的,要么实现了 Comparable 接口,要么在构造 TreeMap 时提供了自定义的比较器。如果键没有实现 Comparable 接口,并且没有提供自定义的比较器,则在插入元素或者进行比较操作时会抛出 ClassCastException 异常。
-
线程安全性:TreeMap 不是线程安全的,如果需要在多线程环境下使用 TreeMap,需要进行额外的同步处理。可以考虑使用 Collections 类的 synchronizedSortedMap 方法包装 TreeMap,或者使用并发集合类如 ConcurrentHashMap。
-
迭代顺序:TreeMap 中的元素是有序的,可以根据键来进行排序。通过 iterator 或者 forEach 遍历 TreeMap 时,元素会按照键的顺序以升序进行遍历。
-
性能开销:由于 TreeMap 的底层是红黑树,插入、删除和查找操作的时间复杂度均为 O(logn),相比于其他集合类可能会有较高的性能开销。如果对性能有较高要求,可以考虑使用其他集合类。