TreeMap
TreeMap的原理
TreeMap是一个有序的key-value集合,基于红黑树的 Navigable 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator 进行排序
红黑树
- 根节点是黑色
- 每个节点都只能是红色或者黑色
- 每个叶节点(NIL节点,空节点)是黑色的。
- 如果一个节点是红色的,则它两个子节点都是黑色的,也就是说在一条路径上不能出现两个红色的节点。
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
- TreeMap存储 Key-Value对时,需要根据Key对key-value对进行排序。TreeMap可以保证所有的Key-Value对处于有序状态
- TreeMap的Key的排序:TreeSet集合默认会进行排序。因此必须有排序,如果没有就会报类型转换异常。
package org.lanqiao.treemap.demo;
public class Student implements Comparable{
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
// 先根据年龄进行排序,如果年龄相同,则使用姓名进行排序
Student st = (Student)o;
int res = this.getAge().compareTo(st.getAge());
if(res == 0 ) {
res = this.getName().compareTo(st.getName());
}
return res;
}
}
package org.lanqiao.treemap.demo;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
Map map = new TreeMap();
/*map.put(2, "aa");
map.put(4, "aa");
map.put(6, "aa");
map.put(3, "aa");
map.put(1, "aa");
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
Map.Entry me = (Map.Entry)obj;
Object key = me.getKey();
Object value = me.getValue();
System.out.println(key+"---"+value);
}*/
/*map.put("b", "张三");
map.put("d", "张三");
map.put("e", "张三");
map.put("c", "张三");
map.put("a", "张三");
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
Map.Entry me = (Map.Entry)obj;
Object key = me.getKey();
Object value = me.getValue();
System.out.println(key+"---"+value);
}*/
/*Student stu1 = new Student("小强",20);
Student stu2 = new Student("旺财",18);
Student stu3 = new Student("买买提",21);
Student stu4 = new Student("小花",19);
map.put(2, stu2);
map.put(1, stu1);
map.put(4, stu4);
map.put(3, stu3);
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
Map.Entry me = (Map.Entry)obj;
Object key = me.getKey();
Object value = me.getValue();
System.out.println(key+"---"+value);
}*/
Student stu1 = new Student("小强",20);
Student stu2 = new Student("旺财",18);
Student stu3 = new Student("买买提",18);
Student stu4 = new Student("小花",19);
map.put(stu2, "bb");
map.put(stu1, "aa");
map.put(stu4, "mm");
map.put(stu3, "cc");
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
Map.Entry me = (Map.Entry)obj;
Object key = me.getKey();
Object value = me.getValue();
System.out.println(key+"---"+value);
}
}
}
package org.lanqiao.treemap.demo2;
public class Emp {
private String name;
private Integer salary;
public Emp() {
}
public Emp(String name, int salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((salary == null) ? 0 : salary.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Emp other = (Emp) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary == null) {
if (other.salary != null)
return false;
} else if (!salary.equals(other.salary))
return false;
return true;
}
@Override
public String toString() {
return "Emp [name=" + name + ", salary=" + salary + "]";
}
}
package org.lanqiao.treemap.demo2;
import java.util.Comparator;
public class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Emp emp1 = (Emp)o1;
Emp emp2 = (Emp)o2;
int res = emp1.getSalary().compareTo(emp2.getSalary());
if(res == 0 ) {
res = emp1.getName().compareTo(emp2.getName());
}
return res;
}
}
package org.lanqiao.treemap.demo2;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapComparatorDemo {
public static void main(String[] args) {
//创建集合容器
Map map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Emp emp1 = (Emp)o1;
Emp emp2 = (Emp)o2;
int res = emp1.getSalary().compareTo(emp2.getSalary());
if(res == 0 ) {
res = emp1.getName().compareTo(emp2.getName());
}
return res;
}
}) ;
//创建要在容器中保存的对象
Emp e1 = new Emp("Tom",5000);
Emp e2 = new Emp("Lilei",8000);
Emp e3 = new Emp("Mary",3000);
Emp e4 = new Emp("HanMeiMei",7000);
//将对象保存到集合中
map.put(e1, "财务部");
map.put(e2, "开发部");
map.put(e3, "行政部");
//map.put(e4, "开发部");
map.put(e4, null);
//遍历集合
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
Map.Entry me = (Map.Entry)obj;
Object key = me.getKey();
Object value = me.getValue();
System.out.println(key +"--"+value);
}
}
/*class MyInnerComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Emp emp1 = (Emp)o1;
Emp emp2 = (Emp)o2;
int res = emp1.getSalary().compareTo(emp2.getSalary());
if(res == 0 ) {
res = emp1.getName().compareTo(emp2.getName());
}
return res;
}
}*/
}
总结
- TreeMap是根据key进行排序的,它的排序和定位需要依赖比较器或覆写Comparable接口,也因此不需要key覆写hashCode方法和equals方法,就可以排除掉重复的key,而HashMap的key则需要通过覆写hashCode方法和equals方法来确保没有重复的key。
- TreeMap的查询、插入、删除效率均没有HashMap高,一般只有要对key排序时才使用TreeMap。
- TreeMap的key不能为null,而HashMap的key可以为null。
- TreeMap不是同步的。如果多个线程同时访问一个映射,并且其中至少一个线程从结构上修改了该映射,则其必须 外部同步。