Skip to content

Commit 51fb570

Browse files
committed
红黑树完善
1 parent ec99316 commit 51fb570

File tree

11 files changed

+592
-14
lines changed

11 files changed

+592
-14
lines changed

.idea/inspectionProfiles/Project_Default.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

HashTable/README.md

+12-11
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class Solution {
3333
}
3434
}
3535
```
36-
  可以发现最后运行的效率特别低,所以可以对此进行更改底层实现。在题目的下方标注着:**注意事项:您可以假定该字符串只包含小写字母。**
37-
所以说可以使用固定的数组来进行实现。数组大小为 26,数组索引的方式`char - 'a'`通过这样的方式来找到对应的字符。
36+
  可以发现最后运行的效率特别低,所以可以对此进行更改底层实现。在题目的下方标注着:
37+
**注意事项:您可以假定该字符串只包含小写字母。**
38+
  所以说可以使用固定的数组来进行实现。数组大小为 26,数组索引的方式`char - 'a'`通过这样的方式来找到对应的字符。
3839
**使用数组程序实现:**
3940
```java
4041
class Solution {
@@ -74,7 +75,7 @@ class Solution {
7475
7576
具体素数取什么,有人已经给出了结论。
7677
<div align=center>
77-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/hashFun.png width=40% alt=哈希函数模值的取值>
78+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/hashFun.png width=22% alt=哈希函数模值的取值>
7879
</div>
7980

8081
+ lwr:数据大小的下界
@@ -87,7 +88,7 @@ class Solution {
8788
&emsp;&emsp;我们知道在我们的计算机当中,对于浮点数的存储也是采用二进制的形式,只不过计算机解析成了浮点数。下面以32位计算机为例。
8889

8990
<div align=center>
90-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/floatSave.png width=80% alt=浮点数的存储>
91+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/floatSave.png width=50% alt=浮点数的存储>
9192
</div>
9293

9394
存储方式同整型相同,所以仍然可以将浮点数按照整型进行处理。
@@ -108,7 +109,7 @@ Java = J \times I^3 + a \times I^2 + v \times I^1 + a \times I^0
108109
$$
109110
&emsp;&emsp; I 表示进制,I的数值表示所代表类型的大小。对于字符串产生的这种大整型,我们可以按照2.1节那种,对大整型进行取模。
110111
$$
111-
hash(Java) = (J \times I^3 + a \times I^2 + v \times I^1 + a \times I^0) \% M
112+
hash(Java) = (J \times I^3 + a \times I^2 + v \times I^1 + a \times I^0) \% M
112113
$$
113114
化简可得:
114115
$$
@@ -160,31 +161,31 @@ class Dog{
160161
&emsp;&emsp;根据前面讲解的哈希表的哈希函数,需要对大整型进行取模的操作,其实最后的存储的数据大小就是模值。存储的方式就是采用和动态数组类似的方式,底层采用数组的方式存储。
161162

162163
<div align=center>
163-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/Save.png width=15% alt=底层数组存储>
164+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/Save.png width=8% alt=底层数组存储>
164165
</div>
165166

166167
具体存储到哪个索引的位置就要根据我们的哈希函数设计了。
167168

168169
<div align=center>
169-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-add.png width=30% alt=>
170+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-add.png width=18% alt=>
170171
</div>
171172
<br/>
172173
<p align=center><b>index = ( hashCode(s1) & 0x7fffffff ) % M</b></p>
173174

174175
&emsp;&emsp;在前面中说到 Java 中的 hasCode 可以返回负值,但是数组索引没有负值,所以需要将最前面的符号位设置为零。
175176
**添加两个元素后:**
176177
<div align=center>
177-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-two.png width=24% alt=添加两个元素>
178+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-two.png width=15% alt=添加两个元素>
178179
</div>
179180

180181
&emsp;&emsp;当添加第三个元素(s3)的时候,假设获得的索引依然是 2 。这样就产生了**哈希冲突**。那么我们就需要将新添加的元素 s3 放到 s1 后面,类似于链表的形式。
181182
<div align=center>
182-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-three.png width=33% alt=哈希冲突>
183+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/save-three.png width=20% alt=哈希冲突>
183184
</div>
184185

185186
&emsp;&emsp;当然前面的形式我们采用链表的形式,其实对于每一个索引位置我们可以索引一个树结构,也就降低了时间复杂度。类似于下面的形式。
186187
<div align=center>
187-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/HashMAP.png width=31% alt=TreeMap>
188+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/HashMAP.png width=20% alt=TreeMap>
188189
</div>
189190

190191
&emsp;&emsp;实际上**HashMap 的底层就是 TreeMap 数组;HashSet 的底层就是 TreeSet 数组;**
@@ -364,7 +365,7 @@ if (size < lowerTol * M && capacityIndex >= 1)
364365
**再分析发生扩容的情况:**
365366
&emsp;&emsp;当我们进行resize操作以后,我们可以发现,oldM 和 newM 之间大约有两倍的关系。
366367
<div align=center>
367-
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/hashFun2.png width=50% alt=精简版>
368+
<img src=https://markdown-liyang.oss-cn-beijing.aliyuncs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/11-HashTable/hashFun2.png width=30% alt=精简版>
368369
</div>
369370

370371
&emsp;&emsp;对于原本元素个数为 upperTol * oldM = N 的元素增加到 upperTol * newM = 2 * N,才触发一次resize操作,相当于进行了翻倍操作。resize的时间复杂度为O(N)级别的,但是需要增加N个元素才触发一次resize操作,所以根据均摊时间复杂度,增删两种操作的时间复杂度为O(2)级别的复杂度,改查操作的时间复杂度为O(1)级别。

RedBlackTree/RBTree.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private Node leftRotate(Node node) {
6868
private void flipColors(Node node) {
6969
node.color = RED;
7070
node.left.color = BLACK;
71-
node.right.color = RED;
71+
node.right.color = BLACK;
7272
}
7373

7474
private Node rightRotate(Node node) {

0 commit comments

Comments
 (0)