diff --git a/notes/Java 容器.md b/notes/Java 容器.md index 1cb19fe6..2e10a401 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -9,9 +9,9 @@ * [ArrayList](#arraylist) * [Vector](#vector) * [LinkedList](#linkedlist) + * [LinkedHashMap](#linkedhashmap) * [TreeMap](#treemap) * [HashMap](#hashmap) - * [LinkedHashMap](#linkedhashmap) * [ConcurrentHashMap - JDK 1.7](#concurrenthashmap---jdk-17) * [ConcurrentHashMap - JDK 1.8](#concurrenthashmap---jdk-18) * [参考资料](#参考资料) @@ -40,13 +40,13 @@ - Vector:和 ArrayList 类似,但它是线程安全的; -- LinkedList:基于双向循环链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双端队列。 +- LinkedList:基于双向循环链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。 ### 3. Queue - LinkedList:可以用它来支持双向队列; -- PriorityQueue:基于堆结构实现,可以用它来实现优先级队列。 +- PriorityQueue:基于堆结构实现,可以用它来实现优先队列。 ## Map @@ -111,7 +111,7 @@ List list = Arrays.asList(1,2,3); ## ArrayList -[ArraList.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/ArrayList.java) +[ArrayList.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/ArrayList.java) ### 1. 概览 @@ -224,6 +224,10 @@ private void writeObject(java.io.ObjectOutputStream s) [LinkedList.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/LinkedList.java) +## LinkedHashMap + +[LinkedHashMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/HashMap.java) + ## TreeMap [TreeMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/TreeMap.java) @@ -302,7 +306,7 @@ map.put("K3", "V3"); - 插入 <K2,V2> 键值对,先计算 K2 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6。 - 插入 <K3,V3> 键值对,先计算 K3 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6,插在 <K2,V2> 后面。 -

+

查找需要分成两步进行: @@ -317,7 +321,7 @@ map.put("K3", "V3"); 因为从 JDK 1.8 开始引入了红黑树,因此扩容操作较为复杂,为了便于理解,以下内容使用 JDK 1.7 的内容。 -设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的数量级为 O(N/M)。 +设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的复杂度为 O(N/M)。 为了让查找的成本降低,应该尽可能使得 N/M 尽可能小,因此需要保证 M 尽可能大,也就是说 table 要尽可能大。HashMap 采用动态扩容来根据当前的 N 值来调整 M 值,使得空间效率和时间效率都能得到保证。 @@ -397,11 +401,9 @@ void transfer(Entry[] newTable) { ### 5. 确定桶下标 -很多操作都需要先确定一个键值对所在的桶下标,需要分三步进行。 +很多操作都需要先确定一个键值对所在的桶下标,这个操作需要分三步进行。 -(一)hashCode() - -调用 Key 的 hashCode() 方法得到 hashCode。 +(一)调用 hashCode() ```java public final int hashCode() { @@ -420,7 +422,7 @@ static final int hash(Object key) { } ``` -(三)除留余数法 +(三)除留余数 令 x = 1<<4,即 x 为 2 的 4 次方,它具有以下性质: @@ -429,7 +431,7 @@ x : 00010000 x-1 : 00001111 ``` -令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位及以上数: +令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位以上数: ``` y : 10110010 @@ -449,7 +451,7 @@ y%x : 00000010 拉链法需要使用除留余数法来得到桶下标,也就是需要进行以下计算:hash%capacity,如果能保证 capacity 为 2 的幂次方,那么就可以将这个操作转换位位运算。 -以下操作在 Java 8 中没有,但是原理上相同。 +以下操作在 JDK 1.8 中没有,但是原理上相同。 ```java static int indexFor(int h, int length) { @@ -472,7 +474,7 @@ new capacity : 00100000 ### 7. 扩容-计算数组容量 -先考虑如何求一个数的补码,对于 10010000,它的掩码为 11111111,可以使用以下方法得到: +先考虑如何求一个数的掩码,对于 10010000,它的掩码为 11111111,可以使用以下方法得到: ``` mask |= mask >> 1 11011000 @@ -480,9 +482,14 @@ mask |= mask >> 2 11111100 mask |= mask >> 4 11111111 ``` -如果最后令 mask+1,得到就是大于原始数字的最小的 2 次方。 +mask+1 是大于原始数字的最小的 2 次方。 -以下是 HashMap 中计算一个大小所需要的数组容量的代码: +``` +num 10010000 +mask+1 100000000 +``` + +以下是 HashMap 中计算数组容量的代码: ```java static final int tableSizeFor(int cap) { @@ -508,10 +515,6 @@ HashMap 允许有一个 Node 的 Key 为 null,该 Node 一定会放在第 0 - 由于 Hashtable 是线程安全的也是 synchronized,所以在单线程环境下它比 HashMap 要慢。 - HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。 -## LinkedHashMap - -[LinkedHashMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/HashMap.java) - ## ConcurrentHashMap - JDK 1.7 [ConcurrentHashMap.java](https://github.com/CyC2018/JDK-Source-Code/blob/master/src/1.7/ConcurrentHashMap.java) diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index f3f229d8..0cee7066 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -190,7 +190,7 @@ You have 3 cookies and their sizes are big enough to gratify all of the children You need to output 2. ``` -题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。 +题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。 因为最小的孩子最容易得到满足,因此先满足最小孩子。给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。 diff --git a/notes/正则表达式.md b/notes/正则表达式.md index 1252be08..e21a85c5 100644 --- a/notes/正则表达式.md +++ b/notes/正则表达式.md @@ -231,7 +231,7 @@ a.+c **正则表达式** ``` -(((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}(((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))) +((25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d))\.){3}(25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d)) ``` **匹配结果** diff --git a/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png b/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png new file mode 100644 index 00000000..df5be529 Binary files /dev/null and b/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png differ