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对象。
|