HashMap

数组:存储区间连续,占用内存严重,空间复杂很大,时间复杂为O(1)。

- 优点:是随机读取效率很高,原因数组是连续(随机访问性强,查找速度快)。

- 缺点:插入删除数据效率低,因插入数据,这个位置后面的数据在内存中要往后移的,且大小固定不易动态扩展

链表:区间离散,占用内存宽松,空间复杂度小,时间复杂度O(N)。

1.单向链表由节点组成,每个节点都包含下一个节点的指针。

- 优点:插入删除速度快(不需要像线性结构那样移动剩下的数据),内存利用率高,没有大小固定,扩展灵活

- 缺点:不能随机查找,需要通过循环或者递归的方法访问到任意数据,平均的访问效率低于线性表(查询效率低)。单向链表只能从头到尾遍历。只能找到后继,无法找到前驱,也就是只能前进。

2.双向链表是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

 

特点:

  1. 有两个指针,一个指向前一个节点,一个指向后一个节点
  2. 可以找到前驱和后继,可进可退
  3. 增加删除节点复杂,需要多分配一个指针存储空间

红黑树是一种特定类型的二叉树,也是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树,由于每一棵红黑树都是一颗二叉排序树,因此,在对红黑树进行查找时,可以采用运用于普通二叉排序树上的查找算法。

 

特点:

  1. 每个节点只能是红色或者黑色。
  2. 根节点必须是黑色。
  3. 红色的节点,它的叶节点只能是黑色。
  4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树

HashMap(哈希表):

是一个键值对的集合,每个节点用Node<K,V>表示

static class Node<K,V> implements Map.Entry<K,V> {
   final int hash;
   final K key;
   V value;
   Node<K,V> next;

Node是一个内部类,这里的key为键,value为值,next指向下一个元素,可以看出HashMap中的元素不是一个单纯的键值对,还包含下一个元素的引用。

在JDK1.7时HashMap的底层是由数组+链表实现的,到了JDK1.8后改成了数组+链表+红黑树实现

在HashMap底层使用数组+(链表或红黑树)的结构完美的解决了数组和链表的问题,使得查询和插入,删除的效率都很高。

PUT操作:

1.计算关于key的hashcode值

2.如果散列表为空时,调用resize()初始化散列表

3.如果没有发生碰撞,直接添加元素到散列表中去

4.如果发生了碰撞(hashCode值相同),进行三种判断 

1:若key地址相同或者equals后内容相同,则替换旧值

2:如果是红黑树结构,就调用树的插入方法

3:链表结构,循环遍历直到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的阙值8;也可以遍历到有节点与插入元素的哈希值和内容相同,进行覆盖。

 5.如果桶满了大于阀值,则resize进行扩容

GET操作

  1. 对key的hashCode进行hashing
  2. 与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找
  3. 如果有hash冲突,则利用equals方法去遍历链表查找节点

RESIZE操作

扩容的时候,HashMap是把长度扩为原来2倍,所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。

1. HashMap的特性?

  • 实现快速存储键值对,允许为null,key值不可重复,若key值重复则覆盖。
  • 线程不安全。
  • 底层是Hash表,不保证有顺序

2. HashMap底层原理?

  • jdk7时采用数组+链表,jdk8后采用数组+链表+红黑树的数据结构。

3. HashMap put原理?

  • 当我们给put()方法传递键和值时,先对键做一个hashCode()的计算来得到它在bucket数组中的位置来存储Entry对象。

4. HashMap get原理?

  • 当获取对象时,通过get获取到bucket的位置,再通过键对象的equals()方法找到正确的键值对,然后再返回值对象。

5. HashMap扩容机制?

  • 扩容需要重新分配一个新数组,新数组是老数组的2倍长,然后遍历整个老结构,把所有的元素挨个重新hash分配到新结构中去。

6. HashMap默认初始化长度为16,并且每次自动扩展或者是手动初始化容量时,为什么必须是2的次幂?

  • 为了数据的均匀分布,减少哈希碰撞。因为确定数组位置是用的位运算,若数据不是2的次幂则会增加哈希碰撞的次数和浪费数组空间。
  • 输入数据若不是2的幂,HashMap通过一通位移运算和或运算得到的肯定是2的幂次数,并且是离那个数最近的数字

7. HashMap大小超过了负载因子(load factor)定义的容量,怎么办?

  • 超过阙值会进行扩容操作,概括的讲就是扩容后的数组大小是原数组的2倍,将原来的元素重新hashing放入到新的散列表中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值