HashMap 和 HashSet 源码分析

HashMap 简单介绍

1、HashMap和 HashTable的区别?
HashMap 线程不安全,HashTable 线程安全。

2、Map 接口中Node对象的作用
Node类的源码,采用链表数据结构,因为 key的 hashcode可能存在相同但是key不相同的情况,hahscode相同的key都存在一个链表数据结构上,再通过equals 比较值。
就是为了解决hashcode冲突问题。
在这里插入图片描述Node 表示存放在HashMap 中的一条键值对,主要用来存储Map集合的元素。

hashcode 和equals

HashCode作用: hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值主要应用于:HashMap能够快速查找

HashCode和Equals实现都是可以比较对象使用,区别就在于两个对象的HashCode.相同,但是对象的不一定相同,但是使用Equals 比较两者对象如果相同,则HashCode一定相同。

所以:HashCode 比较两者对象如果不同,那么对象肯定不同的(不需要使用Equals比较),如果两者之间HashCode相同的,可以再继续使用Equals 比较

HashMap解决HashCode碰撞问题

hashMap中可以使用 key 的hashcode取余计算存放数据的数组的下标。但是这时可能存在不同的 key 的hashcode
的值是相同的情况,这是采用链表和红黑树数据结构解决。一个链表存放相同的 hashcode对象。这是通过key 找到对应的键表再通过循环(hashcode相同的key占少数,概率不高)找到 key对应的value值。

红黑树

JDK8为什么使用红黑树

在Java7中的HashMap,当hashCode冲突的时候会使用同一个链表存放,如果链表的长度过长会导致查询效率非常慢,时间复杂度为o(N)
所以在Java8中HashMap使用数组+链表+红黑树,在链表中长度大于8的时候,将后面的数据以红黑树实现存放,从而加快检索速度;

时间复杂度

O(1):就是最低的时空复杂度了,也就是耗时/耗空间与输入数据大小无关,无论输入数据增大多少倍,耗时/耗空间都不变。哈希算法就是典型的O(1)时间复杂度,无论数据规模多大,都可以在一次计算后找到目标(不考虑冲突的话)

On):比如时间复杂度为O(n),就代表数据量增大几倍,耗时也增大几倍。比如常见的遍历算法,要找到一个数组里面最大的一个数,你要把n个变量都扫描一遍,操作次数为n,那么算法复杂度是O(n).

Olog n),当数据增大n倍时,耗时增大log n倍(这里的log是以2为底的,比如,当数据增大256倍时,耗时只增大8倍,是比线性
还要低的时间复杂度)。二分查找就是O(log n)的算法,每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标。

集合查询的时间复杂度

Arraylist根据下标查询的情况下,时间复杂度为多少o(1).
Arraylist根据内容查询的情况下,时间复杂度为多少 o(n).

Arraylist_底层基于数组实现
LinkeList底层基于链表实现

LinkeList根据下标查询的的情况下,时间复杂度为多少o (n)
LinkeList根据内容查询的情况下,时间复杂度为多少o(n)
Hashmap根据 key查询的情况下,时间复杂度为多少o(1)或者o(nl)

红黑树概念

红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
在这里插入图片描述

基本特征:
1.每个节点不是红色就是黑色
2.不可能有连在一起的红色节点
3.根节点都是黑色
4.每个红色节点的两个子节点都是黑色
红黑树变换规则:
1.改变节点颜色
2.左旋转
3.右旋转

折半查找(二分查找)算法

思考:比如在链表中有1-100个节点,那么现在如何根据下标查询到某个节点举例查询链表中第63个节点
For( int i=0; i<63; i++){
查询63次效率非常低
}
查询算法
二分查找、随机查询(运气查找法)运气好的情况下,一次查询到、差的情况100次·
第一次查询100/2中间值50 63>50从51-100之间查询
第二次查询中间值为75从51-75查询63<75 .
第三次查询51-75之间中间值6363==63

.二分查找效率非常高
二分查询存在那些问题呢? 必须保证有序的问题,
举个例子: 。
2222222
2^31

二叉搜索树

二叉搜索树具有如下特征:
1.节点的左子树只包含小于当前根节点的数
2.节点的右子树只包含大于当前根节点的数
3.所有左子树和右子树自身必须也是二叉搜索树

查找效率:20亿个点也就是查询2^31=21
时间复杂度:2个x=n>x=log2^n=logn
在这里插入图片描述
缺点:不平衡和时间插入的顺序有关系,使用插入的第一个节点作为平衡点,如果插入第一个是为0的情况下,最后成为了一条线。

所以:查找时间复杂度其实就是为树的深度,也就是变为O(n)建议使用平衡二叉树,红黑树是平衡二叉树一种实现方案

变换规则

改变颜色和旋转
变颜色的情况:当前节点父亲是红色,且它的祖父亲节点的另一个子节点也是红色(叔叔节点):
1.将父亲节点设置为黑色
⒉将叔叔节点设为黑色
3.将祖父也就是父亲的父亲设为红色
4.把指针定义到祖父节点设为当前操作

左旋转:
左旋:当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是右子树,左旋转以父节点作为左旋;

**右旋转:**当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是左子树,右旋转以
1.父节点作为右旋;
2.将父节点变为黑色
3.将祖父节点变为红色(爷爷)
4.以祖父节点开始旋转

底层源码分析

HashMap是一个键值对集合,jdk7使用Entry对象(key、value、next〉封装键值对对象,jdk7使用Node对象
jdk7:数组+链表(单向)实现的
jdk8:数组+链表+红黑树实现的

构造函数分析

类的变量分析
在这里插入图片描述在这里插入图片描述构造函数
在这里插入图片描述

put 方法的实现

基本逻辑为:
1.使用key.hashcode计算hash值存放到数组位置
2.如果发生key的hashCode相同的,使用实现存放如果hashCode相同,且equals也相同直接覆盖元素
在这里插入图片描述

扩容原理

每次扩容都是在原来的基础上翻倍,会将原来数组的内容移到新数组里面去
在这里插入图片描述在这里插入图片描述

常见面试题

HashMap 中index 冲突与hash冲突存在那些区别?
答:lndex冲突是因为底层做二进制运算的产生相同的index,对象不同,但是二进制运算是相同的index。
Hash冲突对象不同,但是hashCode相同―在hashMap 中,为了确保相同的key使用equals.

lndex冲突了的话会存在那些问题?
答:会导致值覆盖掉,所以在这时候使用单向链表和红黑树解决

同一个链表中存放了那些内容?
答:lndex 冲突或者hash值冲突

jdk8的HashMap 做了哪些优化?
答:数据结构上优化: jdk8上增加了红黑树数据结构,目的为了index 冲突过多的情况下导致单个链表过长,这是查询效率非常慢,改为红黑树的情况下查询速度变快。
扩容bug:jdk7扩容在多线程情况下,可能会存在死循环采用头插入法jdk8扩容在多线程情况下,已经解决扩容死循环问题才尾插法

HashSet 源码分析

集合特点:存放不重复的元素。底层通过HashMap集合实现,利用HashMap的key不重复(通过hashcode和equals比较)的特性。
在这里插入图片描述添加元素时,就是想 HashMap 集合中存放数据。key就是 HashSet 存放的元素,value为一个object对象。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值