java集合之TreeMap实现原理
java集合之TreeMap实现原理
TreeMap集合的实现其实说简单也简单说复杂也复杂,说简单是因为TreeMap底层实现完全依靠红黑树这个数据结构,相比与HashMap来说TreeMap不用考虑hash表的扩容也不用考虑hash冲突,以及一些具有策略性的转换等(比如jdk8以上HashMap中链表长度大于等于8的时候,会自动转换为红黑树,所以HashMap的结构本身就包含TreeMap)。所以TreeMap相比于HashMap就简单许多。说复杂是因为红黑树的实现也并非我们想象的那么简单,甚至还有点难度。要想把它用自己的代码实现需要对二叉树或二叉排序树非常熟悉,包括对查找二叉树前驱节点后继节点的算法以及二叉树旋转算法等。
红黑树的实现原理
关于红黑树的实现原理之前有一篇博客已经介绍过了,在此就不多叙述,否则的话估计本篇3/4都在描述红黑树的实现。红黑树的实现请参考:http://www.jiajiajia.club/official/weblog/yjw520/42
TreeMap的结构
从源码可以看出TreeMap实现了Map接口并定义了一下几个重要属性
private transient Entry<K,V> root;
/**
* The number of entries in the tree
*/
private transient int size = 0;
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
private final Comparator<? super K> comparator;
- root属性,root是红黑树实现的根节点,树中所有节点的添加、查找、删除等操作都必须经过根节点而来。
- Size属性不用多说,就是集合中节点的个数。
- modCount属性是记录对树进行结构修改的次数。
- comparator属性是一个比较器,用于解决TreeMap中key的排序问题,由于红黑树也是二叉查找树,它们当中每一个节点的比较值都必须大于或等于在它的左子树中的所有节点,并且小于或等于在它的右子树中的所有节点。这确保红黑树运作时能够快速的在树中查找给定的值。所以在调用put方法的key类必须实现Comparable接口或者在创建TreeMap的时候传入一个比较器Comparator的实现类。如下面两种实现:
class Entity implements Comparable<Entity>{
int a;
public Entity(int a) { this.a=a; }
@Override
public int compareTo(Entity o) {
if(o.a>this.a) return 1;
if(o.a<this.a) return -1;
else return 0;
}
}
public class Test {
public static void main(String[] args) {
TreeMap<Entity, String> t=new TreeMap<Entity, String>();
t.put(new Entity(2),"2");
t.put(new Entity(3),"3");
}
}
class Entity {
public Entity(int a) { this.a=a; }
int a;
}
public class Test {
public static void main(String[] args) {
TreeMap<Entity, String> t=new TreeMap<Entity, String>(new Comparator<Entity>() {
@Override
public int compare(Entity o1, Entity o2) {
if(o1.a>o2.a) return 1;
if(o1.a<o2.a) return -1;
else return 1;
}
});
t.put(new Entity(2),"2");
t.put(new Entity(3),"3");
System.out.println(t);
}
}
如果你使用HashMap的时候不满足以上任何一种则会包java.lang.ClassCastException异常。(注意如果用Integer或String等不会有异常,这些类已经实现的Comparable接口)
TreeMap的两种遍历方式
public class Test {
public static void main(String[] args) {
TreeMap<Integer, Integer> t=new TreeMap<Integer, Integer>();
t.put(2,2);
t.put(3,3);
t.put(9,9);
t.put(4,4);
t.put(5,5);
t.put(0,0);
t.put(8,8);
t.put(7,7);
t.put(1,1);
t.put(34,34);
t.put(90,90);
/**
* 方式1
*/
Iterator<Entry<Integer, Integer>> iterator = t.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Integer, Integer> entry =iterator.next();
System.out.println(entry);
}
System.out.println("****************************");
/**
* 方式2
*/
for(Entry<Integer, Integer> entry : t.entrySet()) {
System.out.println(entry);
}
}
}
遍历TreeMap时删除元素的正确方式
在遍历TreeMap时删除元素,一下两种方式会抛java.util.ConcurrentModificationException异常,所以做这个操作时一定要注意。
public class Test {
public static void main(String[] args) {
TreeMap<Integer, Integer> t=new TreeMap<Integer, Integer>();
t.put(2,2);
t.put(3,3);
t.put(9,9);
t.put(4,4);
t.put(5,5);
t.put(0,0);
t.put(8,8);
t.put(7,7);
t.put(1,1);
t.put(34,34);
t.put(90,90);
Iterator<Entry<Integer, Integer>> iterator = t.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Integer, Integer> entry =iterator.next();
System.out.println(entry);
if(entry.getValue()==4) {
t.remove(entry.getKey());//删除元素
}
}
System.out.println("****************************");
for(Entry<Integer, Integer> entry : t.entrySet()) {
System.out.println(entry);
if(entry.getKey()==7) {
t.remove(entry.getKey()); //删除元素
}
}
}
}
正确的删除方式
public class Test {
public static void main(String[] args) {
TreeMap<Integer, Integer> t=new TreeMap<Integer, Integer>();
t.put(2,2);
t.put(3,3);
t.put(9,9);
t.put(4,4);
t.put(5,5);
t.put(0,0);
t.put(8,8);
t.put(7,7);
t.put(1,1);
t.put(34,34);
t.put(90,90);
Iterator<Entry<Integer, Integer>> iterator = t.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Integer, Integer> entry =iterator.next();
System.out.println(entry);
if(entry.getValue()==4) {
iterator.remove();//正确删除元素的方式
}
}
System.out.println("****************************");
for(Entry<Integer, Integer> entry : t.entrySet()) {
System.out.println(entry);
}
}
}
非线程安全
TreeMap和HashMap一样都是非线程安全的,从它的源码的实现中可以看出,所以在并发编程中使用的时候要注意这一点。
评论区
请写下您的评论...
猜你喜欢
blog
java集合之Hashtable
java基础
1665
java集合之Hashtable一、构造方法1.publicHashtable()publicHashtable(){this(11,0.75f);}无参构造,初始化一个容量为11,负载因子为
blog
java集合之HashMap理解和分析
java基础
1378
1.HashMap的构造函数1.publicHashMap()publicHashMap(){this.loadFactor=DEFAULT_LOAD_FACTOR;//allotherfieldsdefaulted}构造一个空的HashMap,初始容量为16,负载因子为0.75,负载因子和它的作用将会在下方解释。2.publicHashMap(intinitialCapacity)publicH
blog
java集合之HashSet
java基础
1514
一、HashSet底层实现从HashSet的源码中可以发现,它的底层维护了一个HashMap,在newHashSet的时候,构造方法中其实是new了一个HashMap
blog
java集合之linkedList
java基础
2397
1.linkedList的实现linkedlist的实现是基于数据结构:双向链表。模型图如对于linkedList没有像arrayList一样有扩容的概念。也不需要移动数据。所以对于新增和删除操作
blog
java集合之ArrayList
java基础
2895
ArrayList的实现是一个动态数组,从源码中也可以看出。这就决定了他的查找效率高,可以直接通过下标访问。但是对于删除和增加元素,需要大量的移动元素,所以插入和删除的效率就很低。ArrayList
算法基础
1878
Java中遍历集合的方式以list集合为例,有三种遍历方式。ListStringlist=newArrayList();
list.add("2");
list.add("2");
list.add
ASM,java基础
1256
/134cglib动态代理底层实现分析java:http://www.jiajiajia.club/official/weblog/yjw520/34cglib代理常用接口和api:http://www.jiajiaj
blog
java集合框架总结
java基础
2896
Java集合框架数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作。Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架。在平
最新发表
归档
2018-11
12
2018-12
33
2019-01
28
2019-02
28
2019-03
32
2019-04
27
2019-05
33
2019-06
6
2019-07
12
2019-08
12
2019-09
21
2019-10
8
2019-11
15
2019-12
25
2020-01
9
2020-02
5
2020-03
16
2020-04
4
2020-06
1
2020-07
7
2020-08
13
2020-09
9
2020-10
5
2020-12
3
2021-01
1
2021-02
5
2021-03
7
2021-04
4
2021-05
4
2021-06
1
2021-07
7
2021-08
2
2021-09
8
2021-10
9
2021-11
16
2021-12
14
2022-01
7
2022-05
1
2022-08
3
2022-09
2
2022-10
2
2022-12
5
2023-01
3
2023-02
1
2023-03
4
2023-04
2
2023-06
3
2023-07
4
2023-08
1
2023-10
1
2024-02
1
2024-03
1
2024-04
1
2024-08
1
标签
算法基础
linux
前端
c++
数据结构
框架
数据库
计算机基础
储备知识
java基础
ASM
其他
深入理解java虚拟机
nginx
git
消息中间件
搜索
maven
redis
docker
dubbo
vue
导入导出
软件使用
idea插件
协议
无聊的知识
jenkins
springboot
mqtt协议
keepalived
minio
mysql
ensp
网络基础
xxl-job
rabbitmq
haproxy
srs
音视频
webrtc
javascript
加密算法
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。