如果你是一个java程序员,在日常开发中,有一个集合你一定经常使用,它是:HashMap。
如果你是一个有经验的java程序员,在日常开发中,你一定知道如何使用HashMap,性能会更好。比如说,你会从这么几个方面考虑:
-
设置初始大小
- HashMap默认的初始容量是16,在实际项目中,我们可以考虑预估要存入的元素个数,根据元素个数设置合适的初始容量。减少HashMap动态扩容,减少重建哈希表,从而提升性能
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
装载因子和动态扩容
- HashMap装载因子,默认是0.75。表示在HashMap中,当元素的个数超过:capacity * 0.75的时候,就会启动动态扩容,每次扩容后容量大小都是之前的两倍
- 装载因子越大,表示空闲空间越小,对应的HashMap冲突的概率就会越大。在实际项目中,我们可以设置合适的装载因子,提升HashMap性能
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
散列冲突解决方法
- HashMap的散列冲突解决方法是:拉链法(即链表)。在jdk1.8中,如果某个链表的元素超过8个,会转换成红黑树。因此在jdk1.8中,HashMap的散列冲突方法是:拉链法+红黑树
如果你是一个有追求的java程序员,那么你一定还想知道,HashMap底层使用了什么样的数据结构,它就是我们今天的主角:散列表
案例
定义散列表
关于什么是散列表,我们从一个故事开始:
1.今天是五四青年节,假设你还是一个大学生
2.你们班上学生比较多,是一个大班级,假设有100人,学生编号从0-100
3.你们学校,或者说你们班上准备组织一个有奖比赛活动
4.活动结束后,会统计每个学生的比赛成绩,根据成绩进行排名颁奖
5.由于你平时喜欢写程序,于是你很荣幸,辅导员就这次比赛活动邀请你开发一个程序,负责统计每个比赛选手的成绩
6.问题:
- 你该怎么做,才能实现根据编号,快速查找到比赛选手的比赛成绩?
- 比如给定编号50,在时间复杂度O(1)下,得到编号50选手的成绩。
#分析:
1.聪明的你,肯定已经找到了关键词:查找操作,时间复杂度O(1)
2.好熟悉,有没有?这不就是数组吗?
#散列表定义:
1.散列表数据结构,是数组的一种扩展,利用了数组支持按照下标随机访问特性(O(1)时间复杂度)
2.比如上面故事的解决办法:
2.1.设计一个散列函数:hash(key)=key,这里的key是学生编号:从0到100
2.2.将hash(key)的值,作为数组的下标,对应的元素值是:选手的比赛成绩
2.3.于是满足:给定任意编号50,把hash(50)=50作为数组下标,按照下标随机访问数组,在O(1)时间复杂度下,得到对应选手的比赛成绩。如下图:
散列表关键知识点
散列表的关键知识点有:
-
散列函数
- 散列函数hash(key),用于计算key与数组下标的对应关系
- 如何设计一个好的散列函数,我们将在下一篇中分享
-
散列冲突解决方法 通过散列函数hash(key),计算出的散列值。在实际应用中,不同的key,经过hash(key),如果散列值相同,我们称为散列冲突。散列冲突的解决方法有:
- 开放寻址法
- 拉链法
- 关于开放寻址法,与拉链法,我们将在下一篇中分享