Repository navigation
Expand file tree
/
Copy pathatom.xml
More file actions
586 lines (284 loc) · 147 KB
/
Copy pathatom.xml
File metadata and controls
586 lines (284 loc) · 147 KB
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
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>WenQian Dong's Web</title>
<subtitle>Coder,Java,Linux,Google Fans</subtitle>
<link href="https://wqdchn.github.io/atom.xml" rel="self"/>
<link href="https://wqdchn.github.io/"/>
<updated>2024-02-17T01:39:55.115Z</updated>
<id>https://wqdchn.github.io/</id>
<author>
<name>WenQian Dong</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>请回答 2021</title>
<link href="https://wqdchn.github.io/reply-2021.html"/>
<id>https://wqdchn.github.io/reply-2021.html</id>
<published>2022-01-03T04:46:59.000Z</published>
<updated>2024-02-17T01:39:55.115Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="0X0001"><a href="#0X0001" class="headerlink" title="0X0001"></a>0X0001</h4><p>今年参加了一场朋友的婚礼,又是为爱情落泪的一次。也见到许久不见的朋友,心里有股火热。我们都在路上向远方走去,又过了一年,我有时会回想过去的那些年,那时的烦恼多么天真,哈哈。回家的时候,没有去那些老地方看看,有些遗憾,还是太懒散了。</p><h4 id="0X0002"><a href="#0X0002" class="headerlink" title="0X0002"></a>0X0002</h4><p>这一年经历了许多,依然有好多东西没有学会,有认识到最重要的是控制自己的情绪和欲望,却做不到做不好,怎么办呢。路漫漫其修远兮,吾将上下而求索,一个人在路上也挺孤独,还好我习惯了。</p><p>2021年过去了,我永远想念这一年遇见的人与事。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="0X0001"><a href="#0X0001" class="headerlink" title="0X0001"></a>0X0001</h4><p>今年参加了一场朋友的婚礼,又是为爱情落泪的一次。也见到许久不</summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="新年" scheme="https://wqdchn.github.io/tags/%E6%96%B0%E5%B9%B4/"/>
</entry>
<entry>
<title>Aloha Heja He</title>
<link href="https://wqdchn.github.io/aloha-heja-he.html"/>
<id>https://wqdchn.github.io/aloha-heja-he.html</id>
<published>2020-08-09T13:18:30.000Z</published>
<updated>2024-02-17T01:39:54.994Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="我曾看过整个世界"><a href="#我曾看过整个世界" class="headerlink" title="我曾看过整个世界"></a>我曾看过整个世界</h3><p>这首《Aloha Heja He》是最近的心头好,旋律和那句 Aloha Heja He 有点让我陶醉。歌词似乎是一个旅行者的自吟自唱,我曾看过整个世界,那曾经是一段艰难的旅程。</p><p>Hab’ die ganze Welt geseh’n<br>我曾看过整个世界</p><p>Von Singapur bis Aberdeen<br>从新加坡到阿伯丁</p><p>Wenn du mich fragst wo’s am sch?nsten war<br>你要问我那里最美</p><p>Sag’ ich Sansibar!<br>我会说是桑西巴尔</p><p>Es war ‘ne harte überfahrt –<br>那曾经是一段艰难的旅程</p><p>Zehn Wochen nur das Deck geschrubbt<br>十个星期都在海浪中浮沉</p><p>Hab’ die Welt verflucht<br>我曾诅咒世界</p><p>In den Wind gespuckt<br>曾对暴风唾骂</p><p>Und salziges Wasser geschluckt!<br>也吞下过咸涩海水</p><p>Als wir den Anker warfen war es himmlische Ruh’<br>当我们抛下锚后 是极其美妙的平静</p><p>Und die Sonne stand senkrecht am Himmel<br>阳光也重新照耀我们</p><p>Als ich über die Reeling sah<br>绞盘后我看到</p><p>Da glaubte ich zu tr?umen –<br>我还以为是梦境——</p><p>Da war’n tausend Boote und sie hielten auf uns zu!<br>那是数千艘船 朝着我们驶来</p><p>In den Booten waren M?nner und Frau’n<br>船上站着男男女女</p><p>Ihre Leiber gl?nzten in der Sonne<br>在阳光下引人注目</p><p>Und sie sangen ein Lied<br>他们唱着一支歌</p><p>Das kam mir seltsam bekannt vor<br>歌声让我感觉异常亲切</p><p>Aber so hab’ ich’s noch nie geh?rt<br>但是我却从未听过</p><p>Uhhhh, so hab’ ich’s noch nie geh?rt!<br>喔,我却从未听过</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~(这是瑞典语加油加油的意思)</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Ihre Boote machten l?ngsseits fest<br>他们的船并排停下</p><p>Und mit dem Wind wehte Gel?chter herüber<br>笑声随风飘扬过来</p><p>Sie nahmen ihre Blumenkr?nze ab<br>他们取下头上花冠</p><p>Und warfen sie zu uns herüber<br>然后扔向我们</p><p>Hehhhh, und schon war die Party im Gange!<br>狂欢已经开始</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈 嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈 嘿呀 嘿~</p><p>Ich hab’ das Paradies geseh’n<br>我看到了天堂</p><p>Es war um neunzehnhundertzehn!<br>在那1910年</p><p>Der Steuermann hatte Matrosen am Mast<br>大副让水手们守在桅杆旁</p><p>Und den Zahlmeister ha’m die Gonokokken vernascht –<br>军需官遭受了淋球菌感染</p><p>Aber sonst war’n wir bei bester Gesundheit!<br>但除此之外我们一切健康</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja he<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><p>Aloha heja he – aloha heja he, aloha heja . . .<br>阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿阿啰哈嘿呀 嘿~</p><iframe width="560" height="480" src="https://www.youtube.com/embed/R8SceCpeekw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="我曾看过整个世界"><a href="#我曾看过整个世界" class="headerlink" title="我曾看过整个世界"></a>我曾看过整个世界</h3><p>这首《Aloha Heja He》是最近的心</summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="音乐" scheme="https://wqdchn.github.io/tags/%E9%9F%B3%E4%B9%90/"/>
</entry>
<entry>
<title>庚子年·仲夏记事</title>
<link href="https://wqdchn.github.io/how-is-going-2020-08-01.html"/>
<id>https://wqdchn.github.io/how-is-going-2020-08-01.html</id>
<published>2020-08-01T15:01:57.000Z</published>
<updated>2024-02-17T01:39:55.034Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="最近的事"><a href="#最近的事" class="headerlink" title="最近的事"></a>最近的事</h3><p>离开学校的第一个月,作息上有些不太习惯,哈哈。工作的事正在学习和摸索中,应该可以尽快上手吧,哈哈。这段时间静心思考的时间比较少了,即使是周末稍有时间了,好像也只瘫在床上不想动了,本站和 Github 更新的频率都下降了,这个节奏不太对呀。</p><p>天气越来越热,开始有夏天的感觉了,我喜欢夏天。不过好久没正经去西湖边晃一晃,看看人群和风景了,八月的周末要出去走走吧。</p><p>还有就是要坚持锻炼身体,周末的晚上要跑上几公里,争取越跑越远。</p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="最近的事"><a href="#最近的事" class="headerlink" title="最近的事"></a>最近的事</h3><p>离开学校的第一个月,作息上有些不太习惯,哈哈。工作的事正在学习和摸索中,应该</summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="记事" scheme="https://wqdchn.github.io/tags/%E8%AE%B0%E4%BA%8B/"/>
</entry>
<entry>
<title>庚子年·夏至记事</title>
<link href="https://wqdchn.github.io/how-is-going-2020-06-30.html"/>
<id>https://wqdchn.github.io/how-is-going-2020-06-30.html</id>
<published>2020-06-30T11:26:57.000Z</published>
<updated>2024-02-17T01:39:55.034Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="最近的事"><a href="#最近的事" class="headerlink" title="最近的事"></a>最近的事</h3><p>二零二零年上半年的最后一天,闲下来写一个随笔,回想一下最近的事。</p><p>很高兴的是自己顺利毕业了,这是一件值得庆祝的事。同时也有些伤感,要与熟悉的学校、亲爱的老师告别,要与学生时代告别了。</p><p>刚刚离开学校的几天,我还有些不太适应,不知道该去哪里学习,哪里吃饭,好像一下子找不到北了。</p><p>不过另一件事很快让我暂时忘却了这些,那就是令人头疼的驾照考试。我努力趁着最后一段闲暇的空档期,抓紧练车考试。然而结果还是半喜半忧,差一点点运气,差一点点实力,换句话说,细节真的很重要喔。</p><p>整理好心态,等待七月,我要重新出发了,祝我好运。</p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="最近的事"><a href="#最近的事" class="headerlink" title="最近的事"></a>最近的事</h3><p>二零二零年上半年的最后一天,闲下来写一个随笔,回想一下最近的事。</p>
<</summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="记事" scheme="https://wqdchn.github.io/tags/%E8%AE%B0%E4%BA%8B/"/>
</entry>
<entry>
<title>庚子年·初夏记事</title>
<link href="https://wqdchn.github.io/how-is-going-2020-05-31.html"/>
<id>https://wqdchn.github.io/how-is-going-2020-05-31.html</id>
<published>2020-05-31T01:45:44.000Z</published>
<updated>2024-02-17T01:39:55.034Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="最近的人"><a href="#最近的人" class="headerlink" title="最近的人"></a>最近的人</h3><p>认识了一些有趣的网友,隔着网线隔着屏幕也能感受到对方所说的种种有趣的事,真是神奇。这是网上冲浪最大的乐趣了吧,不再关心那些国家大事,世界风云。就看看沙雕网友们又在讨论什么好吃的,好玩的,哈哈哈哈哈就挺好的。不过在资本掌控舆论的时代,这些没有流量的小事很难被人发现吧,真正寻找到这样的网友,看到他们在自己的一亩三分地上说说闹闹,也不太容易。</p><h3 id="最近的物"><a href="#最近的物" class="headerlink" title="最近的物"></a>最近的物</h3><p>五月中下旬的时候,杨梅已经上市了,昨天在水果店买了一盒杨梅,真的难吃,感觉是放了好久没卖出的、不新鲜的杨梅。等六月的时候,我一定要补回来,不能错过杨梅这样的好东西!</p><h3 id="最近的事"><a href="#最近的事" class="headerlink" title="最近的事"></a>最近的事</h3><p>2020 年也快过去小一半了,恍惚间有些不太真实,我真的有认真度过每一天吗。如果有的话,我怎么看不太明白身边发生的事呢。一场疫情,从全世界都盯着中国,发展到现在各个国家都自顾不暇。太平洋对岸最近还发生了暴乱,他们倒是很利索地就出动了武装力量平乱,完全没有当初香港暴乱时劝告中国政府时的那种异常理智与冷静了,思之令人发笑。</p><p>但是重点并不在比较当初他们是怎么做的和现在他们是怎么做的,我相信有比我更加聪明的人会研究这些事情。我所关心的是,作为一个普通人,该如何在扰乱的信息流中获取自己的喘息之机。每天都有那么多新闻,国内的国外的,有些肮臜事令人愤怒而气血上涌,有些破烂事前后反复反转令人迷茫而不知所措。一个普通人,看到这些事情的时候,总觉得自己能做些什么,但是其实好像什么也做不了。而当自己觉得做不了什么的时候,又会觉得这样好像就让什么人得逞了一样。</p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="最近的人"><a href="#最近的人" class="headerlink" title="最近的人"></a>最近的人</h3><p>认识了一些有趣的网友,隔着网线隔着屏幕也能感受到对方所说的种种有趣的事,真是</summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="记事" scheme="https://wqdchn.github.io/tags/%E8%AE%B0%E4%BA%8B/"/>
</entry>
<entry>
<title>Java基础:类加载过程</title>
<link href="https://wqdchn.github.io/java-basic-classloader.html"/>
<id>https://wqdchn.github.io/java-basic-classloader.html</id>
<published>2020-04-14T00:15:47.000Z</published>
<updated>2024-02-17T01:39:55.035Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="类加载过程"><a href="#类加载过程" class="headerlink" title="类加载过程"></a>类加载过程</h3><p>一般来说,Java 的类加载过程分为三个主要步骤:加载、链接、初始化,细节部分在<a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html">Java 虚拟机规范</a>中有详细介绍。</p><p>Java 的语言类型可以分为基本类型和引用类型。基本类型是 Java 虚拟机预先定义好的。引用类型中,Java将其细分为:类、接口、数组类和泛型参数,泛型参数在编译过程中会被擦除(没看懂啥意思??),数组类是 JVM 直接生成的,另外两种则有对应的字节流。</p><p>最常见的字节流就是 Java 编译生成的 class 文件,Java 将来自不同数据源的字节流读取到 JVM 中生成类或接口就是类加载过程,这里的数据源可能是 jar 包、class文件等等。</p><h3 id="加载"><a href="#加载" class="headerlink" title="加载"></a>加载</h3><p>加载,是指查找字节流,并根据字节流创建类的过程。JVM 中有三种类加载器:启动类加载器、扩展类加载器、应用类加载器,每种类加载器加载一部分类。加载阶段,类的唯一性通过类加载器名称和类全面来共同确定,因此不同类加载器加载同一串字节流也会生成两个不同的类。</p><p>启动类加载器(Bootstrap Class Loader)加载最基础、最重要的类,比如 lib/ 目录下 jar 包中的类。</p><p>扩展类加载器(Extension Class Loader)的父-类加载器是启动类加载器,它负责加载 lib/ext/ 目录下的 jar 包,即所谓的 extension 机制。</p><p>应用类加载器(Application Class Loader)的父-类加载器是扩展类加载器,它负责加载应用程序路径下的类,这个应用程序路径一般是环境变量 classpath 指定的路径。</p><h3 id="链接"><a href="#链接" class="headerlink" title="链接"></a>链接</h3><p>链接是指将创建成的类合并到 JVM 中,使之能够被执行的过程,这是类加载的核心步骤。链接阶段又可分为验证、准备、解析三个子阶段。</p><p>验证阶段要核验字节信息是否符合JVM 规范,保证加载类能够满足JVM 的约束条件。</p><p>准备阶段,创建并为被加载的类的静态字段分配内存,注意,这里并不会做一般意义上的显式初始化,而只是创建变量并为变量开辟内存空间,做默认的初始化。例如我们 int a = 1,那么在链接的准备阶段,这个 a 的值是 0,并不会赋值为 1。</p><p>在准备阶段,还有一个重要的工作,就是为类构造相关的数据结构,例如实现动态绑定的方法表。在 class 文件被加载至 JVM 之前,一个类无法知道自己和其他类的其方法、字段所对应的具体地址。Java编译时会生成一个符号引用,通过符号引用来无歧义得定位到具体目标上。</p><p>举例来说,对于一个方法调用,编译器会生成一个包含目标方法所在类的名字、目标方法的名字、接收参数类型以及返回值类型的符号引用,来指代所要调用的方法。</p><p>解析阶段就是要将符号引用解析为直接引用或实际引用。但是解析阶段的发生是不确定的,它可能在初始化步骤之前,也可能在初始化步骤之后。同时,在类加载的过程中,所有步骤、阶段是按顺序开始,但并不是一定按顺序进行或完成的。</p><h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h3><p>类加载的最后一步是初始化,这一步真正去执行类初始化的代码逻辑,包括静态字段赋值的动作,以及执行类定义中的静态初始化块内的逻辑,编译器在编译阶段就会把这部分逻辑整理好,父类型的初始化逻辑优先于当前类型的逻辑。</p><p>JVM 规范枚举了下述多种触发情况:</p><ol><li>当虚拟机启动时,初始化用户指定的主类;</li><li>当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;</li><li>当遇到调用静态方法的指令时,初始化该静态方法所在的类;</li><li>当遇到访问静态字段的指令时,初始化该静态字段所在的类;</li><li>子类的初始化会触发父类的初始化;</li><li>如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;</li><li>使用反射 API 对某个类进行反射调用时,初始化这个类;</li><li>当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。</li></ol><p>只有初始化完成之后,一个类才能真正成为可执行的状态。</p><h3 id="双亲委派"><a href="#双亲委派" class="headerlink" title="双亲委派"></a>双亲委派</h3><p>双亲委派模型,简单说就是当类加载器(Class Loader)试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载 Java 类型。</p><h3 id="NoClassDefFoundError-和-ClassNotFoundException"><a href="#NoClassDefFoundError-和-ClassNotFoundException" class="headerlink" title="NoClassDefFoundError 和 ClassNotFoundException"></a>NoClassDefFoundError 和 ClassNotFoundException</h3><p>NoClassDefFoundError 在官方文档中解释是要使用的类的编译时还找得到,但是到了运行的时候找不到了,那么此时就会抛出这个异常。例如,我编译了一个类 B,在类 A 中调用类 B 的方法,但是编译之后我删除了类 B 的 class 文件,此时运行类 A 就会报错 NoClassDefFoundError。</p><p>ClassNotFoundException 情况就比较多了,当通过以下方法来加载类的时候,</p><ol><li>类 Class 中的 forName() 方法</li><li>类 ClassLoader 中的 findSystemClass() 方法</li><li>类 ClassLoader 中的 loadClass() 方法</li></ol><p>但是没有找到具体指定的名称的类的定义,就会报错 ClassNotFoundException。</p><p>从类加载过程来看 NoClassDefFoundError 和 ClassNotFoundException。在加载阶段,如果从 classpath 等路径中找不到所需的类,那么就会报错 ClassNotFoundException,除了上面的三种原因之外,还有可能是因为类被不同类加载器重复加载了导致的。而 NoClassDefFoundError 是在链接步骤中,从内存找不到所需的类,那么就会报错 NoClassDefFoundError。</p><p>总结就是,加载时从外存储器找不到需要的 class 就出现 ClassNotFoundException ,链接时从内存找不到需要的 class 就出现 NoClassDefFoundError 。</p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="类加载过程"><a href="#类加载过程" class="headerlink" title="类加载过程"></a>类加载过程</h3><p>一般来说,Java 的类加载过程分为三个主要步骤:加载、链接、初始</summary>
<category term="Java" scheme="https://wqdchn.github.io/categories/Java/"/>
<category term="Java" scheme="https://wqdchn.github.io/tags/Java/"/>
<category term="JVM" scheme="https://wqdchn.github.io/tags/JVM/"/>
<category term="类加载" scheme="https://wqdchn.github.io/tags/%E7%B1%BB%E5%8A%A0%E8%BD%BD/"/>
</entry>
<entry>
<title>Java基础:多态</title>
<link href="https://wqdchn.github.io/java-basic-polymorphism.html"/>
<id>https://wqdchn.github.io/java-basic-polymorphism.html</id>
<published>2020-04-09T23:09:22.000Z</published>
<updated>2024-02-17T01:39:55.035Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>我们知道,面向对象的基本要素是封装、继承、多态。其中多态也叫动态绑定,是指程序在执行期间,判断所引用的对象的实际类型,根据实际类型来调用其相应的方法。以下面的代码为例,</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PolymorphTest</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Animal</span> <span class="variable">animal</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">"小白"</span>, <span class="string">"白色"</span>);</span><br><span class="line"> <span class="type">Animal</span> <span class="variable">animal2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Cat</span>(<span class="string">"小橘"</span>, <span class="string">"黑色"</span>);</span><br><span class="line"> </span><br><span class="line"> animal.eat();</span><br><span class="line"> animal2.eat();</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="keyword">class</span> <span class="title class_">Animal</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"> Animal(String name) {</span><br><span class="line"> <span class="built_in">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">eat</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"动物在吃东西"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> <span class="keyword">extends</span> <span class="title class_">Animal</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String Color; <span class="comment">// 肤色</span></span><br><span class="line"></span><br><span class="line"> Dog(String name, String Color) {</span><br><span class="line"> <span class="built_in">super</span>(name);</span><br><span class="line"> <span class="built_in">this</span>.Color = Color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">eat</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"小狗在吃骨头"</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="keyword">class</span> <span class="title class_">Cat</span> <span class="keyword">extends</span> <span class="title class_">Animal</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String eyeColor; <span class="comment">// 眼睛色</span></span><br><span class="line"></span><br><span class="line"> Cat(String name, String eyeColor) {</span><br><span class="line"> <span class="built_in">super</span>(name);</span><br><span class="line"> <span class="built_in">this</span>.eyeColor = eyeColor;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">eat</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"小猫在吃小鱼干"</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><br><span class="line">小狗在吃骨头</span><br><span class="line">小猫在吃小鱼干</span><br></pre></td></tr></table></figure><p>程序在执行 Animal animal = new Dog(“小白”, “白色”) 时,栈空间内会有一个变量 animal ,animal 指向堆空间中 new 出来的 Dog 对象。在 new 这个 Dog 对象的时候,首先会调用父类 Animal 的构造方法,把名字小白传递给构造方法 Animal(String name) ,然后再初始化自己的私有成员变量 Color。这样,当 Dog 对象的构造方法 Dog(String name, String Color) 执行完毕之后,内存空间中就出现了一个 Dog 对象和一个 Dog 对象的引用 animal 变量,这个 Dog 对象有自己的私有成员变量 Color,同时,Dog 对象中还包含了一个父类的 Animal 对象,这个 Animal 对象中包含了 Dog 对象的名字。</p><p>在方法区中,则存在两个 eat() 方法,分别是父类 Animal 对象的 eat() 方法和子类 Dog 对象的 eat() 方法,当我们执行 animal 的 eat 方法调用时,多态就发挥作用了,它会根据实际 new 出来的对象去取得对应的方法,并执行,所以我们看见了 小狗在吃骨头 而不是 动物在吃东西。</p><p>这里,我们小结一下,多态是指程序在执行期间,判断所引用的对象的实际类型,根据实际类型来调用其相应的方法,实现多态需要三个条件,分别是要有继承,子类要重写 Override 父类的方法,父类引用指向子类对象。</p><h3 id="多态的实现"><a href="#多态的实现" class="headerlink" title="多态的实现"></a>多态的实现</h3><p>那么多态是怎么实现的呢?回想一下类的加载机制,在类加载的准备阶段,Java 虚拟机会为类的静态字段分配内存,同时构造与该类相关联方法表,这个方法表就是实现动态绑定也就是多态的关键所在。</p><p>方法表本质是一个数组,它存储了当前类及其父类中非私有的实例方法。在动态绑定过程中,程序会访问栈空间上的调用者,根据其指向的对象取得调用者的实际类型,然后读取该类型的方法表,进而读取方法表中某个索引下对应的目标方法。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>关于多态更加细致的实现暂时先不讨论了,先了解到这里吧。</p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>我们知道,面向对象的基本要素是封装、继承、多态。其中多态也叫动态绑定,是指程序在执行期间,</summary>
<category term="Java" scheme="https://wqdchn.github.io/categories/Java/"/>
<category term="Java" scheme="https://wqdchn.github.io/tags/Java/"/>
<category term="多态" scheme="https://wqdchn.github.io/tags/%E5%A4%9A%E6%80%81/"/>
</entry>
<entry>
<title>对比Hashtable、HashMap、TreeMap有什么不同?</title>
<link href="https://wqdchn.github.io/java-hashtable-hashmap-treemap.html"/>
<id>https://wqdchn.github.io/java-hashtable-hashmap-treemap.html</id>
<published>2020-04-01T00:14:00.000Z</published>
<updated>2024-02-17T01:39:55.036Z</updated>
<content type="html"><</p><p> Hashtable 继承自 Dictionary 类,而 HashMap 与 TreeMap 继承 AbstractMap 类,它们的类结构上是不同的,不同的实现表明了它们不同的设计目的。</p><p> Hashtable 是 Java 类库关于哈希表的一个早期实现,它的方法都使用 synchronized 进行同步,是线程安全的。 Hashtable 不允许 key 为 null ,不允许 value 为 null 。 </p><p> HashMap 是使用最广的一种哈希表实现,大部分方法与 Hashtable 是相似的,但是减少了同步开销,因此是线程不安全的。 HashMap 允许 key 为 null ,允许 value 为 null 。</p><p> TreeMap 是基于红黑树的一种提供顺序访问的 Map ,与前两者不同,它的 put() 、 get() 等操作的时间复杂度都是 O(log(n)) 。其顺序可以通过 Comparator 来决定,或者根据键值的自然顺序 Comparable 来决定。它也是线程不安全的。 TreeMap 不允许 key 为 null ,允许 value 为 null 。</p><p>对于 TreeMap ,当实现 Comparator 接口时,若未对 null 情况进行判断,则可能抛 NullPointerException 异常。如果针对 null 情况实现了特别处理,则可以 put() 存入,但是却不能正常使用 get() 访问,只能通过遍历去访问。</p><p>因此,建议遵循设计的规范,不要做这种使用错误。例如 HashMap 明确声明是线程不安全的,如果不加考虑,直接简单地应用在多线程场景中,总是要出问题的。</p><h3 id="HashMap的实现"><a href="#HashMap的实现" class="headerlink" title="HashMap的实现"></a>HashMap的实现</h3><p> HashMap 的底层是数组和链表组成的复合结构,数组被分成桶 bucket ,里面存放哈希值,通过哈希值来确定数组寻址时的数组下标。哈希值相同的键值对则以链表的形式存储,如果链表的长度超过阈值 TREEIFY_THRESHOLD = 8 ,则对链表进行改造,转化为红黑树。当红黑树的节点小于阈值 UNTREEIFY_THRESHOLD = 6 时,则对红黑树进行改造,转化为链表。我想这是为了避免链表在阈值附近频繁地转换造成过大的开销而设置的两个临界点。</p><h3 id="HashMap的工作流程"><a href="#HashMap的工作流程" class="headerlink" title="HashMap的工作流程"></a>HashMap的工作流程</h3><h4 id="存储对象"><a href="#存储对象" class="headerlink" title="存储对象"></a>存储对象</h4><p>存储对象时,将键值对 K/V 传给 put() 方法:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> V <span class="title function_">put</span><span class="params">(K key, V value)</span> {</span><br><span class="line"> <span class="keyword">return</span> putVal(hash(key), key, value, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后调用 hash() 方法计算 K 的哈希值:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hash</span><span class="params">(Object key)</span> {</span><br><span class="line"> <span class="type">int</span> h;</span><br><span class="line"> <span class="keyword">return</span> (key == <span class="literal">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h >>> <span class="number">16</span>);</span><br><span class="line">}</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line">这里进行了一个 hashCode() 高位数据移位到低位 h >>> <span class="number">16</span> 并进行异或运算 ^ 的操作。将高位和低位进行异或运算,只要有高位或低位中有一位的变化,整个 hash() 返回的哈希值就会发生变化,尽可能地减少哈希碰撞。</span><br><span class="line"></span><br><span class="line">在计算得到数组下标之后,通过 putVal() 方法进行存储, putVal() 方法本身的逻辑非常密集,从初始化、扩容、树化都与它有关:</span><br><span class="line"></span><br><span class="line">```Java</span><br><span class="line"><span class="keyword">final</span> V <span class="title function_">putVal</span><span class="params">(<span class="type">int</span> hash, K key, V value, <span class="type">boolean</span> onlyIfAbsent,</span></span><br><span class="line"><span class="params"> <span class="type">boolean</span> evict)</span> {</span><br><span class="line"> Node<K,V>[] tab; Node<K,V> p; <span class="type">int</span> n, i;</span><br><span class="line"> <span class="keyword">if</span> ((tab = table) == <span class="literal">null</span> || (n = tab.length) == <span class="number">0</span>)</span><br><span class="line"> n = (tab = resize()).length;</span><br><span class="line"> <span class="keyword">if</span> ((p = tab[i = (n - <span class="number">1</span>) & hash]) == <span class="literal">null</span>)</span><br><span class="line"> tab[i] = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> Node<K,V> e; K k;</span><br><span class="line"> <span class="keyword">if</span> (p.hash == hash &&</span><br><span class="line"> ((k = p.key) == key || (key != <span class="literal">null</span> && key.equals(k))))</span><br><span class="line"> e = p;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (p <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line"> e = ((TreeNode<K,V>)p).putTreeVal(<span class="built_in">this</span>, tab, hash, key, value);</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">binCount</span> <span class="operator">=</span> <span class="number">0</span>; ; ++binCount) {</span><br><span class="line"> <span class="keyword">if</span> ((e = p.next) == <span class="literal">null</span>) {</span><br><span class="line"> p.next = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line"> <span class="keyword">if</span> (binCount >= TREEIFY_THRESHOLD - <span class="number">1</span>) <span class="comment">// -1 for 1st</span></span><br><span class="line"> treeifyBin(tab, hash);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e.hash == hash &&</span><br><span class="line"> ((k = e.key) == key || (key != <span class="literal">null</span> && key.equals(k))))</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> p = e;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e != <span class="literal">null</span>) { <span class="comment">// existing mapping for key</span></span><br><span class="line"> <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> e.value;</span><br><span class="line"> <span class="keyword">if</span> (!onlyIfAbsent || oldValue == <span class="literal">null</span>)</span><br><span class="line"> e.value = value;</span><br><span class="line"> afterNodeAccess(e);</span><br><span class="line"> <span class="keyword">return</span> oldValue;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ++modCount;</span><br><span class="line"> <span class="keyword">if</span> (++size > threshold)</span><br><span class="line"> resize();</span><br><span class="line"> afterNodeInsertion(evict);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果哈希表为 null , resize() 方法会负责初始化 tab = resize() 。</p><p>当哈希表容量不足时,出现 ++size > threshold , resize() 方法还会进行扩容。默认的初始化容量参数和最大容量参数如下。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The default initial capacity - MUST be a power of two.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">DEFAULT_INITIAL_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> << <span class="number">4</span>; <span class="comment">// aka 16, 2的4次方</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MAXIMUM_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> << <span class="number">30</span>; <span class="comment">// 2的30次方</span></span><br></pre></td></tr></table></figure><p>如果 K 的 hash 值在 HashMap 中不存在,则执行插入,若存在,则发生碰撞。</p><p>如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 true ,则更新键值对。</p><p>如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 false,则插入链表的尾部(尾插法)或者红黑树中(树的添加方式)。</p><h4 id="获取对象"><a href="#获取对象" class="headerlink" title="获取对象"></a>获取对象</h4><p>获取对象时,将 K 传给 get() 方法:</p><p>调用 hash(K) 方法,计算 K 的 hash 值,从而获取该键值所在链表的数组下标。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> V <span class="title function_">get</span><span class="params">(Object key)</span> {</span><br><span class="line"> Node<K,V> e;</span><br><span class="line"> <span class="keyword">return</span> (e = getNode(hash(key), key)) == <span class="literal">null</span> ? <span class="literal">null</span> : e.value;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后顺序遍历链表,根据equals()方法查找相同 Node 链表中 K 值对应的 V 值。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">final</span> Node<K,V> <span class="title function_">getNode</span><span class="params">(<span class="type">int</span> hash, Object key)</span> {</span><br><span class="line"> Node<K,V>[] tab; Node<K,V> first, e; <span class="type">int</span> n; K k;</span><br><span class="line"> <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> && (n = tab.length) > <span class="number">0</span> &&</span><br><span class="line"> (first = tab[(n - <span class="number">1</span>) & hash]) != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (first.hash == hash && <span class="comment">// always check first node</span></span><br><span class="line"> ((k = first.key) == key || (key != <span class="literal">null</span> && key.equals(k))))</span><br><span class="line"> <span class="keyword">return</span> first;</span><br><span class="line"> <span class="keyword">if</span> ((e = first.next) != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (first <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line"> <span class="keyword">return</span> ((TreeNode<K,V>)first).getTreeNode(hash, key);</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="keyword">if</span> (e.hash == hash &&</span><br><span class="line"> ((k = e.key) == key || (key != <span class="literal">null</span> && key.equals(k))))</span><br><span class="line"> <span class="keyword">return</span> e;</span><br><span class="line"> } <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="扩容"><a href="#扩容" class="headerlink" title="扩容"></a>扩容</h4><p>扩容的方法比较复杂</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">float</span> <span class="variable">DEFAULT_LOAD_FACTOR</span> <span class="operator">=</span> <span class="number">0.75f</span>; <span class="comment">// 负载因子</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> Node<K,V>[] resize() {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> ((newCap = oldCap << <span class="number">1</span>) < MAXIMUM_CAPACIY &&</span><br><span class="line"> oldCap >= DEFAULT_INITIAL_CAPAITY)</span><br><span class="line"> newThr = oldThr << <span class="number">1</span>; <span class="comment">// double there</span></span><br><span class="line"> <span class="comment">// ... </span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldThr > <span class="number">0</span>) <span class="comment">// initial capacity was placed in threshold</span></span><br><span class="line"> newCap = oldThr;</span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> <span class="comment">// zero initial threshold signifies using defaultsfults</span></span><br><span class="line"> newCap = DEFAULT_INITIAL_CAPAITY;</span><br><span class="line"> newThr = (<span class="type">int</span>)(DEFAULT_LOAD_ATOR* DEFAULT_INITIAL_CAPACITY;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (newThr ==<span class="number">0</span>) {</span><br><span class="line"> <span class="type">float</span> <span class="variable">ft</span> <span class="operator">=</span> (<span class="type">float</span>)newCap * loadFator;</span><br><span class="line"> newThr = (newCap < MAXIMUM_CAPACITY && ft < (<span class="type">float</span>)MAXIMUM_CAPACITY ?(<span class="type">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line"> }</span><br><span class="line"> threshold = neThr;</span><br><span class="line"> Node<K,V>[] newTab = (Node<K,V>[])<span class="keyword">new</span> <span class="title class_">Node</span>[newap];</span><br><span class="line"> table = n;</span><br><span class="line"> <span class="comment">// 移动到新的数组结构e数组结构 </span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>如果负载因子 * 容量 > 元素数量,则会进行扩容。扩容时创建一个新的数组,其容量为旧数组的两倍,并重新计算旧数组中结点的存储位置。结点在新数组中的位置只有两种,原下标位置或原下标+旧数组的大小。</p><h4 id="树化改造"><a href="#树化改造" class="headerlink" title="树化改造"></a>树化改造</h4><p>在使用 put() 方法进行存储对象时,除了会遇到扩容方法,还有可能遇到树化改造:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MIN_TREEIFY_CAPACITY</span> <span class="operator">=</span> <span class="number">64</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">treeifyBin</span><span class="params">(Node<K,V>[] tab, <span class="type">int</span> hash)</span> {</span><br><span class="line"> <span class="type">int</span> n, index; Node<K,V> e;</span><br><span class="line"> <span class="keyword">if</span> (tab == <span class="literal">null</span> || (n = tab.length) < MIN_TREEIFY_CAPACITY)</span><br><span class="line"> resize();</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> ((e = tab[index = (n - <span class="number">1</span>) & hash]) != <span class="literal">null</span>) {</span><br><span class="line"> TreeNode<K,V> hd = <span class="literal">null</span>, tl = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> TreeNode<K,V> p = replacementTreeNode(e, <span class="literal">null</span>);</span><br><span class="line"> <span class="keyword">if</span> (tl == <span class="literal">null</span>)</span><br><span class="line"> hd = p;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> p.prev = tl;</span><br><span class="line"> tl.next = p;</span><br><span class="line"> }</span><br><span class="line"> tl = p;</span><br><span class="line"> } <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line"> <span class="keyword">if</span> ((tab[index] = hd) != <span class="literal">null</span>)</span><br><span class="line"> hd.treeify(tab);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果容量小于 MIN_TREEIFY_CAPACITY,只会进行简单的扩容。</p><p>如果容量大于 MIN_TREEIFY_CAPACITY ,则会进行树化改造。</p><p>HashMap 之所以要进行树化改造,是因为底层结构中链表的遍历时间复杂度是 O(N) 的,在哈希碰撞较为严重的时候,链表较长,其存取性能较低,还可能有额外的安全隐患。</p><h3 id="hashCode"><a href="#hashCode" class="headerlink" title="hashCode"></a>hashCode</h3><p>hashCode 是所有 Java 对象的固有方法,如果不重载的话,返回的实际上是该对象在 JVM 的堆上内存地址,而不同对象的内存地址肯定不同,所以这个 hashCode 也就肯定不同了。如果重载了的话,由于采用的算法的问题,有可能导致两个不同对象的hashCode相同。</p><h3 id="equals-的特性。"><a href="#equals-的特性。" class="headerlink" title="equals 的特性。"></a>equals 的特性。</h3><p>自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。<br>对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。<br>传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。<br>一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。<br>非空性:对于任何非空引用值 x,x.equals(null) 都应返回 false。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>大部分使用 Map 的场景,通常就是放入、访问或者删除,而对顺序没有特别要求,HashMap 在这种情况下基本是最好的选择。HashMap 的性能表现非常依赖于哈希码的有效性,请务必遵守 hashCode 和 equals 的一些基本约定:</p><ul><li>equals 相等,hashCode 一定要相等。</li><li>重写了 hashCode 也要重写 equals。</li><li>hashCode 需要保持一致性,状态改变返回的哈希值仍然要一致。</li></ul><p>以上内容都基于 jdk1.8.0_161 。</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650125459&idx=1&sn=56a14e497b5644eba72f034ac791a4d9&chksm=f36ba9b2c41c20a43611ef0d54747abdaf12f1f867ab23f2f0fc8eac87c657353c734f926cbb&scene=21#wechat_redirect">为啥 HashMap 的默认容量是16?</a><br><a href="https://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651486554&idx=1&sn=23a0786a8c401c799042ac7a9aa0e811&chksm=bd2515258a529c3312285c2536a92a7eb56805ded2eb726b72ab06beabe8e167d00d20789333&scene=126&sessionid=1585703424&key=e7b22394d9386bca990226e723bf6055c836e7d8b7dabe02034009cb225b77c844a21b5027ec82bfa738aa258fea0d41ca89603c0b8e93de1540103a2ec25a970c5c796cb2d499aaa6fce20c5e2772c3&ascene=1&uin=MTIzMjgzNDMyNw==&devicetype=Windows+10&version=62080079&lang=zh_CN&exportkey=AxuN6zS95LSdyZL9KQG5Oj0=&pass_ticket=LGstMxzdbnh6CyV6rurD3W6ylR1d9GRkDMmoMP80xAWiS91bl+2xlMkQ2wePQ23q">我说我了解集合类,面试官竟然问我为啥 HashMap 的负载因子不设置成1!?</a></p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="Map容器"><a href="#Map容器" class="headerlink" title="Map容器"></a>Map容器</h3><p>Map 通常被包括在 Java 集合框架中,但是其本身并不是真正的</summary>
<category term="Java" scheme="https://wqdchn.github.io/categories/Java/"/>
<category term="Java" scheme="https://wqdchn.github.io/tags/Java/"/>
<category term="容器" scheme="https://wqdchn.github.io/tags/%E5%AE%B9%E5%99%A8/"/>
<category term="集合" scheme="https://wqdchn.github.io/tags/%E9%9B%86%E5%90%88/"/>
<category term="哈希表" scheme="https://wqdchn.github.io/tags/%E5%93%88%E5%B8%8C%E8%A1%A8/"/>
</entry>
<entry>
<title>对比Vector、ArrayList、LinkedList有何区别?</title>
<link href="https://wqdchn.github.io/java-vector-arraylist-linkedlist.html"/>
<id>https://wqdchn.github.io/java-vector-arraylist-linkedlist.html</id>
<published>2020-03-31T00:24:58.000Z</published>
<updated>2024-02-17T01:39:55.037Z</updated>
<content type="html"><</p><h3 id="List集合"><a href="#List集合" class="headerlink" title="List集合"></a>List集合</h3><p> Vector 、 ArrayList 、 LinkedList 是 List 的实现,都是有序集合。它们都提供了诸如随机访问、添加、删除等常用操作,以及迭代器遍历、排序等方法,在功能上较为相近。但是其具体的设计存在一定区别,因此在性能、线程安全等方面有所不同。</p><p>常用方法:</p><ul><li>size() 集合元素个数</li><li>add()/addAll() 添加元素</li><li>remove()/removeAll() 删除元素</li><li>get() 获取元素</li><li>set() 修改元素</li><li>sort() 集合元素排序</li><li>toArray() 转换</li><li>clear() 清空集合</li></ul><h3 id="Vector"><a href="#Vector" class="headerlink" title="Vector"></a>Vector</h3><p> Vector 是 Java 早期提供的线程安全的动态数组,内部使用对象数组类保存数据,其线程安全通过 synchronized 实现。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E e)</span> {</span><br><span class="line"> modCount++;</span><br><span class="line"> ensureCapacityHelper(elementCount + <span class="number">1</span>);</span><br><span class="line"> elementData[elementCount++] = e;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">synchronized</span> E <span class="title function_">remove</span><span class="params">(<span class="type">int</span> index)</span> {</span><br><span class="line"> modCount++;</span><br><span class="line"> <span class="keyword">if</span> (index >= elementCount)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ArrayIndexOutOfBoundsException</span>(index);</span><br><span class="line"> <span class="type">E</span> <span class="variable">oldValue</span> <span class="operator">=</span> elementData(index);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">numMoved</span> <span class="operator">=</span> elementCount - index - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (numMoved > <span class="number">0</span>)</span><br><span class="line"> System.arraycopy(elementData, index+<span class="number">1</span>, elementData, index,</span><br><span class="line"> numMoved);</span><br><span class="line"> elementData[--elementCount] = <span class="literal">null</span>; <span class="comment">// Let gc do its work</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> oldValue;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> Vector 默认创建一个大小为 10 的 Object 数组,并将动态扩展大小 capacityIncrement 设置为 0 。 Vector 能够根据需要进行自动扩容,当数组已满时,会创建新的数组,并拷贝原有数据。在初始化时若指定了容量的动态扩展大小 capacityIncrement > 0 则依据指定的大小进行扩容,否则默认扩展一倍的容量。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">grow</span><span class="params">(<span class="type">int</span> minCapacity)</span> {</span><br><span class="line"> <span class="comment">// overflow-conscious code</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">oldCapacity</span> <span class="operator">=</span> elementData.length;</span><br><span class="line"> <span class="type">int</span> <span class="variable">newCapacity</span> <span class="operator">=</span> oldCapacity + ((capacityIncrement > <span class="number">0</span>) ?</span><br><span class="line"> capacityIncrement : oldCapacity);</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - minCapacity < <span class="number">0</span>)</span><br><span class="line"> newCapacity = minCapacity;</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - MAX_ARRAY_SIZE > <span class="number">0</span>)</span><br><span class="line"> newCapacity = hugeCapacity(minCapacity);</span><br><span class="line"> elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">Vector</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>(<span class="number">10</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">Vector</span><span class="params">(<span class="type">int</span> initialCapacity, <span class="type">int</span> capacityIncrement)</span> {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> <span class="keyword">if</span> (initialCapacity < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">"Illegal Capacity: "</span>+</span><br><span class="line"> initialCapacity);</span><br><span class="line"> <span class="built_in">this</span>.elementData = <span class="keyword">new</span> <span class="title class_">Object</span>[initialCapacity];</span><br><span class="line"> <span class="built_in">this</span>.capacityIncrement = capacityIncrement;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="ArrayList"><a href="#ArrayList" class="headerlink" title="ArrayList"></a>ArrayList</h3><p> ArrayList 是应用最多的动态数组,由于它没有了同步开销,因此性能更加良好。相应的,它不是线程安全的。 ArrayList 也支持动态扩容,但是与 Vector 默认扩容一倍不同, ArrayList 扩容时是增加当前容量的 50% ,其默认容量是 10 。</p><figure class="highlight java"><table><tr><td class="code"><pre><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="type">int</span> <span class="variable">DEFAULT_CAPACITY</span> <span class="operator">=</span> <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">grow</span><span class="params">(<span class="type">int</span> minCapacity)</span> {</span><br><span class="line"> <span class="comment">// overflow-conscious code</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">oldCapacity</span> <span class="operator">=</span> elementData.length;</span><br><span class="line"> <span class="type">int</span> <span class="variable">newCapacity</span> <span class="operator">=</span> oldCapacity + (oldCapacity >> <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - minCapacity < <span class="number">0</span>)</span><br><span class="line"> newCapacity = minCapacity;</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - MAX_ARRAY_SIZE > <span class="number">0</span>)</span><br><span class="line"> newCapacity = hugeCapacity(minCapacity);</span><br><span class="line"> <span class="comment">// minCapacity is usually close to size, so this is a win:</span></span><br><span class="line"> elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> ArrayList 在执行插入操作时,若元素个数超过当前数组预定义容量的最大值,数组需要扩容,扩容过程需要调用底层 System.arraycopy() 方法进行大量的数组复制操作。它在删除元素时并不会减少数组的容量,但是如果需要缩小数组容量,可以调用 trimToSize() 方法。在查找元素时要遍历数组,对于非 null 的元素采取 equals 的方式寻找。</p><h3 id="LinkedList"><a href="#LinkedList" class="headerlink" title="LinkedList"></a>LinkedList</h3><p> LinkedList 是双向链表,它不需要进行调整容量,它也不是线程安全的。 LinkedList 在插入元素时,须创建一个新的 Entry 对象,并更新相应元素的前后元素的引用;在查找元素时,需遍历链表;在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除即可。</p><h3 id="排序操作"><a href="#排序操作" class="headerlink" title="排序操作"></a>排序操作</h3><p> Vector 、 ArrayList 、 LinkedList 内部都实现了排序操作,允许进行自定义排序。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> LinkedList<String> linkedList = <span class="keyword">new</span> <span class="title class_">LinkedList</span><>();</span><br><span class="line"></span><br><span class="line"> linkedList.add(<span class="string">"c"</span>);</span><br><span class="line"> linkedList.add(<span class="string">"b"</span>);</span><br><span class="line"> linkedList.add(<span class="string">"a"</span>);</span><br><span class="line"></span><br><span class="line"> linkedList.sort(<span class="keyword">new</span> <span class="title class_">Comparator</span><String>() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(String o1, String o2)</span> {</span><br><span class="line"> <span class="keyword">return</span> o1.compareTo(o2);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> linkedList.forEach((s) -> {</span><br><span class="line"> System.out.print(s + <span class="string">" "</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><br><span class="line">输出 a b c </span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p> Vector 、 ArrayList 、 LinkedList 是 List 的实现,都是有序集合。 Vector 、 ArrayList 使用数组实现,有需要时可以进行动态扩容, LinkedList 使用双向链表实现,不需要动态扩容。 Vector 是线程安全的,而 ArrayList 、 LinkedList 是线程不安全的。在分析以上三类集合的读写效率时,还应注意的一点是是否需要考尾部的情况。</p><p>以上内容都基于 jdk1.8.0_161 。</p><p><del>JDK源码是四个空格缩进,而我用的是Google Style两个空格缩进,有点不协调orz。</del></p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651485602&idx=2&sn=569035c3b6bd1a1028df03517418e84a&chksm=bd2519dd8a5290cb32f88a88fc8f57799b5d25e79452bc66749f83c40f593509931506603623&mpshare=1&scene=1&srcid=&sharer_sharetime=1575123269344&sharer_shareid=3c5653a301d37ee49e0cb689e723404f#rd">Java问答:用ArrayList还是LinkedList</a></p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="Java的集合框架"><a href="#Java的集合框架" class="headerlink" title="Java的集合框架"></a>Java的集合框架</h3><p> Java 提供的主要容器类型分别</summary>
<category term="Java" scheme="https://wqdchn.github.io/categories/Java/"/>
<category term="Java" scheme="https://wqdchn.github.io/tags/Java/"/>
<category term="容器" scheme="https://wqdchn.github.io/tags/%E5%AE%B9%E5%99%A8/"/>
<category term="集合" scheme="https://wqdchn.github.io/tags/%E9%9B%86%E5%90%88/"/>
<category term="数组" scheme="https://wqdchn.github.io/tags/%E6%95%B0%E7%BB%84/"/>
<category term="链表" scheme="https://wqdchn.github.io/tags/%E9%93%BE%E8%A1%A8/"/>
</entry>
<entry>
<title>R语言新手教程:我在哪,我的数据在哪</title>
<link href="https://wqdchn.github.io/beginner-guide-to-r-demo1.html"/>
<id>https://wqdchn.github.io/beginner-guide-to-r-demo1.html</id>
<published>2020-03-07T10:17:55.000Z</published>
<updated>2024-02-17T01:39:54.995Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="R语言与RStudio"><a href="#R语言与RStudio" class="headerlink" title="R语言与RStudio"></a>R语言与RStudio</h4><p>我知道新手那种对未知的知识,陌生的工具的恐惧和焦虑,一些对于老手来说就是几条命令行,几条代码的事,对于新手来说可能要摸索好几天才能找到头绪。虽说都有这么一个过程,但是能够尽快走过这个阶段总是好的。</p><p>今天我在一个<code>R</code>语言的群里看到一个新手同学为一个很简单的问题而困恼,不禁想起了我刚接触<code>R</code>语言的时候。不过我本身是计算机专业的学生,可能比较容易学习新的工具。但是对很多非计算机专业的学生来说,学习<code>R</code>语言可能是一件不那么容易的事。</p><p><code>R</code>语言自带了一个<code>GUI</code>,也就是编程时的用户界面了,不过它的风格非常朴素,功能也很朴素,不太适合作为新手上手的工具。因此,我强烈建议使用<code>RStudio</code>,这里并不介绍<code>RStudio</code>的安装、启动,以及<code>RStudio</code>面板上各个窗口表示的内容。相信知乎、简书等网站上有很多详细的中文教程。</p><p>那么这篇文章要介绍什么东西呢?</p><p>很简单,就是如何在<code>RStudio</code>命令窗口中使用<code>R</code>语言,命令它告诉我,我在哪。</p><h4 id="我在哪,我的数据在哪"><a href="#我在哪,我的数据在哪" class="headerlink" title="我在哪,我的数据在哪"></a>我在哪,我的数据在哪</h4><p>我执行了读取文件的命令,但是却显示错误,请问是怎么回事啊???</p><p>这是我在群里最容易看到的一个问题。一看新手同学贴出来的<code>R</code>代码可能类似这样:</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> read_csv<span class="punctuation">(</span><span class="string">"data.csv"</span><span class="punctuation">)</span></span><br><span class="line">Error<span class="operator">:</span> <span class="string">'data.csv'</span> does not exist <span class="keyword">in</span> current working directory <span class="punctuation">(</span><span class="string">'F:/Documents'</span><span class="punctuation">)</span>.</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>报错信息提示我们,文件<code>data.csv</code>不在工作路径<code>F:/Documents</code>下。也就是说,我现在在的这个地方没有这个东西。那么,首先要知道的就是,我现在在哪里。在<code>R</code>中,可以通过<code>getwd()</code>命令来获取当前所在的工作路径。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> getwd<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">[</span><span class="number">1</span><span class="punctuation">]</span> <span class="string">"F:/Documents"</span></span><br></pre></td></tr></table></figure><p>输出的信息提示我们,我现在处于文件夹<code>F:/Documents</code>目录下。然后我又发现,我的<code>data.csv</code>文件其实是在文件夹<code>F:/Documents/test</code>目录下的。那么我该怎么让<code>R</code>读取到它呢?一种方法是改变工作路径,我的数据在哪里,我就要把哪里里当做工作路径。这可以通过<code>setwd()</code>命令来实现。注意,我们需要为该命令指定相应的路径参数,否则该命令将报错,因为你没有告诉<code>R</code>到底去哪里。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> getwd<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">[</span><span class="number">1</span><span class="punctuation">]</span> <span class="string">"F:/Documents"</span></span><br><span class="line"><span class="operator">></span> setwd<span class="punctuation">(</span><span class="string">"F:/Documents/test"</span><span class="punctuation">)</span></span><br><span class="line"><span class="operator">></span> getwd<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">[</span><span class="number">1</span><span class="punctuation">]</span> <span class="string">"F:/Documents/test"</span></span><br></pre></td></tr></table></figure><p>现在我们来到了文件夹<code>F:/Documents/test</code>目录下,这时,最初那条执行错误的命令可以顺利执行了。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> read_csv<span class="punctuation">(</span><span class="string">"data.csv"</span><span class="punctuation">)</span></span><br><span class="line">Parsed with column specification<span class="operator">:</span></span><br><span class="line">cols<span class="punctuation">(</span></span><br><span class="line"> .default <span class="operator">=</span> col_double<span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span></span><br><span class="line"> diagnosis <span class="operator">=</span> col_character<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">)</span></span><br><span class="line">See spec<span class="punctuation">(</span>...<span class="punctuation">)</span> <span class="keyword">for</span> full column specifications.</span><br><span class="line"><span class="comment"># A tibble: 569 x 32</span></span><br></pre></td></tr></table></figure><p>你看,我们读取到了一个<code>569 x 32</code>的数据框,数据成功地进入了<code>R</code>环境中。这是为什么呢?首先通过如下命令来查看<code>read_csv()</code>的参数。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> args<span class="punctuation">(</span>read.csv<span class="punctuation">)</span></span><br><span class="line"><span class="keyword">function</span> <span class="punctuation">(</span>file<span class="punctuation">,</span> header <span class="operator">=</span> <span class="literal">TRUE</span><span class="punctuation">,</span> sep <span class="operator">=</span> <span class="string">","</span><span class="punctuation">,</span> <span class="built_in">quote</span> <span class="operator">=</span> <span class="string">"\""</span><span class="punctuation">,</span> dec <span class="operator">=</span> <span class="string">"."</span><span class="punctuation">,</span> </span><br><span class="line"> fill <span class="operator">=</span> <span class="literal">TRUE</span><span class="punctuation">,</span> comment.char <span class="operator">=</span> <span class="string">""</span><span class="punctuation">,</span> ...<span class="punctuation">)</span> </span><br><span class="line"><span class="literal">NULL</span></span><br></pre></td></tr></table></figure><p>可以看到,<code>read_csv()</code>命令中第一个参数是文件。最初的时候,我们位于<code>F:/Documents</code>工作路径,我们指定的<code>data.csv</code>只告诉了文件名,那么<code>read_csv()</code>就会到<strong>相对路径</strong>中寻找。因为<code>read_csv()</code>并不清楚这个东西到底在哪里,那没办法了,就在工作路径里找找看,有就有,没有拉倒吧,别的地方我是不会去找的。此时,这个相对路径就是工作路径。而我的<code>data.csv</code>文件其实是在文件夹<code>F:/Documents/test</code>目录下的,那结果当然是找不到了。</p><p>这时候我们灵机一动,如果我在<code>read_csv()</code>命令中第一个参数中指定<code>data.csv</code>的真实位置和文件名呢?我们依然回到最初的地点,将<code>F:/Documents</code>设置为工作路径,再告诉<code>read_csv()</code>命令<code>data.csv</code>的真实位置和文件名。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="operator">></span> setwd<span class="punctuation">(</span><span class="string">"F:/Documents"</span><span class="punctuation">)</span></span><br><span class="line"><span class="operator">></span> getwd<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">[</span><span class="number">1</span><span class="punctuation">]</span> <span class="string">"F:/Documents"</span></span><br><span class="line"><span class="operator">></span> read_csv<span class="punctuation">(</span><span class="string">"F:/Documents/test/data.csv"</span><span class="punctuation">)</span></span><br><span class="line">Parsed with column specification<span class="operator">:</span></span><br><span class="line">cols<span class="punctuation">(</span></span><br><span class="line"> .default <span class="operator">=</span> col_double<span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span></span><br><span class="line"> diagnosis <span class="operator">=</span> col_character<span class="punctuation">(</span><span class="punctuation">)</span></span><br><span class="line"><span class="punctuation">)</span></span><br><span class="line">See spec<span class="punctuation">(</span>...<span class="punctuation">)</span> <span class="keyword">for</span> full column specifications.</span><br><span class="line"><span class="comment"># A tibble: 569 x 32</span></span><br></pre></td></tr></table></figure><p>结果顺利地读取到了这个文件。这又是为什么呢???这是因为,我们这次告诉<code>read_csv()</code>命令的是<strong>绝对路径</strong>:你必须到这个地方找到这个东西,于是<code>read_csv()</code>就乖乖去找了。</p><p>对于老手来说,可能会觉得这种问题很可笑。但是偏偏就是这些不起眼的问题,常常给新手同学造成很大的烦恼。</p><p>我在哪,我的数据在哪,一切的一切都从这里出发,绽放出耀眼的光彩。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="R语言与RStudio"><a href="#R语言与RStudio" class="headerlink" title="R语言与RStudio"></a>R语言与RStudio</h4><p>我知道新手那种对未</summary>
<category term="R" scheme="https://wqdchn.github.io/categories/R/"/>
<category term="R" scheme="https://wqdchn.github.io/tags/R/"/>
<category term="RStudio" scheme="https://wqdchn.github.io/tags/RStudio/"/>
</entry>
<entry>
<title>LeetCode股票买卖系列</title>
<link href="https://wqdchn.github.io/leetcode-best-time-to-by-and-sell-stock.html"/>
<id>https://wqdchn.github.io/leetcode-best-time-to-by-and-sell-stock.html</id>
<published>2020-03-06T01:01:48.000Z</published>
<updated>2024-02-17T01:39:55.104Z</updated>
<content type="html"><![CDATA[<h4 id="Best-Time-to-Buy-and-Sell-Stock"><a href="#Best-Time-to-Buy-and-Sell-Stock" class="headerlink" title="Best Time to Buy and Sell Stock"></a>Best Time to Buy and Sell Stock</h4><p>来看<code>LeetCode</code>的股票买卖系列问题的第一题<a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">Best Time to Buy and Sell Stock</a>。这一题要求在一系列股票价格中,通过一次买卖交易获得最大的收益。假设有这么一组股票价格<code>[7,1,5,3,6,4]</code>,我们只能在买进之后再卖出来赚取收益。很显然,我们需要在第二天的时候以<code>1</code>元的价格买进,然后在第五天的时候以<code>6</code>元的价格卖出,这样得到最大的收益<code>5</code>元。这可以用暴力法通过两层<code>for</code>循环遍历实现,但是还有一个比较好的办法,更加贴近人的思维。</p><p>首先,我们知道,买进时的股价是代价,卖出时的股价和代价之间的差价是收益。我们的目的是希望代价最低,收益最高。以上面的股价序列为例,如果我们在第一天以<code>7</code>元的价格买入股票,这时代价是<code>7</code>,收益是<code>0</code>。到了第二天,现在的股价是<code>1</code>,意味着此时代价可以是<code>1</code>,而收益是<code>1-7</code>等于<code>-6</code>。所以我们更新一下代价,但是不更新收益,此时代价是<code>1</code>,收益是<code>0</code>。从人类的思维来说,这是选择在第二天买进,然后等等看。到了第三天,现在的股价是<code>5</code>,此时的代价可以是<code>5</code>,而收益是此时的股价减去之前的代价<code>5-1</code>等于<code>4</code>。所以我们选择更新收益,但是不更新代价,此时代价是<code>1</code>,收益是<code>4</code>。以此类推,有更小的代价就更新代价,有更高的收益就更新收益。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">maxProfit</span><span class="params">(<span class="type">int</span>[] prices)</span> {</span><br><span class="line"> <span class="keyword">if</span> (prices.length < <span class="number">2</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 class="type">int</span> <span class="variable">cost</span> <span class="operator">=</span> Integer.MAX_VALUE;</span><br><span class="line"> <span class="type">int</span> <span class="variable">profit</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> price : prices) {</span><br><span class="line"> cost = Math.min(cost, price);</span><br><span class="line"> profit = Math.max(profit, price - cost);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> profit;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Best-Time-to-Buy-and-Sell-Stock-III"><a href="#Best-Time-to-Buy-and-Sell-Stock-III" class="headerlink" title="Best Time to Buy and Sell Stock III"></a>Best Time to Buy and Sell Stock III</h4><p>来看<code>LeetCode</code>的股票买卖系列问题的第三题<a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/">Best Time to Buy and Sell Stock III</a>。这一题要求在一系列股票价格中获得最大的收益,最多可以通过两次买卖交易,但是需要第一次买卖交易完成之后才能进行第二次买卖交易。</p><p>与第一题类似,只是可以多一次交易。进行第二次交易时,我们可以把第一次交易的收益当做代价。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">maxProfit</span><span class="params">(<span class="type">int</span>[] prices)</span> {</span><br><span class="line"> <span class="keyword">if</span> (prices.length < <span class="number">2</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 class="type">int</span> <span class="variable">cost1</span> <span class="operator">=</span> Integer.MAX_VALUE;</span><br><span class="line"> <span class="type">int</span> <span class="variable">profit1</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">cost2</span> <span class="operator">=</span> Integer.MAX_VALUE;</span><br><span class="line"> <span class="type">int</span> <span class="variable">profit2</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> price : prices) {</span><br><span class="line"></span><br><span class="line"> cost1 = Math.min(cost1, price);</span><br><span class="line"> profit1 = Math.max(profit1, price - cost1);</span><br><span class="line"></span><br><span class="line"> cost2 = Math.min(cost2, price - profit1);</span><br><span class="line"> profit2 = Math.max(profit2, price - cost2);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> profit2;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>股市有风险,入行需谨慎。股民如何在最好的时机买进股票,并在最好的时机卖出股票,这是一个玄学问题。</p>]]></content>
<summary type="html"><h4 id="Best-Time-to-Buy-and-Sell-Stock"><a href="#Best-Time-to-Buy-and-Sell-Stock" class="headerlink" title="Best Time to Buy and Sell Stoc</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="动态规划" scheme="https://wqdchn.github.io/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
</entry>
<entry>
<title>R语言获取标准中国地图</title>
<link href="https://wqdchn.github.io/get-china-map-with-R.html"/>
<id>https://wqdchn.github.io/get-china-map-with-R.html</id>
<published>2020-03-04T02:49:48.000Z</published>
<updated>2024-02-17T01:39:55.032Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="地图在哪里"><a href="#地图在哪里" class="headerlink" title="地图在哪里"></a>地图在哪里</h3><p>空间数据分析离不开基础地理数据的支持,比如省市县乡等各级行政区划的数据。然而我国的基础地理数据处于一种薛定谔的状态,往往找不到一个能给出基础地理数据的政府部门的官网。有些网站会共享一部分基础地理数据,但是申请数据的手续有时非常复杂, 即要注册提交个人信息,又要手持身份证拍照,还要写下申请书。于是在大部分情况下只能转向万能的某宝,说多了都是泪。</p><p>最近突然发现,民政部的官网悄咪咪的提供了一个接口可以获取到一些基础地理数据。既然是民政部门提供的数据,那当然是最权威的,再也不用担心有些数据中存在的南海九段线缺失,台湾岛没有等问题啦。</p><h3 id="获取全国县级地图"><a href="#获取全国县级地图" class="headerlink" title="获取全国县级地图"></a>获取全国县级地图</h3><p>民政部提供了省级与县级的 json 格式地图数据,我们可以使用 R 语言的 sf 包读取需要的数据,然后使用 tmap 包来绘制地图。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line">library<span class="punctuation">(</span>sf<span class="punctuation">)</span></span><br><span class="line">library<span class="punctuation">(</span>tmap<span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 民政部官网</span></span><br><span class="line">url <span class="operator"><-</span> <span class="string">"http://xzqh.mca.gov.cn/data/"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取全国县级地图</span></span><br><span class="line">xian_quanguo <span class="operator"><-</span> sf<span class="operator">::</span>st_read<span class="punctuation">(</span></span><br><span class="line"> dsn <span class="operator">=</span> paste0<span class="punctuation">(</span>url<span class="punctuation">,</span> <span class="string">"xian_quanguo.json"</span><span class="punctuation">)</span><span class="punctuation">,</span></span><br><span class="line"> stringsAsFactors <span class="operator">=</span> <span class="literal">FALSE</span></span><br><span class="line"><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 简单检查一下数据</span></span><br><span class="line">head<span class="punctuation">(</span>xian_quanguo<span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line">st_crs<span class="punctuation">(</span>xian_quanguo<span class="punctuation">)</span> <span class="operator"><-</span> st_crs<span class="punctuation">(</span><span class="string">"+proj=longlat +datum=WGS84"</span><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># tmap绘制地图</span></span><br><span class="line">tm_shape<span class="punctuation">(</span>xian_quanguo<span class="punctuation">)</span> <span class="operator">+</span> </span><br><span class="line"> tm_polygons<span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">+</span> </span><br><span class="line"> tm_compass<span class="punctuation">(</span>position <span class="operator">=</span> <span class="built_in">c</span><span class="punctuation">(</span><span class="string">"left"</span><span class="punctuation">,</span> <span class="string">"bottom"</span><span class="punctuation">)</span><span class="punctuation">)</span> <span class="operator">+</span> <span class="comment"># 指北针</span></span><br><span class="line"> tm_scale_bar<span class="punctuation">(</span>position <span class="operator">=</span> <span class="built_in">c</span><span class="punctuation">(</span><span class="string">"left"</span><span class="punctuation">,</span> <span class="string">"bottom"</span><span class="punctuation">)</span><span class="punctuation">)</span> <span class="comment"># 比例尺</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>sf 包的计算效率非常高,是当前 R 语言空间数据分析过程中不可缺少的重要工具,强烈 push。 tmap 包是我接触的比较友好的一种地图可视化包,使用也很简洁,更新也比较及时。</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://github.com/r-spatial/sf">sf: A package that provides simple features access for R</a></p><p><a href="https://github.com/mtennekes/tmap">tmap: R package for thematic maps</a></p>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="地图在哪里"><a href="#地图在哪里" class="headerlink" title="地图在哪里"></a>地图在哪里</h3><p>空间数据分析离不开基础地理数据的支持,比如省市县乡等各级行政区划的数</summary>
<category term="R" scheme="https://wqdchn.github.io/categories/R/"/>
<category term="R" scheme="https://wqdchn.github.io/tags/R/"/>
<category term="tmap" scheme="https://wqdchn.github.io/tags/tmap/"/>
<category term="sf" scheme="https://wqdchn.github.io/tags/sf/"/>
<category term="地理数据" scheme="https://wqdchn.github.io/tags/%E5%9C%B0%E7%90%86%E6%95%B0%E6%8D%AE/"/>
</entry>
<entry>
<title>说一说二分查找</title>
<link href="https://wqdchn.github.io/bin-search.html"/>
<id>https://wqdchn.github.io/bin-search.html</id>
<published>2020-02-20T13:08:46.000Z</published>
<updated>2024-02-17T01:39:55.030Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h3 id="二分查找"><a href="#二分查找" class="headerlink" title="二分查找"></a>二分查找</h3><p>二分查找也称折半查找,思想很简单,对于一个有序数组,查找数组中是否存在指定元素,只需比较指定元素与数组中间元素的大小关系,通过这种比较来判断下一次查找的范围,直到完成整个查找。尽管二分查找的基本思想相对简单,但有时它的细节可以令人难以招架。</p><h3 id="一个简单的二分查找实现"><a href="#一个简单的二分查找实现" class="headerlink" title="一个简单的二分查找实现"></a>一个简单的二分查找实现</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">binSearch</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> key)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">left</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">right</span> <span class="operator">=</span> nums.length - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (left <= right) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">mid</span> <span class="operator">=</span> left + ((right - left) >>> <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (nums[mid] > key) {</span><br><span class="line"> right = mid - <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (nums[mid] < key) {</span><br><span class="line"> left = 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><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><span id="more"></span>
<h3 id="二分查找"><a href="#二分查找" class="headerlink" title="二分查找"></a>二分查找</h3><p>二分查找也称折半查找,思想很简单,对于一个有序数组,查找数组中是否存在指定元</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="位运算" scheme="https://wqdchn.github.io/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/"/>
<category term="二分查找" scheme="https://wqdchn.github.io/tags/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/"/>
</entry>
<entry>
<title>LeetCode第204题Count Primes</title>
<link href="https://wqdchn.github.io/leetcode-count-primes.html"/>
<id>https://wqdchn.github.io/leetcode-count-primes.html</id>
<published>2020-02-08T01:33:25.000Z</published>
<updated>2024-02-17T01:39:55.105Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="Count-Primes"><a href="#Count-Primes" class="headerlink" title="Count Primes"></a>Count Primes</h4><p><a href="https://leetcode.com/problems/count-primes/">Count Primes</a>给出一个数,计算小于这个数的所有的素数个数。例如,输入<code>10</code>,则<code>10</code>以内的素数有四个,分别为<code>2</code>,<code>3</code>,<code>5</code>,<code>7</code>,故返回<code>4</code>。</p><p>求素数的问题相信很多计算机专业的同学在大一刚接触编程的时候一定会碰上,求素数也不难。但是在这里是求素数的个数,一个很简单的思路是调用素数判断的函数,如果是素数则计数加一,最后返回结果。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//Runtime: 548 ms, faster than 13.15% of Java online submissions for Count Primes.</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">countPrimes</span><span class="params">(<span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">if</span> (isPrime(i)) {</span><br><span class="line"> count++;</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="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">isPrime</span><span class="params">(<span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">2</span>; i * i <= n; i++) {</span><br><span class="line"> <span class="keyword">if</span> (n % i == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>但是你也看到了,这样的效率并不高,有没有办法让它更高更快更强呢,答案是有的。</p><p>首先我们知道,所有的偶数都不是素数,也就是说,我们的<code>n</code>中有一半都不是素数,即我们的<code>count</code>最多也就是<code>n/2</code>。</p><p>其次,我们只需要在剩下的一半中寻找素数,或者反向操作寻找不是素数的,然后令<code>count</code>不断地减减。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// Runtime: 6 ms, faster than 99.32% of Java online submissions for Count Primes.</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">countPrimes2</span><span class="params">(<span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="keyword">if</span> (n < <span class="number">3</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 class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> n / <span class="number">2</span>;</span><br><span class="line"> <span class="type">boolean</span> not_prime[] = <span class="keyword">new</span> <span class="title class_">boolean</span>[n];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// i从奇数开始,从奇数中取</span></span><br><span class="line"> <span class="comment">// i会取3,5,7,9...</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">3</span>; i * i < n; i += <span class="number">2</span>) {</span><br><span class="line"> <span class="keyword">if</span> (not_prime[i] == <span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// j从奇数开始,从奇数中取,我们要剔除的是i的奇数倍</span></span><br><span class="line"> <span class="comment">// j会取 3*3, 3*(3+2),3*(3+4),3*(3+6)...</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> i * i; j < n; j += i * <span class="number">2</span>) {</span><br><span class="line"> <span class="comment">// 找到count个奇数中的合数,count--,并标记为非素数</span></span><br><span class="line"> <span class="keyword">if</span> (not_prime[j] == <span class="literal">false</span>) {</span><br><span class="line"> not_prime[j] = <span class="literal">true</span>;</span><br><span class="line"> count--;</span><br><span class="line"> }</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></pre></td></tr></table></figure><p>是不是更高更快更强了呢。</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>素数真好玩。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="Count-Primes"><a href="#Count-Primes" class="headerlink" title="Count Primes"></a>Count Primes</h4><p><a hre</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="素数" scheme="https://wqdchn.github.io/tags/%E7%B4%A0%E6%95%B0/"/>
</entry>
<entry>
<title>再见二零一九</title>
<link href="https://wqdchn.github.io/goodbye-2019.html"/>
<id>https://wqdchn.github.io/goodbye-2019.html</id>
<published>2020-01-24T11:10:09.000Z</published>
<updated>2024-02-17T01:39:55.033Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="久违的更新"><a href="#久违的更新" class="headerlink" title="久违的更新"></a>久违的更新</h4><p>好久不见,有好多话想说,但是还是决定留在心里,且做后来故事。</p><p>今天是除夕,祝愿大家春节愉快,平安健康。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="久违的更新"><a href="#久违的更新" class="headerlink" title="久违的更新"></a>久违的更新</h4><p>好久不见,有好多话想说,但是还是决定留在心里,且做后来故事。</p></summary>
<category term="杂的文" scheme="https://wqdchn.github.io/categories/%E6%9D%82%E7%9A%84%E6%96%87/"/>
<category term="新年" scheme="https://wqdchn.github.io/tags/%E6%96%B0%E5%B9%B4/"/>
<category term="春节" scheme="https://wqdchn.github.io/tags/%E6%98%A5%E8%8A%82/"/>
</entry>
<entry>
<title>LeetCode第322题Coin Change</title>
<link href="https://wqdchn.github.io/leetcode-coin-change.html"/>
<id>https://wqdchn.github.io/leetcode-coin-change.html</id>
<published>2019-11-29T09:36:35.000Z</published>
<updated>2024-02-17T01:39:55.104Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="Coin-Change"><a href="#Coin-Change" class="headerlink" title="Coin Change"></a>Coin Change</h4><p><a href="https://leetcode.com/problems/coin-change/">Coin Change</a>给出不同币值的硬币和一个目标金额,求组成目标金额所需最少的硬币数量,注意,这里可供取用的硬币数据量是不限制的,如果没有可用的硬币,则返回-1即可。</p><h5 id="Example-1"><a href="#Example-1" class="headerlink" title="Example 1:"></a>Example 1:</h5><blockquote><p>Input: coins = [1, 2, 5], amount = 11<br>Output: 3<br>Explanation: 11 = 5 + 5 + 1</p></blockquote><h5 id="Example-2"><a href="#Example-2" class="headerlink" title="Example 2:"></a>Example 2:</h5><blockquote><p>Input: coins = [2], amount = 3<br>Output: -1</p></blockquote><p>这一题使用暴力法会超时,因此需要改换策略,实际上就是要求使用动态规划来完成。动态规划最头痛的就是递推方程,要了解每一次方程的状态是如何转移的,简直让我选择放弃,好在这一题是找零钱,仿佛小学生奥数似的,稍有些趣味性,不妨挑战一下。</p><p>以示例一为例,我们现在有1,2,5三种币值的硬币,且任意取用。当我们需要11块钱的时候,我们可以选择摸11个一块钱,也可以选择摸5个两块钱和1个一块钱,当然,最少的是摸2个五块钱和1个一块钱。那么这里就存在一种规律了,比如说我们恰好摸了2个五块钱和1个一块钱,完成了任务,可是这个过程中,我们是摸了2个五块钱和1个一块钱的<del>这不是废话嘛!!!</del>注意了,这个2个五块钱和1个一块钱可不简单,它们分别是十块钱和一块钱<del>这又是什么废话啊!!!</del><br>嗯,到这里暗示已经结束,该明示了。就是说,组合11块钱的任务是由组合10块钱和组合1块钱来完成的,而两个组合也恰好是最少的,不仅是组合成11块钱是最少的,他们本身组合成10块钱和组合成1块钱也是最少的。因此,我们的动态规划递推方程中,当前的组合金额<code>(11)</code>还有币值<code>(1,2,5)</code>与之前的组合金额<code>(10,1)</code>是有关联的,我们最终会推到<code>0</code>,也就是什么都不做。</p><p>简单的数学公式是这样的:<br><code>F(11) = min(F(11-1),F(11-2),F(11-5)) + 1</code><br><code>F(11) = min(F(10),F(9),F(6)) + 1</code><br>然后呢我们分别再求<code>F(10)</code>、<code>F(9)</code>、<code>F(6)</code>….</p><p>这个<code>F</code>函数就是我们要实现的摸硬币操作。</p><h4 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h4><p>下面是<code>Java</code>的代码:</p><p>注意:外层循环表示可用的硬币组合,内层循环则表示在当前可用的硬币组合下,完成目标金额数所需要的硬币数量。</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">coinChange</span><span class="params">(<span class="type">int</span>[] coins, <span class="type">int</span> amount)</span> {</span><br><span class="line"> <span class="keyword">if</span> (amount == <span class="number">0</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 class="type">int</span>[] dp = <span class="keyword">new</span> <span class="title class_">int</span>[amount + <span class="number">1</span>];</span><br><span class="line"> Arrays.fill(dp, amount + <span class="number">1</span>);</span><br><span class="line"> dp[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> coin : coins) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> coin; i < amount + <span class="number">1</span>; i++) {</span><br><span class="line"> dp[i] = Math.min(dp[i], dp[i - coin] + <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> dp[amount] != amount + <span class="number">1</span> ? dp[amount] : -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面是<code>Python</code>的代码:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">coinChange</span>(<span class="params">self, coins, amount</span>):</span><br><span class="line"> dp = [<span class="number">0</span>] + [<span class="built_in">float</span>(<span class="string">'inf'</span>)] * amount</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> coin <span class="keyword">in</span> coins:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(coin, amount + <span class="number">1</span>):</span><br><span class="line"> dp[i] = <span class="built_in">min</span>(dp[i], dp[i - coin] + <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> dp[-<span class="number">1</span>] <span class="keyword">if</span> dp[-<span class="number">1</span>] != <span class="built_in">float</span>(<span class="string">'inf'</span>) <span class="keyword">else</span> -<span class="number">1</span> </span><br></pre></td></tr></table></figure><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>第322题是中等题,除了找零钱有些趣味,动态规划实在打扰了。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="Coin-Change"><a href="#Coin-Change" class="headerlink" title="Coin Change"></a>Coin Change</h4><p><a href="h</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="动态规划" scheme="https://wqdchn.github.io/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
</entry>
<entry>
<title>R语言ggplot2绘图转PDF中文乱码问题</title>
<link href="https://wqdchn.github.io/r-ggplot2-to-pdf-with-chinese.html"/>
<id>https://wqdchn.github.io/r-ggplot2-to-pdf-with-chinese.html</id>
<published>2019-10-20T12:53:49.000Z</published>
<updated>2024-02-17T01:39:55.114Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="ggplot2与中文乱码的Solution"><a href="#ggplot2与中文乱码的Solution" class="headerlink" title="ggplot2与中文乱码的Solution"></a>ggplot2与中文乱码的Solution</h4><h5 id="字体文件"><a href="#字体文件" class="headerlink" title="字体文件"></a>字体文件</h5><p>首先假设你有一个<code>Windows</code>系统,其次进行R语言编程所使用的<code>IDE</code>是<code>RStudio</code><del>非常好用的集成开发环境</del>。</p><p>然后在<code>Windows</code>系统中找到中文字体,比如宋体或黑体,再找到一个英文字体,比如<code>Times New Roman</code>。它们大概在<code>C盘</code>的<code>Windows/Fonts</code>路径下。</p><p>找出所需的字体文件,比如宋体的字体文件是<code>simsun.ttc</code>,黑体的字体文件是<code>simhei.ttf</code>,<code>Times New Roman</code>的字体文件是<code>times.ttf</code>。</p><p>找到字体文件就是成功的一半了,然后我把它们随便放到一个地方准备加载。</p><h5 id="showtext包"><a href="#showtext包" class="headerlink" title="showtext包"></a>showtext包</h5><p>然后需要在<code>R</code>中调用<code>showtext</code>包,如果没有这个包,请安装它。</p><figure class="highlight r"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 调用showtext包</span></span><br><span class="line">library<span class="punctuation">(</span>showtext<span class="punctuation">)</span></span><br><span class="line">showtext_auto<span class="punctuation">(</span>enable <span class="operator">=</span> <span class="literal">TRUE</span><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 载入黑体</span></span><br><span class="line">font_add<span class="punctuation">(</span><span class="string">"heiti"</span><span class="punctuation">,</span> regular <span class="operator">=</span> <span class="string">"F:\\font\\simhei.ttf"</span><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 载入宋体</span></span><br><span class="line">font_add<span class="punctuation">(</span><span class="string">"songti"</span><span class="punctuation">,</span> regular <span class="operator">=</span> <span class="string">"F:\\font\\simsun.ttc"</span><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 载入Times New Roman字体</span></span><br><span class="line">font_add<span class="punctuation">(</span><span class="string">"newrom"</span><span class="punctuation">,</span> regular <span class="operator">=</span> <span class="string">"F:\\font\\times.ttf"</span><span class="punctuation">)</span></span><br></pre></td></tr></table></figure><p>在上面,我们载入了三种字体,并重命名<del>请随意命名</del>后供<code>ggplot2</code>调用。</p><p>注意载入的路径,在<code>Windows</code>下好像要使用反斜杠。</p><p>注意,使用字体的过程中,可能会出现提示没有这种字体!!!!!!无妨,重新执行一下上面的命令可以解决。</p><h5 id="ggplot2绘图带中文"><a href="#ggplot2绘图带中文" class="headerlink" title="ggplot2绘图带中文"></a>ggplot2绘图带中文</h5><figure class="highlight r"><table><tr><td class="code"><pre><span class="line">p <span class="operator"><-</span> ggplot<span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">+</span> geom_point<span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">+</span> ... <span class="operator">+</span></span><br><span class="line"> theme<span class="punctuation">(</span>axis.title.x <span class="operator">=</span> element_text<span class="punctuation">(</span>family<span class="operator">=</span><span class="string">"newrom"</span><span class="punctuation">)</span><span class="punctuation">,</span> axis.title.y <span class="operator">=</span> element_text<span class="punctuation">(</span>family <span class="operator">=</span> <span class="string">"songti"</span><span class="punctuation">)</span><span class="punctuation">)</span> <span class="operator">+</span></span><br><span class="line"> xlab<span class="punctuation">(</span><span class="string">"Hello World"</span><span class="punctuation">)</span> <span class="operator">+</span> </span><br><span class="line"> ylab<span class="punctuation">(</span><span class="string">"你好世界"</span><span class="punctuation">)</span></span><br></pre></td></tr></table></figure><p>在上面的命令中,我们把<code>X</code>轴的字体指定为<code>Times New Roman</code>,<code>Y</code>轴的字体指定为宋体。</p><h5 id="转换为PDF"><a href="#转换为PDF" class="headerlink" title="转换为PDF"></a>转换为PDF</h5><figure class="highlight r"><table><tr><td class="code"><pre><span class="line">p <span class="operator"><-</span> ggplot<span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">+</span> geom_point<span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">+</span> ... <span class="operator">+</span></span><br><span class="line"> theme<span class="punctuation">(</span>axis.title.x <span class="operator">=</span> element_text<span class="punctuation">(</span>family<span class="operator">=</span><span class="string">"newrom"</span><span class="punctuation">)</span><span class="punctuation">,</span> axis.title.y <span class="operator">=</span> element_text<span class="punctuation">(</span>family <span class="operator">=</span> <span class="string">"songti"</span><span class="punctuation">)</span><span class="punctuation">)</span> <span class="operator">+</span></span><br><span class="line"> xlab<span class="punctuation">(</span><span class="string">"Hello World"</span><span class="punctuation">)</span> <span class="operator">+</span> </span><br><span class="line"> ylab<span class="punctuation">(</span><span class="string">"你好世界"</span><span class="punctuation">)</span></span><br><span class="line"></span><br><span class="line">ggsave<span class="punctuation">(</span><span class="string">"Fig_p.pdf"</span><span class="punctuation">,</span> plot <span class="operator">=</span> p<span class="punctuation">)</span></span><br></pre></td></tr></table></figure><p>在上面的命令中,我们把<code>p</code>转换为了<code>PDF</code>。再次提醒,这个过程中,可能会出现提示没有这种字体!!!!!!无妨,重新执行一下上面的字体加载命令即可解决。</p><p>然后我们查看一下生成的<code>PDF</code>,应该会得到一个<code>X</code>轴字体是<code>Times New Roman</code>的英文<code>Hello World</code>,<code>Y</code>轴字体是宋体的中文你好世界。</p><p>如果你使用<code>RStudio</code>的图片预览功能,并且尝试<code>Save as PDF</code>,那么可能依然会出现中文乱码问题。</p><p>去试试看吧!</p><h4 id="提醒"><a href="#提醒" class="headerlink" title="提醒"></a>提醒</h4><p>上面的内容只能解决文字中不包含中英文混合的情况。如果需要中英文混合,那么可能需要把某两种中英文字体文件合并生成新的字体文件,然后加载进来才行。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="ggplot2与中文乱码的Solution"><a href="#ggplot2与中文乱码的Solution" class="headerlink" title="ggplot2与中文乱码的Solution"></a</summary>
<category term="R" scheme="https://wqdchn.github.io/categories/R/"/>
<category term="R" scheme="https://wqdchn.github.io/tags/R/"/>
<category term="RStudio" scheme="https://wqdchn.github.io/tags/RStudio/"/>
<category term="ggplot2" scheme="https://wqdchn.github.io/tags/ggplot2/"/>
</entry>
<entry>
<title>LeetCode第104题Maximum Depth of Binary Tree</title>
<link href="https://wqdchn.github.io/leetcode-maximum-depth-of-binary-tree.html"/>
<id>https://wqdchn.github.io/leetcode-maximum-depth-of-binary-tree.html</id>
<published>2019-10-11T07:12:39.000Z</published>
<updated>2024-02-17T01:39:55.109Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="Maximum-Depth-of-Binary-Tree"><a href="#Maximum-Depth-of-Binary-Tree" class="headerlink" title="Maximum Depth of Binary Tree"></a>Maximum Depth of Binary Tree</h4><p><a href="https://leetcode.com/problems/maximum-depth-of-binary-tree/">Maximum Depth of Binary Tree</a>求二叉树的最大深度。</p><h5 id="Example"><a href="#Example" class="headerlink" title="Example:"></a>Example:</h5><p><img src="https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png" alt="Lowest Common Ancestor of a Binary Search Tree Example1"></p><blockquote><p>Input: root = [6,2,8,0,4,7,9,null,null,3,5]<br>Output: 4</p></blockquote><p>二叉树的深度可以通过深度优先搜索和广度优先搜索两种方式来遍历,并记录树的层次。</p><h4 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h4><p>下面是<code>Java</code>的代码:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * public class TreeNode {</span></span><br><span class="line"><span class="comment"> * int val;</span></span><br><span class="line"><span class="comment"> * TreeNode left;</span></span><br><span class="line"><span class="comment"> * TreeNode right;</span></span><br><span class="line"><span class="comment"> * TreeNode(int x) { val = x; }</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">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="comment">// dfs</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">maxDepth</span><span class="params">(TreeNode root)</span> {</span><br><span class="line"> <span class="keyword">return</span> root == <span class="literal">null</span> ? <span class="number">0</span> : <span class="number">1</span> + Math.max(maxDepth(root.left),maxDepth(root.right));</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// bfs</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">maxDepth</span><span class="params">(TreeNode root)</span> {</span><br><span class="line"> <span class="keyword">if</span> (root == <span class="literal">null</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> Deque<TreeNode> q = <span class="keyword">new</span> <span class="title class_">LinkedList</span><>();</span><br><span class="line"> q.add(root);</span><br><span class="line"> <span class="type">int</span> <span class="variable">depth</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (!q.isEmpty()){</span><br><span class="line"> <span class="type">int</span> <span class="variable">size</span> <span class="operator">=</span> q.size();</span><br><span class="line"> <span class="keyword">while</span> (size-- > <span class="number">0</span>){</span><br><span class="line"> <span class="type">TreeNode</span> <span class="variable">node</span> <span class="operator">=</span> q.poll();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (node.left != <span class="literal">null</span>){</span><br><span class="line"> q.offer(node.left);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (node.right != <span class="literal">null</span>){</span><br><span class="line"> q.offer(node.right);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> depth++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> depth;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面是<code>Python</code>的代码:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"># class TreeNode:</span></span><br><span class="line"><span class="comment"># def __init__(self, x):</span></span><br><span class="line"><span class="comment"># self.val = x</span></span><br><span class="line"><span class="comment"># self.left = None</span></span><br><span class="line"><span class="comment"># self.right = None</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="comment"># dfs</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">maxDepth</span>(<span class="params">self, root: TreeNode</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> root: <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> + <span class="built_in">max</span>(self.maxDepth(root.left), self.maxDepth(root.right))</span><br><span class="line"> <span class="comment"># bfs</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">maxDepth</span>(<span class="params">self, root</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> root: <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> q = collections.deque([(root, <span class="number">1</span>)])</span><br><span class="line"> <span class="keyword">while</span> q:</span><br><span class="line"> curr, depth = q.popleft()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> curr.left <span class="keyword">and</span> <span class="keyword">not</span> curr.right <span class="keyword">and</span> <span class="keyword">not</span> q:</span><br><span class="line"> <span class="keyword">return</span> depth</span><br><span class="line"> <span class="keyword">if</span> curr.left:</span><br><span class="line"> q.append((curr.left, depth + <span class="number">1</span>))</span><br><span class="line"> <span class="keyword">if</span> curr.right:</span><br><span class="line"> q.append((curr.right, depth + <span class="number">1</span>))</span><br></pre></td></tr></table></figure><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>第104题是简单题,只需熟悉二叉树的深度优先搜索与广度优先搜索,并记录对应的层次即可。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="Maximum-Depth-of-Binary-Tree"><a href="#Maximum-Depth-of-Binary-Tree" class="headerlink" title="Maximum Dept</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="深度优先搜索" scheme="https://wqdchn.github.io/tags/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/"/>
<category term="树" scheme="https://wqdchn.github.io/tags/%E6%A0%91/"/>
<category term="二叉树" scheme="https://wqdchn.github.io/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
<category term="广度优先搜索" scheme="https://wqdchn.github.io/tags/%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/"/>
</entry>
<entry>
<title>LeetCode第111题Minimum Depth of Binary Tree</title>
<link href="https://wqdchn.github.io/leetcode-minimum-depth-of-binary-tree.html"/>
<id>https://wqdchn.github.io/leetcode-minimum-depth-of-binary-tree.html</id>
<published>2019-10-10T05:14:13.000Z</published>
<updated>2024-02-17T01:39:55.109Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="Minimum-Depth-of-Binary-Tree"><a href="#Minimum-Depth-of-Binary-Tree" class="headerlink" title="Minimum Depth of Binary Tree"></a>Minimum Depth of Binary Tree</h4><p><a href="https://leetcode.com/problems/minimum-depth-of-binary-tree/">Minimum Depth of Binary Tree</a>求二叉树的最小深度。</p><h5 id="Example"><a href="#Example" class="headerlink" title="Example:"></a>Example:</h5><p><img src="https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png" alt="Lowest Common Ancestor of a Binary Search Tree Example1"></p><blockquote><p>Input: root = [6,2,8,0,4,7,9,null,null,3,5]<br>Output: 3</p></blockquote><p>二叉树的深度可以通过深度优先搜索和广度优先搜索两种方式来遍历,并记录树的层次。</p><h4 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h4><p>下面是<code>Java</code>的代码:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * public class TreeNode {</span></span><br><span class="line"><span class="comment"> * int val;</span></span><br><span class="line"><span class="comment"> * TreeNode left;</span></span><br><span class="line"><span class="comment"> * TreeNode right;</span></span><br><span class="line"><span class="comment"> * TreeNode(int x) { val = x; }</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">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="comment">// dfs</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">minDepth</span><span class="params">(TreeNode root)</span> {</span><br><span class="line"> <span class="keyword">if</span> (root == <span class="literal">null</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">left</span> <span class="operator">=</span> minDepth(root.left);</span><br><span class="line"> <span class="type">int</span> <span class="variable">right</span> <span class="operator">=</span> minDepth(root.right);</span><br><span class="line"> <span class="keyword">return</span> (left == <span class="number">0</span> || right ==<span class="number">0</span>) ? left + right + <span class="number">1</span> : Math.min(left, right) + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// bfs</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">minDepth</span><span class="params">(TreeNode root)</span> {</span><br><span class="line"> <span class="keyword">if</span> (root == <span class="literal">null</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> Deque<TreeNode> q = <span class="keyword">new</span> <span class="title class_">LinkedList</span><>();</span><br><span class="line"> q.add(root);</span><br><span class="line"> <span class="type">int</span> <span class="variable">depth</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (!q.isEmpty()){</span><br><span class="line"> <span class="type">int</span> <span class="variable">size</span> <span class="operator">=</span> q.size();</span><br><span class="line"> <span class="keyword">while</span> (size-- > <span class="number">0</span>){</span><br><span class="line"> <span class="type">TreeNode</span> <span class="variable">node</span> <span class="operator">=</span> q.poll();</span><br><span class="line"> <span class="keyword">if</span> (node.left == <span class="literal">null</span> && node.right == <span class="literal">null</span>){</span><br><span class="line"> <span class="keyword">return</span> depth;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (node.left != <span class="literal">null</span>){</span><br><span class="line"> q.offer(node.left);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (node.right != <span class="literal">null</span>){</span><br><span class="line"> q.offer(node.right);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> depth++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> depth;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面是<code>Python</code>的代码:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"># class TreeNode:</span></span><br><span class="line"><span class="comment"># def __init__(self, x):</span></span><br><span class="line"><span class="comment"># self.val = x</span></span><br><span class="line"><span class="comment"># self.left = None</span></span><br><span class="line"><span class="comment"># self.right = None</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="comment"># dfs</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">minDepth</span>(<span class="params">self, root: TreeNode</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> root:</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">not</span> root.left <span class="keyword">and</span> <span class="keyword">not</span> root.right:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> root.left <span class="keyword">and</span> <span class="keyword">not</span> root.right:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> + self.minDepth(root.left)</span><br><span class="line"> <span class="keyword">if</span> root.right <span class="keyword">and</span> <span class="keyword">not</span> root.left:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> + self.minDepth(root.right)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> + <span class="built_in">min</span>(self.minDepth(root.left), self.minDepth(root.right))</span><br><span class="line"> <span class="comment"># bfs</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">minDepth</span>(<span class="params">self, root</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> root: <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> q = collections.deque([(root, <span class="number">1</span>)])</span><br><span class="line"> <span class="keyword">while</span> q:</span><br><span class="line"> curr, depth = q.popleft()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> curr.left <span class="keyword">and</span> <span class="keyword">not</span> curr.right:</span><br><span class="line"> <span class="keyword">return</span> depth</span><br><span class="line"> <span class="keyword">if</span> curr.left:</span><br><span class="line"> q.append((curr.left, depth + <span class="number">1</span>))</span><br><span class="line"> <span class="keyword">if</span> curr.right:</span><br><span class="line"> q.append((curr.right, depth + <span class="number">1</span>))</span><br></pre></td></tr></table></figure><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>第111题是简单题,只需熟悉二叉树的深度优先搜索与广度优先搜索,并记录对应的层次即可。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="Minimum-Depth-of-Binary-Tree"><a href="#Minimum-Depth-of-Binary-Tree" class="headerlink" title="Minimum Dept</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="深度优先搜索" scheme="https://wqdchn.github.io/tags/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/"/>
<category term="树" scheme="https://wqdchn.github.io/tags/%E6%A0%91/"/>
<category term="二叉树" scheme="https://wqdchn.github.io/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
<category term="广度优先搜索" scheme="https://wqdchn.github.io/tags/%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/"/>
</entry>
<entry>
<title>LeetCode第235题Lowest Common Ancestor of a Binary Search Tree</title>
<link href="https://wqdchn.github.io/leetcode-lowest-common-ancestor-of-a-binary-search-tree.html"/>
<id>https://wqdchn.github.io/leetcode-lowest-common-ancestor-of-a-binary-search-tree.html</id>
<published>2019-10-09T02:23:53.000Z</published>
<updated>2024-02-17T01:39:55.108Z</updated>
<content type="html"><![CDATA[<span id="more"></span><h4 id="Lowest-Common-Ancestor-of-a-Binary-Search-Tree"><a href="#Lowest-Common-Ancestor-of-a-Binary-Search-Tree" class="headerlink" title="Lowest Common Ancestor of a Binary Search Tree"></a>Lowest Common Ancestor of a Binary Search Tree</h4><p><a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/">Lowest Common Ancestor of a Binary Search Tree</a>给定一个二叉<strong>搜索</strong>树,找到树中两个给定结点的最近公共祖先结点<a href="https://en.wikipedia.org/wiki/Lowest_common_ancestor">LCA</a>。</p><h5 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h5><p><img src="https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png" alt="Lowest Common Ancestor of a Binary Search Tree Example1"></p><blockquote><p>Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8<br>Output: 6<br>Explanation: The LCA of nodes 2 and 8 is 6.</p></blockquote><p>这一题和236题<a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/">Lowest Common Ancestor of a Binary Tree</a>有些相似,二叉搜索树是二叉树的一种,所以236题的解法也适用于这题。特别的是,二叉搜索树中根节点的值大于左子树的节点值,小于右子树的节点值,这是可以利用的一个性质:</p><ul><li>我们记<code>LCA(2,8) = 6</code>,此时节点<code>p</code>和<code>q</code>是2和8,我们将节点值与根节点值6进行比较,发现<code>p</code>和<code>q</code>分别位于根节点左右两侧,此时根节点6是最近祖先。</li><li>我们记<code>LCA(7,9) = 8</code>,此时节点<code>p</code>和<code>q</code>是7和9,我们将节点值与根节点值6进行比较,发现<code>p</code>和<code>q</code>都大于根节点,都位于右子树,于是,我们进入右子树进行遍历,此时原来右子树的根节点8成为新的根节点,继续遍历比较。</li></ul><h4 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h4><p>下面是<code>Java</code>的代码:</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * public class TreeNode {</span></span><br><span class="line"><span class="comment"> * int val;</span></span><br><span class="line"><span class="comment"> * TreeNode left;</span></span><br><span class="line"><span class="comment"> * TreeNode right;</span></span><br><span class="line"><span class="comment"> * TreeNode(int x) { val = x; }</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">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> TreeNode <span class="title function_">lowestCommonAncestor</span><span class="params">(TreeNode root, TreeNode p, TreeNode q)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">parentVal</span> <span class="operator">=</span> root.val;</span><br><span class="line"> <span class="type">int</span> <span class="variable">pVal</span> <span class="operator">=</span> p.val;</span><br><span class="line"> <span class="type">int</span> <span class="variable">qVal</span> <span class="operator">=</span> q.val;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (pVal > parentVal && qVal > parentVal) {</span><br><span class="line"> <span class="keyword">return</span> lowestCommonAncestor(root.right, p, q);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pVal < parentVal && qVal < parentVal) {</span><br><span class="line"> <span class="keyword">return</span> lowestCommonAncestor(root.left, p, q);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> root;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面是<code>Python</code>的代码:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"># class TreeNode:</span></span><br><span class="line"><span class="comment"># def __init__(self, x):</span></span><br><span class="line"><span class="comment"># self.val = x</span></span><br><span class="line"><span class="comment"># self.left = None</span></span><br><span class="line"><span class="comment"># self.right = None</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">lowestCommonAncestor</span>(<span class="params">self, root, p, q</span>):</span><br><span class="line"> <span class="keyword">if</span> p.val < root.val > q.val:</span><br><span class="line"> <span class="keyword">return</span> self.lowestCommonAncestor(root.left, p, q)</span><br><span class="line"> <span class="keyword">if</span> p.val > root.val < q.val:</span><br><span class="line"> <span class="keyword">return</span> self.lowestCommonAncestor(root.right, p, q)</span><br><span class="line"> <span class="keyword">return</span> root</span><br></pre></td></tr></table></figure><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>第235题是简单题,利用二叉<strong>搜索</strong>树的性质,通过递归可以写出美感较强的代码,易于阅读。</p>]]></content>
<summary type="html"><span id="more"></span>
<h4 id="Lowest-Common-Ancestor-of-a-Binary-Search-Tree"><a href="#Lowest-Common-Ancestor-of-a-Binary-Search-Tree" cl</summary>
<category term="数据结构与算法" scheme="https://wqdchn.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="LeetCode" scheme="https://wqdchn.github.io/tags/LeetCode/"/>
<category term="树" scheme="https://wqdchn.github.io/tags/%E6%A0%91/"/>
<category term="二叉树" scheme="https://wqdchn.github.io/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
</entry>
</feed>