Skip to content

Commit

Permalink
correct some typo
Browse files Browse the repository at this point in the history
  • Loading branch information
CarpenterLee committed May 28, 2016
1 parent eaa3eb7 commit 0556912
Showing 1 changed file with 9 additions and 5 deletions.
14 changes: 9 additions & 5 deletions markdown/7-LinkedHashSet and LinkedHashMap.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

如果你已看过前面关于*HashSet**HashMap*,以及*TreeSet**TreeMap*的讲解,一定能够想到本文将要讲解的*LinkedHashSet**LinkedHashMap*其实也是一回事。*LinkedHashSet**LinkedHashMap*在Java里也有着相同的实现,前者仅仅是对后者做了一层包装,也就是说***LinkedHashSet*里面有一个*LinkedHashMap*(适配器模式)**。因此本文将重点分析*LinkedHashMap*

*LinkedHashMap*实现了*Map*接口,即允许放入`key``null`的元素,也允许插入`value``null`的元素。从名字上可以看出该容器是*linked list**HashMap*的混合体,也就是说它同时满足*HashMap**linked list*的某些特性。**可将*LinkedHashMap*看作采用*linked list*增强的*HashMap* **
*LinkedHashMap*实现了*Map*接口,即允许放入`key``null`的元素,也允许插入`value``null`的元素。从名字上可以看出该容器是*linked list**HashMap*的混合体,也就是说它同时满足*HashMap**linked list*的某些特性。**可将*LinkedHashMap*看作采用*linked list*增强的*HashMap***

![LinkedHashMap_base.png](../PNGFigures/LinkedHashMap_base.png)

事实上*LinkedHashMap**HashMap*的直接子类,**二者唯一的区别是*LinkedHashMap**HashMap*的基础上,采用双向链表(doubly-linked list)的形式将所有`entry`连接起来,这样是为保证元素的迭代顺序跟插入顺序相同**。上图给出了*LinkedHashMap*的结构图,主体部分跟*HashMap*完全一样,多了`header`指向双向链表的头部(是一个哑元),**该双向链表的迭代顺序就是`entry`的插入顺序**

除了可以保迭代历顺序,这种结构还有一个好处:**迭代*LinkedHashMap*时不需要像*HashMap*那样遍历整个`table`,而只需要直接遍历`header`指向的双向链表即可**,也就是说*LinkedHashMap*的迭代时间就只跟`entry`的个数相关,而跟`table`的大小无关。
除了可以保迭代历顺序,这种结构还有一个好处:**迭代*LinkedHashMap*时不需要像*HashMap*那样遍历整个`table`,而只需要直接遍历`header`指向的双向链表即可**,也就是说*LinkedHashMap*的迭代时间就只跟`entry`的个数相关,而跟`table`的大小无关。

有两个参数可以影响*HashMap*的性能:初始容量(inital capacity)和负载系数(load factor)。初始容量指定了初始`table`的大小,负载系数用来指定自动扩容的临界值。当`entry`的数量超过`capacity*load_factor`时,容器将自动扩容并重新哈希。对于插入元素较多的场景,将初始容量设大可以减少重新哈希的次数。
有两个参数可以影响*LinkedHashMap*的性能:初始容量(inital capacity)和负载系数(load factor)。初始容量指定了初始`table`的大小,负载系数用来指定自动扩容的临界值。当`entry`的数量超过`capacity*load_factor`时,容器将自动扩容并重新哈希。对于插入元素较多的场景,将初始容量设大可以减少重新哈希的次数。

将对象放入到*LinkedHashMap**LinkedHashSet*中时,有两个方法需要特别关心:`hashCode()``equals()`**`hashCode()`方法决定了对象会被放到哪个`bucket`里,当多个对象的哈希值冲突时,`equals()`方法决定了这些对象是否是“同一个对象”**。所以,如果要将自定义的对象放入到`LinkedHashMap``LinkedHashSet`中,需要*@Override*`hashCode()``equals()`方法。

Expand All @@ -39,7 +39,9 @@ void foo(Map m) {

`put(K key, V value)`方法是将指定的`key, value`对添加到`map`里。该方法首先会对`map`做一次查找,看是否包含该元组,如果已经包含则直接返回,查找过程类似于`get()`方法;如果没有找到,则会通过`addEntry(int hash, K key, V value, int bucketIndex)`方法插入新的`entry`

注意,这里的**插入有两重含义**,1. 从`table`的角度看,新的`entry`需要插入到对应的`bucket`里,当有哈希冲突时,采用头插法将新的`entry`插入到冲突链表的头部;2. 从`header`的角度看,新的`entry`需要插入到双向链表的尾部。
注意,这里的**插入有两重含义**
> 1.`table`的角度看,新的`entry`需要插入到对应的`bucket`里,当有哈希冲突时,采用头插法将新的`entry`插入到冲突链表的头部。
> 2.`header`的角度看,新的`entry`需要插入到双向链表的尾部。
![LinkedHashMap_addEntry.png](../PNGFigures/LinkedHashMap_addEntry.png)

Expand Down Expand Up @@ -80,7 +82,9 @@ private void addBefore(Entry<K,V> existingEntry) {

`remove(Object key)`的作用是删除`key`值对应的`entry`,该方法的具体逻辑是在`removeEntryForKey(Object key)`里实现的。`removeEntryForKey()`方法会首先找到`key`值对应的`entry`,然后删除该`entry`(修改链表的相应引用)。查找过程跟`get()`方法类似。

注意,这里的**删除也有两重含义**,1. 从`table`的角度看,需要将该`entry`从对应的`bucket`里删除,如果对应的冲突链表不空,需要修改冲突链表的相应引用;2. 从`header`的角度来看,需要将该`entry`从双向链表中删除,同时修改链表中前面以及后面元素的相应引用。
注意,这里的**删除也有两重含义**
> 1.`table`的角度看,需要将该`entry`从对应的`bucket`里删除,如果对应的冲突链表不空,需要修改冲突链表的相应引用。
> 2.`header`的角度来看,需要将该`entry`从双向链表中删除,同时修改链表中前面以及后面元素的相应引用。
![LinkedHashMap_removeEntryForKey.png](../PNGFigures/LinkedHashMap_removeEntryForKey.png)

Expand Down

0 comments on commit 0556912

Please sign in to comment.