hashmap containsvalue时间复杂度_HashMap(JDK8)知识汇总(一)

一、数据结构

特性

  • HashMap存储键值对,实现快速存取数据,时间复杂度见 常用数据结构的时间复杂度;

  • 允许null键/值;

  • 非线程安全;

  • 不保证有序(比如插入的顺序)

  • 实现map接口

  • 继承AbstractMap

存储结构

这里需要区分一下,JDK1.7和 JDK1.8之后的 HashMap 存储结构。在JDK1.7及之前,是用数组加链表的方式存储的。

但是,众所周知,当链表的长度特别长的时候,查询效率将直线下降,查询的时间复杂度为 O(n)。因此,JDK1.8 把它设计为达到一个特定的阈值之后,就将链表转化为红黑树。(数组默认初始化大小为16,当链接长度大于8的时候就会转换为红黑树,实现logn的复杂度查询,如果小于6就会再次转换为链表)

这里简单说下红黑树的特点:

  1. 每个节点只有两种颜色:红色或者黑色

  2. 根节点必须是黑色

  3. 每个叶子节点(NIL)都是黑色的空节点

  4. 从根节点到叶子节点,不能出现两个连续的红色节点

  5. 从任一节点出发,到它下边的子节点的路径包含的黑色节点数目都相同

由于红黑树,是一个自平衡的二叉搜索树,因此可以使查询的时间复杂度降为O(logn)。(红黑树不是本文重点,不了解的童鞋可自行查阅相关资料哈)

HashMap 结构示意图:

8343c493e46539034e8dd6a98a8efe25.png

HashMap底层数据结构:数组+链表+红黑树,可以接受null的key和value值.数组默认初始化大小为16,当链接长度大于8的时候就会转换为红黑树,实现logn的复杂度查询,如果小于6就会再次转换为链表. 其中的结构单体是 entry,包括四个元素:key,value,next,hash值.

常量

在 HashMap源码中,比较重要的常用变量。

  • DEFAULTINITIALCAPACITY = 1 << 4

  • MAXIMUM_CAPACITY = 1 << 30

  • DEFAULTLOADFACTOR = 0.75f

  • TREEIFY_THRESHOLD = 8

  • UNTREEIFY_THRESHOLD = 6

  • MINTREEIFYCAPACITY = 64

//默认的初始化容量为16,必须是2的n次幂

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

//最大容量为 2^30

static final int MAXIMUM_CAPACITY = 1 << 30;

//默认的加载因子0.75,乘以数组容量得到的值,用来表示元素个数达到多少时,需要扩容。

//为什么设置 0.75 这个值呢,简单来说就是时间和空间的权衡。

//若小于0.75如0.5,则数组长度达到一半大小就需要扩容,空间使用率大大降低,

//若大于0.75如0.8,则会增大hash冲突的概率,影响查询效率。

static final float DEFAULT_LOAD_FACTOR = 0.75f;

//刚才提到了当链表长度过长时,会有一个阈值,超过这个阈值8就会转化为红黑树

static final int TREEIFY_THRESHOLD = 8;

//当红黑树上的元素个数,减少到6个时,就退化为链表

static final int UNTREEIFY_THRESHOLD = 6;

//链表转化为红黑树,除了有阈值的限制,还有另外一个限制,需要数组容量至少达到64,才会树化。

//这是为了避免,数组扩容和树化阈值之间的冲突。

static final int MIN_TREEIFY_CAPACITY = 64;

常用变量

//存放所有Node节点的数组

transient Node<K,V>[] table;

//存放所有的键值对

transient Set<Map.Entry<K,V>> entrySet;

//map中的实际键值对个数,即数组中元素个数

transient int size;

//每次结构改变时,都会自增,fail-fast机制,这是一种错误检测机制。

//当迭代集合的时候,如果结构发生改变,则会发生 fail-fast,抛出异常。

transient int modCount;

//数组扩容阈值

int threshold;

//加载因子

final float loadFactor;

内部类

f80a862035c8b77bf58b5ac9bc7ea210.png

普通链表节点

//普通单向链表节点类

static class Node<K,V> implements Map.Entry<K,V> {

//key的hash值,put和get的时候都需要用到它来确定元素在数组中的位置

final int hash;

final K key;

V value;

//指向单链表的下一个节点

Node<K,V> next;

Node(int hash, K key, V value, Node<K,V> next) {

this.hash = hash;

this.key = key;

this.value = value;

this.next = next;

}

}

红黑树节点

//转化为红黑树的节点类

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {

//当前节点的父节点

TreeNode<K,V> parent;

//左孩子节点

TreeNode<K,V> left;

//右孩子节点

TreeNode<K,V> right;

//指向前一个节点

TreeNode<K,V> prev; // needed to unlink next upon deletion

//当前节点是红色或者黑色的标识

boolean red;

TreeNode(int hash, K key, V val, Node<K,V> next) {

super(hash, key, val, next);

}

}

  • HashMap中size表示当前共有多少个KV对;

  • capacity表示当前HashMap的容量是多少,默认值是16,每次扩容都是成倍的;

  • loadFactor是装载因子,当Map中元素个数超过 loadFactor*capacity的值时,会触发扩容。 loadFactor*capacity可以用threshold表示。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值