-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
2354 lines (1938 loc) · 108 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Ranger's blog</title>
<link>https://rangerzz.github.io/</link>
<description>Recent content on Ranger's blog</description>
<generator>Hugo -- gohugo.io</generator>
<language>zh-cn</language>
<lastBuildDate>Tue, 21 Aug 2018 00:00:00 +0000</lastBuildDate>
<atom:link href="https://rangerzz.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>About</title>
<link>https://rangerzz.github.io/about/</link>
<pubDate>Tue, 21 Aug 2018 00:00:00 +0000</pubDate>
<guid>https://rangerzz.github.io/about/</guid>
<description><p>Ranger的博客站。</p>
</description>
</item>
<item>
<title>HTTP基础(下)</title>
<link>https://rangerzz.github.io/post/12/</link>
<pubDate>Sun, 11 Aug 2019 00:00:00 +0000</pubDate>
<guid>https://rangerzz.github.io/post/12/</guid>
<description>
<h2 id="https-http-secure">HTTPS(HTTP Secure)</h2>
<p>HTTP+加密+认证+完整性保护=HTTPS</p>
<p>HTTP通信接口部分用SSL(Secure Socket Layer)和TLS(Transport Layer Security)协议代替</p>
<p>通常HTTP直接和TCP通信,当使用SSL时,则演变成先和SSL通信,再由SSL和TCP通信</p>
<h3 id="公开密钥加密技术-非对称加密">公开密钥加密技术(非对称加密)</h3>
<p>SSL采用公开密钥加密(Publick-key cryptography)的加密处理方式</p>
<p>加密和解密采用同一个秘钥的方式称为<strong>共享秘钥加密(对称加密)</strong></p>
<p><strong>公开密钥加密</strong>使用一对非对称的秘钥,一把不能让其他任何人知道的<strong>私有秘钥</strong>,一把可以随意发布,任何人都可以获得的<strong>公开秘钥</strong>。
使用公开密钥加密(非对称加密),发送密文的一方使用对方的公开秘钥进行加密处理,对方收到被加密信息后,在使用自己的私有秘钥进行解密</p>
<h3 id="https采用混合加密机制">HTTPS采用混合加密机制</h3>
<p>共享密钥加密和公开密钥加密两者并用的混合加密机制,若密钥能实现安全交换,那么有可能考虑仅使用公开密钥加密来通信,但是公开密钥加密比共享密钥加密处理速度要慢</p>
<p>所以,<strong>在交换密钥环节使用公开密钥加密方式,之后的建立通信交换报文阶段使用共享密钥加密方式</strong></p>
<h3 id="证书">证书</h3>
<p>公开密钥加密方式还存在一些问题:无法证明公开密钥本身就是真实的公开密钥,无法证明收到的公开密钥就是原版预想的那台服务器发行的公开密钥,公开密钥在传输的过程中,可能已经被替换掉。</p>
<p>为了解决上述问题,<strong>使用由数字证书认证机构(CA)颁发的公开密钥证书。</strong></p>
<p>所以完整的HTTPS认证过程是:</p>
<ol>
<li>客户端提前内置CA的公开密钥</li>
<li>服务器把自己的公开密钥登陆至CA</li>
<li>CA用自己的私钥向公开密钥部署数字签名并颁发公钥证书</li>
<li>客户端请求服务器时,拿到服务器的公钥证书后,使用内置的CA公开密钥,向CA验证公钥证书上的数字签名,确认服务器的公开密钥的真实性</li>
<li>客户端使用服务器公钥对报文加密后发送</li>
<li>服务器用私钥对报文解密</li>
</ol>
<h2 id="认证">认证</h2>
<p>确认用户身份</p>
<ul>
<li>BASIC认证(基本认证)</li>
<li>DIGEST认证(摘要认证)</li>
<li>SSL客户端认证</li>
<li>FormBase认证(基于表单认证)</li>
</ul>
<h3 id="ssl客户端认证-银行-12306">SSL客户端认证&ndash;银行、12306</h3>
<p>SSL客户端认证借由HTTPS的客户端证书完成认证,需要先将客户端证书发给客户端,客户端必须安装此证书</p>
<p>SSL客户端认证采用双因素认证(Two-factor-authentication),SSL客户端证书是第一个认证要素,密码是另一个认证要素</p>
<h3 id="formbase认证-基于表单认证-多数使用的认证方式">FormBase认证(基于表单认证)&ndash;多数使用的认证方式</h3>
<p>输入用户ID和密码等登录信息,发送给Web应用,基于认证结果来决定是否认证成功</p>
<p>由于HTTP是无状态协议,所以会使用Cookie来管理Session,弥补状态管理功能</p>
<ol>
<li>客户端-登录信息-&gt;服务器,记录认证状态</li>
<li>服务器-Session ID(Set-Cookit:)-&gt;客户端,作为Cookie保存在本地</li>
<li>客户端-包含Session ID的Cookie:-&gt;服务端,验证Session ID判定是否是真实用户</li>
</ol>
<p><strong>通常,通过给密码加盐的方式增加额外信息,再使用散列函数计算出散列值后保存</strong></p>
<h2 id="基于http的协议">基于HTTP的协议</h2>
<h3 id="http的瓶颈">HTTP的瓶颈</h3>
<ul>
<li>一条连接上只可发送一个请求</li>
<li>请求只能从客户端开始,客户端不能接收除响应以外的指令</li>
<li>请求、响应首部未经压缩就发送,首部信息越多延迟越大</li>
<li>发送冗长的首部,每次互相发送相同的首部造成的浪费较多</li>
<li>可选择任意数据压缩格式,非强制压缩发送</li>
</ul>
<h3 id="ajax-asynchronous-javascript-and-xml-异步javascript与xml技术">Ajax(Asynchronous JavaScript and XML)异步JavaScript与XML技术</h3>
<p>利用JavaScript和DOM的操作,达到局部Web页面替换加载的异步通信手段</p>
<p>Ajax的核心技术是名为XMLHttpRequest的API,通过JavaScript的调用就能和服务器进行HTTP通信,可以从已经加载完毕的Web页面发起请求,只更新局部页面。</p>
<p>但是依然无法解决HTTP本身存在的问题(例如非强制压缩,相同首部等)</p>
<h3 id="comet">Comet</h3>
<p>通过延迟应答,模拟实现服务端向客户端推送(Server Push)的功能,Comet会先将响应至于挂起状态,当服务器有内容更新时,再返回响应。</p>
<p>但是存在着一次连接持续时间变长,维持连接会消耗更多的资源等问题,同时也没解决HTTP本身存在的问题</p>
<h3 id="spdy">SPDY</h3>
<p>谷歌发布的,旨在解决HTTP的性能瓶颈,缩短Web页面的加载时间。</p>
<p>SPDY并没有完全改写HTTP协议,而是在TCP/IP的应用层与传输层直接通过新加会话层的形式运作,并且规定通信中使用SSL。使HTTP协议额外获得以下功能</p>
<ul>
<li>多路复用流</li>
<li>赋予请求优先级</li>
<li>压缩HTTP首部</li>
<li>推送功能</li>
<li>服务器提示功能</li>
</ul>
<h3 id="全双工通信的websocket">全双工通信的WebSocket</h3>
<p>一旦服务器和客户端直接建立起WebSocket协议的通信连接,之后所有的通信都依靠这个专用协议进行,可以互相发送JSON、XML、HTML或图片等任意格式数据</p>
<p>主要特点</p>
<ul>
<li>推送功能</li>
<li>减少通信量(一直保持连接状态,首部信息小)</li>
</ul>
<p>连接过程</p>
<ul>
<li>连接开始时还是HTTP协议,所以由客户端先发起连接</li>
<li>客户端:握手请求(Upgrade:websocket)</li>
<li>服务器:握手响应(101 Switching Protocols)</li>
<li>切换成WebSocket协议</li>
<li>客户端服务端互相发送WebSocket独立的数据帧</li>
</ul>
</description>
</item>
<item>
<title>HTTP基础(上)</title>
<link>https://rangerzz.github.io/post/11/</link>
<pubDate>Sun, 04 Aug 2019 00:00:00 +0000</pubDate>
<guid>https://rangerzz.github.io/post/11/</guid>
<description>
<h2 id="osi网络分层">OSI网络分层</h2>
<table>
<thead>
<tr>
<th>分层</th>
<th>OSI分层</th>
<th>该层协议</th>
</tr>
</thead>
<tbody>
<tr>
<td>应用层</td>
<td>应用层</td>
<td>http、ssh、smtp、pop、ssl/tls、ftp、mime、DNS</td>
</tr>
<tr>
<td></td>
<td>表示层</td>
<td></td>
</tr>
<tr>
<td></td>
<td>会话层</td>
<td></td>
</tr>
<tr>
<td>传输层</td>
<td>传输层</td>
<td>tcp、udp</td>
</tr>
<tr>
<td>网络层</td>
<td>网络层</td>
<td>ip4、ip6、ARP(解析地址、根据ip地址反查出对应MAC地址)</td>
</tr>
<tr>
<td>链路层</td>
<td>数据链路层</td>
<td>以太网、网线、光纤</td>
</tr>
<tr>
<td></td>
<td>物理层</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="三次握手">三次握手</h2>
<p>握手过程中使用了TCP的标志(flag)
SYN:synchronize
ACK:acknowledgement</p>
<p>发送端-&gt;接收端:发送标有SYN的数据包</p>
<p>接收端-&gt;发送端:接收到数据包,发送标有SYN/ACK的数据包</p>
<p>发送端-&gt;接收端:收到数据包,发送标有ACK的数据包,握手结束</p>
<p>如果某个阶段莫名中断,TCP协议会再次握手</p>
<h3 id="tcp的三次握手过程-为什么会采用三次握手-若采用二次握手可以吗">TCP的三次握手过程?为什么会采用三次握手,若采用二次握手可以吗?</h3>
<p>答:建立连接的过程是利用客户服务器模式,假设主机A为客户端,主机B为服务器端。</p>
<p>(1)TCP的三次握手过程:主机A向B发送连接请求;主机B对收到的主机A的报文段进行确认;主机A再次对主机B的确认进行确认。</p>
<p>(2)采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。</p>
<p>(3)采用两次握手不行,原因就是上面说的实效的连接请求的特殊情况</p>
<h2 id="四次挥手">四次挥手</h2>
<p><img src="media/15638366103723/15638384794987.jpg" alt="" />
A为客户端,B为服务端</p>
<p>为什么是四次呢?
TCP采用全双工模式</p>
<p>全双工模式:可以同时进行双向的数据传输,所以AB既是发送端又是接收端,所以每次断开连接,需要一个发送端发送FIN断开请求,接收端发送ACK确认断开请求,两个连接,四次挥手</p>
<p>第一次分手:A发送FIN报文段给B,用来断开客户端到服务端的连接,此时A处于FIN_WAIT_1状态,等待B断开连接的确认</p>
<p>第二次分手:B收到A的FIN报文段后,回传一个ACK报文段,同意客户端的断开请求,此时B进入CLOSE_WAIT状态,等待A关闭连接,A收到B的ACK后,A关闭向B发送数据的连接,A进入FIN_WAIT_2状态</p>
<p>第三次挥手:A到B的连接断开后,B发送FIN报文段给A,请求断开服务端到客户端的连接,B进入LAST_ACK状态,等待A断开连接的确认</p>
<p>第四次挥手:A收到B的FIN后,回传一个ACK,同意关闭连接,此时A进入TIME_WAIT状态,B收到A的ACK报文段后,关闭服务端向客户端发送数据的连接,B进入CLOSED状态,此时客户端还处于TIME_WAIT,等待两个MSL时间后,自动进入CLOSED状态</p>
<h2 id="dns服务">DNS服务</h2>
<p>域名-解析-&gt;IP地址</p>
<p>发送端-域名-&gt;DNS
DNS-IP-&gt;发送端
发送端-IP-&gt;对应IP地址的服务器</p>
<h2 id="一次完整http通信过程">一次完整HTTP通信过程</h2>
<p>客户端-域名-&gt;DNS</p>
<p>DNS-IP-&gt;客户端</p>
<p>HTTP协议的职责:生成对目标Web服务器的请求报文</p>
<p>TCP协议的职责:为了方便通信,将HTTP请求报文按序号分割成多个报文段,把每个报文段可靠度传给对方</p>
<p>IP协议的职责:搜索对方地址,一边中转一遍传送</p>
<p>TCP协议的职责:收到报文段后,按序号重组请求报文</p>
<p>HTTP协议的职责:解析客户端对Web服务器的请求的内容的处理</p>
<p>请求处理的结果也同样利用TCP/IP协议向客户端回传</p>
<h2 id="http协议报文">HTTP协议报文</h2>
<p>请求报文由请求方法、请求URI、协议版本、可选的请求首部字段、内容实体构成</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></pre></td>
<td class="lntd">
<pre class="chroma">POST(请求方法) /from(请求URI) HTTP/1.1(协议版本)
Host:google.com
Connection:keep-live
Content-Type:application/x-www-form-urlencoded
Content-Length:16
...
(请求首部字段)
name=uers(内容实体)</pre></td></tr></table>
</div>
</div>
<p>响应报文由协议版本、状态码、解释状态码的原因短语、可选的响应首部字段和实体主体构成</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></pre></td>
<td class="lntd">
<pre class="chroma">HTTP/1.1 200 OK
Date:Tue, 10..
Content-Length:36
Content-Type:text/html
&lt;html&gt;...</pre></td></tr></table>
</div>
</div>
<h2 id="cookie">Cookie</h2>
<p>HTTP是无状态协议,不对发生过的请求和响应的状态进行管理,无法根据之前的状态进行本次的请求处理
由此产生的问题例如Web保存登录状态
Cookie技术通过在请求和响应报文(首部字段)中写入Cookie信息来控制客户端的状态</p>
<h3 id="请求过程">请求过程</h3>
<p>A客户端 B服务器</p>
<p>没有cookie状态下
A-请求(无cookie)-&gt;B
B(Set-Cookie)-响应(带Set-Cookie)-&gt;A(保存cookie)</p>
<p>有cookie状态下
A-请求(cookie)-&gt;B检查cookie
B-响应(根据cookie)-&gt;A</p>
<h2 id="状态码">状态码</h2>
<table>
<thead>
<tr>
<th></th>
<th>类别</th>
<th>原因</th>
</tr>
</thead>
<tbody>
<tr>
<td>1XX</td>
<td>Information 信息性状态码</td>
<td>接收的请求正在处理</td>
</tr>
<tr>
<td>2XX</td>
<td>Success 成功状态码</td>
<td>请求正常处理完毕</td>
</tr>
<tr>
<td>3XX</td>
<td>Redirection 重定向状态码</td>
<td>需要进行附加操作以完成请求</td>
</tr>
<tr>
<td>4XX</td>
<td>Client Error 客户端错误状态码</td>
<td>服务器无法处理请求</td>
</tr>
<tr>
<td>5XX</td>
<td>Server Error 服务器错误状态码</td>
<td>服务器处理请求出错</td>
</tr>
</tbody>
</table>
<h3 id="常见状态码">常见状态码</h3>
<ul>
<li>200 OK 表示从客户端发来的请求在服务端被正常处理了</li>
<li>202 No Content 表示服务器成功处理了请求,但在返回响应报文中不含实体的主体部分,一般在只需要客户端往服务端发送信息时使用</li>
<li>204 Partial Cotent 表示客户端进行了范围请求,服务器成功执行了这部分的GET请求</li>
<li>301 Moved Permanently 永久性重定向,表示请求的资源已被分配新的URI,以后应使用新的URI</li>
<li>302 Found 临时性重定向 ,表示请求的资源已被分配新的URI,希望本次使用新的URI访问</li>
<li>303 See Other 表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源</li>
<li>304 Not Modified 表示客户端发送附带条件(If-Match、If-Modified-Since等)的请求时,服务器允许请求访问资源,但是未满足条件,直接返回304(可直接使用客户端未过期的缓存)</li>
<li>307 Temporary Redirect 临时重定向 类似302,每种浏览器行为不一致</li>
<li>400 Bad Request 表示请求报文中存在语法错误</li>
<li>401 Unauthorized 表示发送的请求需要通过HTTP认证(BASIC、DIGEST认证),若之前已经进行过一次请求,则表示用户认证失败</li>
<li>403 Forbidden 表示请求资源的访问被服务器拒绝了</li>
<li>404 Not Found 表示服务器上无法找到请求的资源</li>
<li>500 Internal Server Error 表示服务器执行请求时发生了错误</li>
<li>503 Service Unavailable 表示服务器处于超负载或者维护中,无法处理请求</li>
</ul>
<h2 id="http的缺点">HTTP的缺点</h2>
<ul>
<li>通信使用明文(不加密),内容可能会被窃听</li>
<li>不验证通信方的身份,有可能遭遇伪装</li>
<li>无法证明报文的完整性,有可能已遭篡改</li>
</ul>
</description>
</item>
<item>
<title>堆栈</title>
<link>https://rangerzz.github.io/post/9/</link>
<pubDate>Tue, 09 Jul 2019 00:00:00 +0000</pubDate>
<guid>https://rangerzz.github.io/post/9/</guid>
<description>
<h2 id="堆栈">堆栈</h2>
<h3 id="抽象数据类型描述">抽象数据类型描述</h3>
<p><strong>具有一定操作约束的线性表,只在一端(栈顶,Top)做插入,删除</strong></p>
<ul>
<li>插入数据:入栈(Push)</li>
<li>删除数据:出栈(Pop)</li>
<li>后入先出:Last In First Out(LIFO)</li>
</ul>
<h4 id="类型名称-堆栈-stack">类型名称:堆栈(Stack)</h4>
<h4 id="数据对象集-一个-有0个或多个元素的有穷线性表">数据对象集:一个 有0个或多个元素的有穷线性表</h4>
<h4 id="操作集">操作集</h4>
<ul>
<li>创建空堆栈</li>
<li>判断堆栈是否已满</li>
<li>将元素压入堆栈</li>
<li>判断堆栈是否为空</li>
<li>删除并返回栈顶元素</li>
</ul>
<h2 id="堆栈的顺序存储实现">堆栈的顺序存储实现</h2>
<p>通常由一个一维数组和一个记录栈顶元素位置的变量组成</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></pre></td>
<td class="lntd">
<pre class="chroma">class Stack&lt;T:Hashable&gt; {
var data : Array&lt;T&gt; = Array();
var top : Int = -1
func push(_ item:T) -&gt; Void {
data.append(item)
top += 1
}
func pop() -&gt; T? {
if top == -1 {
print(&#34;空堆栈&#34;)
return nil
}
top -= 1
return data.popLast()
}
}
let stack = Stack&lt;Int&gt;()
stack.push(0)
stack.push(1)
print(stack.pop())
print(stack.top)</pre></td></tr></table>
</div>
</div>
<h2 id="堆栈的链式存储实现">堆栈的链式存储实现</h2>
<p>堆栈的链式存储结构实际上是一个单链表,叫做链栈,插入和删除操作只能在链栈的栈顶进行</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span></pre></td>
<td class="lntd">
<pre class="chroma">class StackNode&lt;T:Hashable&gt; {
var data : T?
var next : StackNode?
}
class Stack&lt;T:Hashable&gt; {
var top = StackNode&lt;T&gt;()// 指向栈顶,本身无意义
func isEmpty() -&gt; Bool {
if top.next == nil {
return true
}
else {
return false
}
}
func push(_ item:T) -&gt; Void {
let node = StackNode&lt;T&gt;();
node.data = item;
node.next = top.next;
top.next = node
}
func pop() -&gt; T? {
if isEmpty() {
print(&#34;空堆栈&#34;)
return nil
}
let node = top.next
top.next = top.next?.next
return node!.data
}
}
let stack = Stack&lt;String&gt;()
stack.push(&#34;aaa&#34;)
stack.push(&#34;bbb&#34;)
print(stack.top.next?.data)
print(stack.pop())
print(stack.pop())
print(stack.isEmpty())
stack.push(&#34;cccc&#34;)
print(stack.top.next?.data)</pre></td></tr></table>
</div>
</div>
<h2 id="堆栈应用">堆栈应用</h2>
<h3 id="后缀表达式求值">后缀表达式求值</h3>
<ul>
<li>从左向右扫描,逐个处理运算数和运算符号</li>
<li>遇到运算数,入栈</li>
<li>遇到运算符,出栈两个运算数,做运算</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span></pre></td>
<td class="lntd">
<pre class="chroma">class ExpressionOperation {
func input(expression:[String]) -&gt; Int {
let stack = Stack&lt;Int&gt;()
for value in expression {
if isInt(string: value) {
stack.push(Int(value)!)
}
else {
let a = stack.pop()!
let b = stack.pop()!
var ret = 0
switch value {
case &#34;+&#34;:
ret = a + b;
case &#34;-&#34;:
ret = b - a;
case &#34;*&#34;:
ret = a * b;
case &#34;/&#34;:
ret = b / a;
default:
ret = 0
}
stack.push(ret)
}
}
return stack.top.next!.data!
}
func isInt(string: String) -&gt; Bool {
let scan: Scanner = Scanner(string: string)
var val:Int = 0
return scan.scanInt(&amp;val) &amp;&amp; scan.isAtEnd
}
}
let test1 = [&#34;1&#34;,&#34;1&#34;,&#34;+&#34;,&#34;2&#34;,&#34;*&#34;,&#34;2&#34;,&#34;-&#34;,&#34;1&#34;,&#34;/&#34;]
let test2 = [&#34;2&#34;,&#34;9&#34;,&#34;3&#34;,&#34;/&#34;,&#34;+&#34;,&#34;4&#34;,&#34;-&#34;]
let exp = ExpressionOperation()
exp.input(expression: test)</pre></td></tr></table>
</div>
</div>
<h3 id="中缀表达式求值">中缀表达式求值</h3>
<p>基本策略:将中缀表达式转换为后缀表示式,然后求值</p>
<ul>
<li>从头到尾读取中缀表达式的每个元素</li>
<li>运算数:直接输出</li>
<li>左括号:入栈</li>
<li>右括号:将栈顶的运算符出栈并输出,直到遇到左括号(出栈,不输出)</li>
<li>运算符:
<ul>
<li>若优先级大于栈顶运算符时,则入栈</li>
<li>若优先级小于栈顶运算符时,将栈顶运算符出栈并输出,再比较新的栈顶运算符,直到该运算符优先级大于栈顶运算符为止,然后该运算符入栈</li>
<li>若对各个元素处理完毕,则把堆栈中留存的运算符一并输出</li>
</ul></li>
</ul>
<h3 id="其他应用">其他应用</h3>
<ul>
<li>函数调用及递归实现</li>
<li>深度优先搜索</li>
<li>回溯算法</li>
</ul>
</description>
</item>
<item>
<title>队列</title>
<link>https://rangerzz.github.io/post/10/</link>
<pubDate>Tue, 09 Jul 2019 00:00:00 +0000</pubDate>
<guid>https://rangerzz.github.io/post/10/</guid>
<description>
<h2 id="队列">队列</h2>
<h3 id="队列的抽象数据类型描述">队列的抽象数据类型描述</h3>
<p>具有一定操作约束的线性表,只能在一端插入,而在另一端删除</p>
<ul>
<li>数据插入:入队</li>
<li>数据删除:出队</li>
<li>先进先出(FIFO)</li>
</ul>
<h4 id="类型名称-队列-queue">类型名称:队列(Queue)</h4>
<h4 id="数据对象集-一个有0个或多个元素的有穷线性表">数据对象集:一个有0个或多个元素的有穷线性表</h4>
<h4 id="操作集">操作集</h4>
<ul>
<li>创建空队列</li>
<li>判读队列是否已满</li>
<li>插入元素</li>
<li>队列是否为空</li>
<li>将队列头部元素删除并返回</li>
</ul>
<h2 id="队列的顺序存储实现">队列的顺序存储实现</h2>
<p>队列的顺序存储结构通常由一个一维数组和一个记录队列头元素位置的变量front以及一个记录队列尾元素位置的变量rear组成</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></pre></td>
<td class="lntd">
<pre class="chroma">swift的特性不适合描述一个数组实现的队列,故采用老师提供的C语音实现
#define MaxSize &lt;储存数据元素的最大个数&gt;
struct QNode {
ElementType Data[ MaxSize ];
int rear;
int front;
};
typedef struct QNode *Queue;
void AddQ( Queue PtrQ, ElementType item) {
if ( (PtrQ-&gt;rear+1) % MaxSize == PtrQ-&gt;front ) {
printf(“队列满”);
return;
}
PtrQ-&gt;rear = (PtrQ-&gt;rear+1)% MaxSize;
PtrQ-&gt;Data[PtrQ-&gt;rear] = item;
}
ElementType DeleteQ ( Queue PtrQ ) {
if ( PtrQ-&gt;front == PtrQ-&gt;rear ) {
printf(“队列空”);
return ERROR;
} else {
PtrQ-&gt;front = (PtrQ-&gt;front+1)% MaxSize;
return PtrQ-&gt;Data[PtrQ-&gt;front];
}
}</pre></td></tr></table>
</div>
</div>
<h2 id="队列的链式存储实现">队列的链式存储实现</h2>
<p>队列的链式存储结构也可以用一个单链表实现,插入和删除操作分别在链表的两头进行.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span></pre></td>
<td class="lntd">
<pre class="chroma">class QueueNode&lt;T:Hashable&gt; : Equatable {
static func == (lhs: QueueNode&lt;T&gt;, rhs: QueueNode&lt;T&gt;) -&gt; Bool {
if lhs.data == rhs.data &amp;&amp; lhs.next == rhs.next {
return true
}
else {
return false
}
}
var data : T?
var next : QueueNode&lt;T&gt;?
}
class Queue&lt;T:Hashable&gt; {
var rear : QueueNode&lt;T&gt;?
var front : QueueNode&lt;T&gt;?
func isEmpty() -&gt; Bool {
if rear == nil &amp;&amp; front == nil {
return true
}
else {
return false;
}
}
func add(item:T) -&gt; Void {
let node = QueueNode&lt;T&gt;()
node.data = item
if isEmpty() {
rear = node
front = node
return
}
rear!.next = node
rear = node
}
func delete() -&gt; T? {
if isEmpty() {
print(&#34;队列空&#34;)
return nil
}
if front == rear {
let data = front!.data
front = nil