目录
一、HashMap底层实现原理
HashMap是基于哈希表的Map接口的非同步实现。元素以键值对的形式存放,并且允许null键和null值,因为key值唯一(不能重复),因此,null键只有一个。另外,HashMap不保证元素存储顺序,是一种无序的,和放入的顺序并不相同(此类不保证映射的顺序,特别是它不保证该顺序恒久不变)。
哈希表由一个数组和指向该数组的指针组成。数组中的每个元素称为桶,每个桶都可以存储一个键值对。
- 当新增一个元素时,HashMap 首先对 key 值进行哈希函数计算,得到一个桶的索引,然后将键值对存储到该桶中。
- 在查找元素时,同样先通过哈希函数计算出键所属的桶,然后在该桶中查找是否存在该键的值。如果存在,则返回其对应的值,否则返回 null。
- 当多个键映射到同一个桶时,HashMap 使用链表来处理冲突,即在该桶中维护一个链表,将哈希值相同的键值对插入到链表中。在 Java 8 中,当链表中元素个数超过一定阈值(默认为 8),该链表会被转化为红黑树来提高查找效率。当链表元素个数变少时,又会被转化回链表。
HashMap是线程不安全的。
二、HashMap底层数据结构的组成
HashMap底层数据结构主要由数组和链表(或红黑树)组成。
具体来说,HashMap内部维护了一个数组,数组元素是一个个的Entry对象。Entry对象中包含了键值对的信息,即key和value,以及一个next指针,指向下一个Entry对象,从而形成一个链表。当链表长度大于8时,会将链表转成红黑树,以提高查找效率。
使用哈希算法来确定键值对在数组中的位置,具体来说,将key的hashCode()取模数组长度,得到的值就是该键值对在数组中的下标。如果不同的key计算出的hashCode()模数组长度后得到的下标相同,就会产生哈希冲突,这时候就在该下标对应的链表中进行查找,找到对应的key值。
通过哈希算法和链表(或红黑树)的结合,HashMap可以实现高效的键值对存储和查找。
Ⅰ一个键值对是如何存入数组中的
键值对一般是通过对象的方式存储在数组中。可以创建一个对象,对象的属性名为键,属性值为值,然后将这个对象存储在数组中。例如,以下代码将一个键值对 `{ name: "Tom", age: 18 }` 存储在一个数组中:
let arr = [];
let obj = { name: "Tom", age: 318};
arr.push(obj);
现在,这个数组 arr 中就包含了一个对象,对象的属性名为 'name',属性值为 "John",属性名为 'age',属性值为 '30'。我们可以通过访问数组中的对象来获得这个键值对的值,例如:
console.log(arr[0].name);
console.log(arr[0].age);
Ⅱ一个键值对是如何存入链表或红黑树中的
在Java中,键值对通常是通过Map接口实现的。Map接口有多个实现,如HashMap、LinkedHashMap、TreeMap等,它们有不同的数据结构来存储键值对。
对于HashMap,当添加键值对时,会先根据键的HashCode值来确定要存储的位置(桶)。如果该位置已经有其他键值对存在,则以链表的形式将新的键值对连接在已有的键值对后面。如果链表长度达到一定的阈值,会将链表转换为红黑树进行存储。这样可以提高查找、插入、删除等操作的效率。
三、链表和红黑树的用途
链表和红黑树都是常用的数据结构,它们的用途各有不同。
Ⅰ 链表的主要用途
链表的主要用途是表示线性结构,可以用来实现队列、栈、链表等数据结构。
链表的优点是插入和删除操作非常快,因为只需要改变指针的指向,不需要移动其他元素。
缺点是访问元素的时间复杂度是O(n),不适合用于查找和排序。
Ⅱ红黑树的主要用途
红黑树是一种平衡二叉搜索树,可以用于实现有序集合、有序映射等数据结构。
红黑树的优点是插入、删除、查找的时间复杂度都是O(log n),可以保证树的平衡性,避免了二叉搜索树退化成链表的问题。
缺点是实现比较复杂,需要维护红黑树的性质。
- 综上所述,链表和红黑树都有各自的优点和局限性,应根据具体场景选择合适的数据结构。
四、链表和红黑树的转换方式
Ⅰ将一个红黑树转换成列表
将一个红黑树转换成链表可以使用中序遍历的方式,即从小到大遍历树的所有节点,将节点依次连接起来形成链表。具体步骤如下:
- 对于红黑树的每个节点,先将其左子树转换成链表。
- 找到当前节点的前驱节点(即左子树的最右节点),将其与当前节点连接起来,成为当前节点的后继节点。
- 将当前节点的右子树转换成链表。
- 继续处理当前节点的后继节点,重复步骤2至步骤4,直到处理完整个树。
- 最终形成的链表顺序为从小到大排列。
Ⅱ将一个链表转换成红黑树
将一个链表转换成红黑树,可以使用递归的方法,具体步骤如下:
- 找到链表的中间节点,作为当前子树的根节点。
- 递归处理链表的左半部分,作为当前节点的左子树。
- 递归处理链表的右半部分,作为当前节点的右子树。
- 根据红黑树的性质,需要对新建的节点进行颜色调整、旋转等操作,以保证红黑树的平衡性和性质。
- 最终形成的红黑树具有平衡性和性质,可以高效地进行搜索、插入和删除操作。