-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
1064 lines (513 loc) · 572 KB
/
local-search.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"?>
<search>
<entry>
<title>nodejs的安装与环境配置</title>
<link href="/2024/09/13/nodejs%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
<url>/2024/09/13/nodejs%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/</url>
<content type="html"><![CDATA[<h2 id="一、介绍">一、介绍</h2><p>基于nodejs提供的不同的下载方式,本文将给出三种不同的安装方式,分别是<a href="#%E4%BA%8C%E4%BD%BF%E7%94%A8nodejs%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8">使用nodejs包管理器</a>、<a href="#%E4%B8%89%E6%89%8B%E5%8A%A8%E5%AE%89%E8%A3%85">手动安装</a>、<a href="#%E5%9B%9B%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85">源码编译安装</a>,每种方式各有优劣,但针对不同的操作系统,推荐windows用户<a href="#1-%E4%BD%BF%E7%94%A8%E9%A2%84%E6%9E%84%E5%BB%BA%E5%AE%89%E8%A3%85%E5%8C%85">使用预构建安装包</a>进行安装,linux用户<a href="#%E4%BA%8C%E4%BD%BF%E7%94%A8nodejs%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8">使用nodejs包管理器</a>或<a href="#2-%E4%BD%BF%E7%94%A8%E9%A2%84%E6%9E%84%E5%BB%BA%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6">使用预构建二进制文件</a>进行安装,其中使用nodejs包管理器是一种多系统通用的且较为简单的方式,后文将依次进行介绍。</p><p>另外,由于官方npm仓库下载速度较慢,推荐大陆用户在使用npm之前<a href="#%E8%AE%BE%E7%BD%AE%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90">设置国内镜像源</a>。</p><h2 id="二、使用nodejs包管理器">二、使用nodejs包管理器</h2><h2 id="三、手动安装">三、手动安装</h2><h3 id="1-Linux系统">(1)Linux系统</h3><h4 id="1-使用linux包管理器">1. 使用linux包管理器</h4><h4 id="2-使用预构建二进制文件">2. 使用预构建二进制文件</h4><h5 id="下载预编译二进制文件">下载预编译二进制文件</h5><p>前往<a href="https://nodejs.cn/en/download/prebuilt-binaries">nodejs中文网</a>下载适用于linux系统的指定版本的预构建二进制文件,例如版本<a href="https://npmmirror.com/mirrors/node/v20.17.0/node-v20.17.0-linux-x64.tar.xz">node.js v20.17.0</a>。</p><h5 id="解压到指定路径">解压到指定路径</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">cd /opt # 建议安装至/opt目录<br>sudo mkdir nodejs #建立nodejs文件夹<br>cd nodejs # 切换工作目录到nodejs<br>sudo tar -xvf ~/Downloads/node-v20.17.0-linux-x64.tar.xz # 解压到当前目录下<br></code></pre></td></tr></table></figure><h5 id="配置环境变量">配置环境变量</h5><p>编辑<code>/etc/profile</code>文件或用户配置文件<code>~/.bashrc</code>均可。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">sudo vim /etc/profile<br></code></pre></td></tr></table></figure><p>将下面的配置内容追加到文件末尾即可:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash"><span class="hljs-built_in">set</span> nodejs/bin to PATH</span><br>NODEJS_VERSION=v20.17.0 # 此处为你下载预构建二进制文件的版本号<br>export PATH=/opt/nodejs/node-$NODEJS_VERSION-linux-x64/bin:$PATH<br></code></pre></td></tr></table></figure><h5 id="重载配置文件">重载配置文件</h5><p>重启或注销即可,也可以执行<code>source /etc/profile</code>在当前终端立即生效。输入<code>npm --version</code>若成功输出npm工具版本号则安装成功。</p><h3 id="2-Windows系统">(2)Windows系统</h3><h4 id="1-使用预构建安装包">1. 使用预构建安装包</h4><h4 id="2-使用预构建二进制包">2. 使用预构建二进制包</h4><h2 id="四、源码编译安装">四、源码编译安装</h2><h2 id="设置国内镜像源">设置国内镜像源</h2><h3 id="1-镜像源地址">(1)镜像源地址</h3><ol><li>淘宝源:<a href="https://registry.npmmirror.com/">https://registry.npmmirror.com/</a></li></ol><h3 id="2-临时修改">(2)临时修改</h3><p>在执行安装命令时加入<code>--registry</code>选项。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm install 软件名 --registry https://registry.npmmirror.com<br></code></pre></td></tr></table></figure><h3 id="3-全局修改">(3)全局修改</h3><p>为当前用户全局环境设置,若需要<code>sudo</code>提权,则需要为root用户设置。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm config set registry https://registry.npmmirror.com<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>简单记录</category>
</categories>
<tags>
<tag>nodejs</tag>
</tags>
</entry>
<entry>
<title>程序员必备工具:git</title>
<link href="/2024/09/13/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BF%85%E5%A4%87%E5%B7%A5%E5%85%B7-git/"/>
<url>/2024/09/13/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BF%85%E5%A4%87%E5%B7%A5%E5%85%B7-git/</url>
<content type="html"><![CDATA[<h2 id="一、安装">一、安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">sudo apt install git<br></code></pre></td></tr></table></figure><h2 id="二、初始化配置">二、初始化配置</h2><h3 id="1-用户信息">(1)用户信息</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">git config --global user.name "John Doe"<br>git config --global user.email johndoe@example.com<br></code></pre></td></tr></table></figure><h3 id="2-文本编辑器">(2)文本编辑器</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git config --global core.editor vim<br></code></pre></td></tr></table></figure><h3 id="3-检查配置信息">(3)检查配置信息</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git config --list<br></code></pre></td></tr></table></figure><h2 id="三、Git-Bash命令">三、Git Bash命令</h2><h3 id="1-克隆仓库">(1)克隆仓库</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git clone https://github.com/your-username/your-repository.git<br></code></pre></td></tr></table></figure><h3 id="2-提交代码">(2)提交代码</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">git add . # 添加当前工作目录所有文件<br>git commit -m "commit message"<br>git push<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>简单记录</category>
</categories>
<tags>
<tag>git</tag>
</tags>
</entry>
<entry>
<title>使用markdown制作ppt演示并嵌入到博客中</title>
<link href="/2024/09/08/%E4%BD%BF%E7%94%A8markdown%E5%88%B6%E4%BD%9Cppt%E6%BC%94%E7%A4%BA%E5%B9%B6%E5%B5%8C%E5%85%A5%E5%88%B0%E5%8D%9A%E5%AE%A2%E4%B8%AD/"/>
<url>/2024/09/08/%E4%BD%BF%E7%94%A8markdown%E5%88%B6%E4%BD%9Cppt%E6%BC%94%E7%A4%BA%E5%B9%B6%E5%B5%8C%E5%85%A5%E5%88%B0%E5%8D%9A%E5%AE%A2%E4%B8%AD/</url>
<content type="html"><![CDATA[<p>在学习rcore课程与观看开源操作系统夏令营课程时,偶然发现老师使用markdown文件编译出的web ppt,于是吸引了我的注意,遂自行进行尝试,以本文记录slidev的使用方法以及嵌入博客的方法,供本人使用时快速查阅参考。</p><p>另外,还有一个更简洁的项目名为<a href="https://github.com/rrrene/nodePPT">nodeppt</a>,但已许久未进行更新,并且可能不兼容nodejs v22,遂并未使用。网上有诸多博客记录如何将nodeppt嵌入hexo博客中,参考那些博客我也顺利将slidev嵌入到hexo中。</p><blockquote><p>本文参考自官方<a href="https://cn.sli.dev/guide/">快速上手指南</a>,仅记录本人常用部分内容,需要获取更多信息或进阶操作请自行阅读手册。</p></blockquote><h2 id="官方demo">官方<a href="../../../../slidev/demo/index.html">demo</a></h2><iframe src="../../../../slidev/demo/index.html" width="100%" height="500" name="topFrame" scrolling="yes" noresize="noresize" frameborder="0" id="topFrame"></iframe><h2 id="安装slidev命令行工具">安装slidev命令行工具</h2><p>slidev由node.js提供,在安装slidev之前需要先保证node.js安装配置正确,并且版本号大于v18。并且出于网速考虑,建议在安装之前确保已经设置可用的软件源。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">sudo npm install @slidev/cli -g<br></code></pre></td></tr></table></figure><blockquote><p>在执行这条命令时,由于配置在<code>/etc/profile</code>或<code>.profile</code>中的nodejs的bin不被sudo信任,所以可能会出现找不到命令npm的情况,如果出现了,最简单的方法是先执行<code>sudo -i</code>提权再执行<code>npm install @slidev/cli -g</code>安装到全局目录吧。</p></blockquote><h2 id="创建slidev项目">创建slidev项目</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm init slidev@latest # 使用npm<br></code></pre></td></tr></table></figure><p>在创建项目时会询问是否需要自动执行<code>npm install</code>与<code>npm run dev</code>,根据需要进行选择。若选择否则需要自行根据提示进入到目录内执行安装和服务命令。</p><blockquote><p>官方还提供了使用StackBlitz在浏览器中在线创建幻灯片的形式<a href="https://sli.dev/new">sli.dev/new</a>,但我没进行尝试,看起来可以省去安装环境的烦恼。</p></blockquote><h2 id="slidev常用方法">slidev常用方法</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev # 启动开发服务器<br>slidev export # 将幻灯片导出为 PDF、PPTX 或 PNG 文件<br>slidev build # 将幻灯片构建为静态网页<br>slidev format # 将幻灯片格式化<br>slidev --help # 显示帮助信息<br></code></pre></td></tr></table></figure><p>详见<a href="#%E5%AF%BC%E5%87%BA%E4%B8%BA%E5%85%B6%E4%BB%96%E6%96%87%E4%BB%B6">导出为其他文件</a>、<a href="#%E6%9E%84%E5%BB%BA%E9%9D%99%E6%80%81%E7%BD%91%E9%A1%B5">构建静态网页</a>、<a href="#%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%B9%BB%E7%81%AF%E7%89%87">格式化幻灯片</a>部分。</p><h2 id="ppt演示">ppt演示</h2><h3 id="界面">界面</h3><img src="/2024/09/08/%E4%BD%BF%E7%94%A8markdown%E5%88%B6%E4%BD%9Cppt%E6%BC%94%E7%A4%BA%E5%B9%B6%E5%B5%8C%E5%85%A5%E5%88%B0%E5%8D%9A%E5%AE%A2%E4%B8%AD/ui.png" class="" title="ui"><p>如上图所示,将鼠标移至界面左下角可见悬浮的工具栏,从左往右依次是<code>全屏</code>、<code>上一页</code>、<code>下一页</code>、<code>总览</code>、夜(日)间模式、<code>绘制工具</code>、<code>演讲者视角</code>、<code>信息</code>、<code>设置</code>、<code>幻灯片页码</code>。</p><h3 id="快捷键">快捷键</h3><p>部分常用快捷键如下,slidev演示还支持<a href="https://cn.sli.dev/custom/config-shortcuts">自定义快捷键</a>,可根据官方手册进行尝试。</p><table><thead><tr><th>快捷键</th><th>动作</th></tr></thead><tbody><tr><td>f</td><td>切换全屏</td></tr><tr><td>right / space</td><td>下一动画或幻灯片</td></tr><tr><td>left</td><td>上一动画或幻灯片</td></tr><tr><td>up</td><td>上一张幻灯片</td></tr><tr><td>down</td><td>下一张幻灯片</td></tr><tr><td>o</td><td>切换幻灯片总览</td></tr><tr><td>d</td><td>切换暗黑模式</td></tr><tr><td>g</td><td>显示“前往…页”</td></tr></tbody></table><h2 id="导出为其他文件">导出为其他文件</h2><h3 id="准备工作">准备工作</h3><p>导出为 PDF、PPTX 或 PNG 依赖于 <a href="https://playwright.dev/">Playwright</a> 来渲染幻灯片。因此,你需要在你的项目中安装 <a href="https://npmjs.com/package/playwright-chromium"><code>playwright-chromium</code></a>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i -D playwright-chromium<br></code></pre></td></tr></table></figure><h3 id="支持的格式">支持的格式</h3><h4 id="PDF">PDF</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev export<br></code></pre></td></tr></table></figure><h4 id="PPTX">PPTX</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev export --format pptx<br></code></pre></td></tr></table></figure><p>需要注意的是,PPTX 文件中的所有幻灯片都会被导出为图片,因此文本不可选择。演讲者备注将以每张幻灯片为单位传递到 PPTX 文件中。</p><p>在此模式下,默认启用了 <code>--with-clicks</code> 选项。要禁用它,请传递 <code>--with-clicks false</code>。</p><blockquote><p><code>--with-clicks</code> 选项将幻灯片的多个步骤导出为多个页面,包含点击动画,在进行其他类型导出时可以手动加上。</p></blockquote><h4 id="PNGs-或-Markdown">PNGs 或 Markdown</h4><p>当传递 <code>--format png</code> 选项时,Slidev 会为每张幻灯片导出 PNG 图像而不是 PDF:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev export --format png<br></code></pre></td></tr></table></figure><p>你也可以使用 <code>--format md</code> 选项将幻灯片导出为 Markdown 文件:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev export --format md<br></code></pre></td></tr></table></figure><h4 id="PDF-大纲">PDF 大纲</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev export --with-toc<br></code></pre></td></tr></table></figure><p>更多选项见<a href="https://cn.sli.dev/guide/exporting">手册-导出幻灯片</a>。</p><h2 id="格式化幻灯片">格式化幻灯片</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev format [entry]<br></code></pre></td></tr></table></figure><p>格式化 markdown 文件。请注意,这不会格式化幻灯片的内容,只会格式化 markdown 文件的组织结构。</p><ul><li><code>[entry]</code> (<code>string</code>, 默认值: <code>slides.md</code>): 幻灯片的 markdown 文件路径</li></ul><h2 id="构建静态网页">构建静态网页</h2><p>你可以通过以下命令将幻灯片构建为静态的 <a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA">单页应用 (SPA)</a>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev build<br></code></pre></td></tr></table></figure><p>默认情况下,生成的文件会被放在 <code>dist</code> 文件夹中。你可以通过运行 <code>npx vite preview</code> 或任何其他静态服务器来测试你的幻灯片的构建版本。</p><blockquote><p>运行<code>npx vite preview</code>命令时需要在当前工作路径下存在<code>dist</code>文件夹,而不是在<code>dist</code>文件夹内。</p></blockquote><h3 id="基础路径">基础路径</h3><p>若要将你的幻灯片部署在子目录下,你需要传递 <code>--base</code> 选项。<code>--base</code> 路径<strong>必须以斜杠 <code>/</code> 开头和结尾</strong>。例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev build --base /slidev/demo/<br></code></pre></td></tr></table></figure><p>基础路径很重要,若是将ppt部署在hexo内,必须将基础路径修改成对应于hexo的<code>source</code>路径。具体说明详见<a href="#%E5%B5%8C%E5%85%A5%E5%88%B0%E5%8D%9A%E5%AE%A2%E4%B8%AD">嵌入到博客中</a>。</p><h3 id="输出目录">输出目录</h3><p>你可以通过 <code>--out</code> 选项更改输出目录:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">slidev build --out my-build-folder<br></code></pre></td></tr></table></figure><h2 id="嵌入到博客中">嵌入到博客中</h2><p>将slidev生成的静态页面嵌入hexo中,亲测可以正常放映以及可以进入全屏模式放映。</p><h3 id="配置hexo编译跳过目录">配置hexo编译跳过目录</h3><p>在Hexo博客里想调用或者链接slidev生成的html,需要hexo设置<code>skip_render</code>, 指定不进行渲染的文件或文件夹,例如在<code>source</code>目录下新建<code>slidev</code>来存放slidev生成的html,则需要在根目录下的<code>_config.yml</code>文件添加:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">skip_render:</span> <br> <span class="hljs-bullet">-</span> <span class="hljs-string">slidev/**</span><br></code></pre></td></tr></table></figure><h3 id="构建slidev静态页面">构建slidev静态页面</h3><p>例如我将把页面放在博客源码的source/slidev/demo路径下,执行命令<code>slidev build --base /slidev/demo/</code>即可。</p><h3 id="放入静态页面">放入静态页面</h3><p>将编译出的文件夹<code>dist</code>直接放入<code>source/slidev/</code>目录下,并改名为<code>demo</code>。</p><h3 id="在文章中引用">在文章中引用</h3><p>首先需要知道ppt相较于当前文章路径的相对路径,如下图,在我的博客编译后的<code>public</code>路径下,需要向上4层才能回到根路径,<code>public</code>路径便视为根目录,因此该ppt对本文章的相对路径则为<code>../../../../slidev/demo/index.html</code>,因此在文章内访问该相对地址可以直接访问静态资源。</p><img src="/2024/09/08/%E4%BD%BF%E7%94%A8markdown%E5%88%B6%E4%BD%9Cppt%E6%BC%94%E7%A4%BA%E5%B9%B6%E5%B5%8C%E5%85%A5%E5%88%B0%E5%8D%9A%E5%AE%A2%E4%B8%AD/%E8%B7%AF%E5%BE%84.png" class="" title="路径"><h3 id="嵌入到文章中">嵌入到文章中</h3><p>通过插入<code>iframe</code>标签实现:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">iframe</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"../../../../slidev/demo/index.html"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"100%"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"500"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"topFrame"</span> <span class="hljs-attr">scrolling</span>=<span class="hljs-string">"yes"</span> <span class="hljs-attr">noresize</span>=<span class="hljs-string">"noresize"</span> <span class="hljs-attr">frameborder</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"topFrame"</span>></span><span class="hljs-tag"></<span class="hljs-name">iframe</span>></span><br></code></pre></td></tr></table></figure><h2 id="Slidev-Markdown语法">Slidev Markdown语法</h2><p>详见<a href="https://cn.sli.dev/guide/syntax">手册-语法</a>。</p>]]></content>
<categories>
<category>简单记录</category>
</categories>
<tags>
<tag>Slidev</tag>
<tag>Web PPT</tag>
<tag>Hexo</tag>
<tag>nodejs</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——总线和输入/输出系统</title>
<link href="/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%80%BB%E7%BA%BF%E5%92%8C%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA%E7%B3%BB%E7%BB%9F/"/>
<url>/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%80%BB%E7%BA%BF%E5%92%8C%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA%E7%B3%BB%E7%BB%9F/</url>
<content type="html"><![CDATA[<h1>总线和输入/输出系统</h1><h2 id="一、总线">一、总线</h2><h3 id="(一)总线的基本概念">(一)总线的基本概念</h3><h3 id="(二)总线的组成及性能指标">(二)总线的组成及性能指标</h3><h3 id="(三)总线事务和定时">(三)总线事务和定时</h3><h2 id="二、I-O接口(I-O控制器)">二、I/O接口(I/O控制器)</h2><h3 id="(一)I-O接口的功能和基本结构">(一)I/O接口的功能和基本结构</h3><h3 id="(二)I-O接口及其编址">(二)I/O接口及其编址</h3><h2 id="三、I-O方式">三、I/O方式</h2><h3 id="(一)程序查询方式">(一)程序查询方式</h3><h3 id="(二)程序中断方式">(二)程序中断方式</h3><p>中断的基本概念,中断响应过程,中断处理过程,多重中断和中断屏蔽的概念。</p><h3 id="(三)DMA方式">(三)DMA方式</h3><p>DMA控制器的组成,DMA传送过程。</p>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>总线和输入/输出系统</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——中央处理器(CPU)</title>
<link href="/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E4%B8%AD%E5%A4%AE%E5%A4%84%E7%90%86%E5%99%A8%EF%BC%88CPU%EF%BC%89/"/>
<url>/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E4%B8%AD%E5%A4%AE%E5%A4%84%E7%90%86%E5%99%A8%EF%BC%88CPU%EF%BC%89/</url>
<content type="html"><![CDATA[<h1>中央处理器(CPU)</h1><h2 id="一、CPU的功能和基本结构">一、CPU的功能和基本结构</h2><h2 id="二、指令执行过程">二、指令执行过程</h2><h2 id="三、数据通路的功能和基本结构">三、数据通路的功能和基本结构</h2><h2 id="四、控制器的功能和工作原理">四、控制器的功能和工作原理</h2><h2 id="五、异常和中断机制">五、异常和中断机制</h2><h3 id="(一)异常和中断的基本概念">(一)异常和中断的基本概念</h3><h3 id="(二)异常和中断的分类">(二)异常和中断的分类</h3><h3 id="(三)异常和中断的检测与响应">(三)异常和中断的检测与响应</h3><h2 id="六、指令流水线">六、指令流水线</h2><h3 id="(一)指令流水线的基本概念">(一)指令流水线的基本概念</h3><h3 id="(二)指令流水线的基本实现">(二)指令流水线的基本实现</h3><h3 id="(三)结构冒险、数据冒险和控制冒险的处理">(三)结构冒险、数据冒险和控制冒险的处理</h3><h3 id="(四)超标量和动态流水线的基本概念">(四)超标量和动态流水线的基本概念</h3><h2 id="七、多处理器基本概念">七、多处理器基本概念</h2><h3 id="(一)SISD、SIMD、MIMD、向量处理器的基本概念">(一)SISD、SIMD、MIMD、向量处理器的基本概念</h3><h3 id="(二)硬件多线程的基本概念">(二)硬件多线程的基本概念</h3><h3 id="(三)多核-multi-core-处理器的基本概念">(三)多核(multi-core)处理器的基本概念</h3><h3 id="(四)共享内存多处理器-SMP-的基本概念">(四)共享内存多处理器(SMP)的基本概念</h3>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>中央处理器</tag>
<tag>CPU</tag>
</tags>
</entry>
<entry>
<title>数据结构——排序</title>
<link href="/2024/08/22/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%8E%92%E5%BA%8F/"/>
<url>/2024/08/22/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%8E%92%E5%BA%8F/</url>
<content type="html"><![CDATA[<h1>排序</h1><h2 id="一、排序的基本概念">一、排序的基本概念</h2><h2 id="二、直接插入排序">二、直接插入排序</h2><h2 id="三、折半插入排序">三、折半插入排序</h2><h2 id="四、起泡排序-bubble-sort">四、起泡排序(bubble sort)</h2><h2 id="五、简单选择排序">五、简单选择排序</h2><h2 id="六、希尔排序-shell-sort">六、希尔排序(shell sort)</h2><h2 id="七、快速排序">七、快速排序</h2><h2 id="八、堆排序">八、堆排序</h2><h2 id="九、二路归并排序-merge-sort">九、二路归并排序(merge sort)</h2><h2 id="十基数排序">十基数排序</h2><h2 id="十一、外部排序">十一、外部排序</h2><h2 id="十二、排序算法的分析和应用">十二、排序算法的分析和应用</h2>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>排序</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——输入/输出(I/O)管理</title>
<link href="/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA-I-O-%E7%AE%A1%E7%90%86/"/>
<url>/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA-I-O-%E7%AE%A1%E7%90%86/</url>
<content type="html"><![CDATA[<h1>输入/输出(I/O)管理</h1><h2 id="一、I-O-管理基础">一、I/O 管理基础</h2><h3 id="(一)设备">(一)设备</h3><p>设备的基本概念,设备的分类,I/O 接口,I/O 端口。</p><h3 id="(二)I-O-控制方式">(二)I/O 控制方式</h3><p>轮询方式,中断方式,DMA 方式。</p><h3 id="(三)I-O-软件层次结构">(三)I/O 软件层次结构</h3><p>中断处理程序,驱动程序,设备独立软件,用户层I/O软件。</p><h3 id="(四)输入-输出应用程序接口">(四)输入/输出应用程序接口</h3><p>字符设备接口,块设备接口,网络设备接口,阻塞/非阻塞I/O。</p><h2 id="二、设备独立文件">二、设备独立文件</h2><h3 id="(一)缓存区管理">(一)缓存区管理</h3><h3 id="(二)设备分配和回收">(二)设备分配和回收</h3><h3 id="(三)假脱机技术-SPOOLing">(三)假脱机技术(SPOOLing)</h3><h3 id="(四)设备驱动程序接口">(四)设备驱动程序接口</h3><h2 id="三、外存管理">三、外存管理</h2><h3 id="(一)磁盘">(一)磁盘</h3><p>磁盘结构,格式化,分区,磁盘调度方法。</p><h3 id="(二)固态硬盘">(二)固态硬盘</h3><p>读写性能特性,磨损均衡。</p>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>输入/输出(I/O)管理</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——文件管理</title>
<link href="/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86/"/>
<url>/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86/</url>
<content type="html"><![CDATA[<h1>文件管理</h1><h2 id="一、文件">一、文件</h2><h3 id="(一)文件的基本概念">(一)文件的基本概念</h3><h3 id="(二)文件元数据和索引结点-inode">(二)文件元数据和索引结点(inode)</h3><h3 id="(三)文件的操作">(三)文件的操作</h3><p>建立,删除,打开,关闭,读,写。</p><h3 id="(四)文件的保护">(四)文件的保护</h3><h3 id="(五)文件的逻辑结构">(五)文件的逻辑结构</h3><h3 id="(六)文件的物理结构">(六)文件的物理结构</h3><h2 id="二、目录">二、目录</h2><h3 id="(一)目录的基本概念">(一)目录的基本概念</h3><h3 id="(二)树形目录">(二)树形目录</h3><h3 id="(三)目录的操作">(三)目录的操作</h3><h3 id="(四)硬链接和软链接">(四)硬链接和软链接</h3><h2 id="三、文件系统">三、文件系统</h2><h3 id="(一)文件系统的全局结构-layout">(一)文件系统的全局结构(layout)</h3><p>文件系统在外存中的结构,文件系统在内存中的结构。</p><h3 id="(二)外存空闲空间管理方法">(二)外存空闲空间管理方法</h3><h3 id="(三)虚拟文件系统">(三)虚拟文件系统</h3><h3 id="(四)文件系统挂载-mounting">(四)文件系统挂载(mounting)</h3>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>文件管理</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——指令系统</title>
<link href="/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%8C%87%E4%BB%A4%E7%B3%BB%E7%BB%9F/"/>
<url>/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%8C%87%E4%BB%A4%E7%B3%BB%E7%BB%9F/</url>
<content type="html"><![CDATA[<h1>指令系统</h1><h2 id="一、指令系统的基本概念">一、指令系统的基本概念</h2><h2 id="二、指令格式">二、指令格式</h2><h2 id="三、寻址方式">三、寻址方式</h2><h2 id="四、数据的对齐和大-小端存放方式">四、数据的对齐和大/小端存放方式</h2><h2 id="五、CISC和RISC的基本概念">五、CISC和RISC的基本概念</h2><h2 id="六、高级语言程序与与机器级代码之间的对应">六、高级语言程序与与机器级代码之间的对应</h2><h3 id="(一)编译器、汇编器和链接器的基本概念">(一)编译器、汇编器和链接器的基本概念</h3><h3 id="(二)选择结构语句的机器级表示">(二)选择结构语句的机器级表示</h3><h3 id="(三)循环结构语句的机器级表示">(三)循环结构语句的机器级表示</h3><h3 id="(四)过程(函数)调用对应的机器级表示">(四)过程(函数)调用对应的机器级表示</h3>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>指令系统</tag>
</tags>
</entry>
<entry>
<title>数据结构——查找</title>
<link href="/2024/08/21/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%9F%A5%E6%89%BE/"/>
<url>/2024/08/21/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%9F%A5%E6%89%BE/</url>
<content type="html"><![CDATA[<h1>查找</h1><h2 id="一、查找的基本概念">一、查找的基本概念</h2><h2 id="二、顺序查找法">二、顺序查找法</h2><h2 id="三、分块查找法">三、分块查找法</h2><h2 id="四、折半查找法">四、折半查找法</h2><h2 id="五、树形查找">五、树形查找</h2><h3 id="(一)二叉搜索树">(一)二叉搜索树</h3><h3 id="(二)平衡二叉树">(二)平衡二叉树</h3><h3 id="(三)红黑树">(三)红黑树</h3><h2 id="六、B树及其基本操作、B-树的基本概念">六、B树及其基本操作、B+树的基本概念</h2><h2 id="七、散列-hash-表">七、散列(hash)表</h2><h2 id="八、字符串模式匹配">八、字符串模式匹配</h2><h2 id="九、查找算法的分析及其应用">九、查找算法的分析及其应用</h2>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>查找</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——内存管理</title>
<link href="/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"/>
<url>/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</url>
<content type="html"><![CDATA[<h1>内存管理</h1><h2 id="一、内存管理基础">一、内存管理基础</h2><h3 id="(一)内存管理的基本概念">(一)内存管理的基本概念</h3><p>逻辑地址空间与物理地址空间,地址变换,内存共享,内存保护,内存分配与回收。</p><h3 id="(二)连续分配管理方式">(二)连续分配管理方式</h3><h3 id="(三)页式管理">(三)页式管理</h3><h3 id="(四)段式管理">(四)段式管理</h3><h3 id="(五)段页式管理">(五)段页式管理</h3><h2 id="二、虚拟内存管理">二、虚拟内存管理</h2><h3 id="(一)虚拟内存的基本概念">(一)虚拟内存的基本概念</h3><h3 id="(二)请求页式管理">(二)请求页式管理</h3><h3 id="(三)页框分配">(三)页框分配</h3><h3 id="(四)页面置换算法">(四)页面置换算法</h3><p>最佳置换算法(OPT);先进先出置换算法(FIFO);最近最少使用置换算法(LRU);时钟置换算法(CLOCK)。</p><h3 id="(五)内存映射文件-Memory-Mapped-Flies">(五)内存映射文件(Memory-Mapped Flies)</h3><h3 id="(六)拟存储器性能的影响因素及改进方法">(六)拟存储器性能的影响因素及改进方法</h3>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>内存管理</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——存储器层次结构</title>
<link href="/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E5%AD%98%E5%82%A8%E5%99%A8%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84/"/>
<url>/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E5%AD%98%E5%82%A8%E5%99%A8%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84/</url>
<content type="html"><![CDATA[<h1>存储器层次结构</h1><h2 id="一、存储器的分类">一、存储器的分类</h2><h2 id="二、层次化存储器的基本结构">二、层次化存储器的基本结构</h2><h2 id="三、半导体随机存取存储器">三、半导体随机存取存储器</h2><h3 id="(一)SRAM-存储器">(一)SRAM 存储器</h3><h3 id="(二)DRAM-存储器">(二)DRAM 存储器</h3><h3 id="(三)Flash-存储器">(三)Flash 存储器</h3><h2 id="四、主存储器">四、主存储器</h2><h3 id="(一)DRAM-芯片和内存条">(一)DRAM 芯片和内存条</h3><h3 id="(二)多模块存储器">(二)多模块存储器</h3><h3 id="(三)主存和CPU之间的连接">(三)主存和CPU之间的连接</h3><h2 id="五、外部存储器">五、外部存储器</h2><h3 id="(一)磁盘存储器">(一)磁盘存储器</h3><h3 id="(二)固态硬盘(SSD)">(二)固态硬盘(SSD)</h3><h2 id="六、高速缓存存储器(Cache)">六、高速缓存存储器(Cache)</h2><h3 id="(一)Cache-的基本原理">(一)Cache 的基本原理</h3><h3 id="(二)Cache-和主存之间的映射方式">(二)Cache 和主存之间的映射方式</h3><h3 id="(三)Cache-中主存块的替换算法">(三)Cache 中主存块的替换算法</h3><h3 id="(四)Cache-写策略">(四)Cache 写策略</h3><h2 id="七、虚拟存储器">七、虚拟存储器</h2><h3 id="(一)虚拟存储器的基本概念">(一)虚拟存储器的基本概念</h3><h3 id="(二)页式虚拟存储器">(二)页式虚拟存储器</h3><p>基本原理,页表,地址转换,TLB(快表)。</p><h3 id="(三)段式虚拟存储器的基本原理">(三)段式虚拟存储器的基本原理</h3><h3 id="(四)段页式虚拟存储器的基本原理">(四)段页式虚拟存储器的基本原理</h3>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>存储器层次结构</tag>
</tags>
</entry>
<entry>
<title>数据结构——图</title>
<link href="/2024/08/20/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E5%9B%BE/"/>
<url>/2024/08/20/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E5%9B%BE/</url>
<content type="html"><![CDATA[<h1>图</h1><h2 id="一、图的基本概念">一、图的基本概念</h2><h2 id="二、图的存储及基本操作">二、图的存储及基本操作</h2><h3 id="(一)邻接矩阵">(一)邻接矩阵</h3><h3 id="(二)邻接表法">(二)邻接表法</h3><h3 id="(三)邻接多重表,十字链表">(三)邻接多重表,十字链表</h3><h2 id="三、图的遍历">三、图的遍历</h2><h3 id="(一)深度优先搜索">(一)深度优先搜索</h3><h3 id="(二)广度优先搜索">(二)广度优先搜索</h3><h2 id="四、图的基本应用">四、图的基本应用</h2><h3 id="(一)最小(代价)生成树">(一)最小(代价)生成树</h3><h3 id="(二)最短路径">(二)最短路径</h3><h3 id="(三)拓扑排序">(三)拓扑排序</h3><h3 id="(四)关键路径">(四)关键路径</h3>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——进程管理</title>
<link href="/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/"/>
<url>/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</url>
<content type="html"><![CDATA[<h1>进程管理</h1><h2 id="一、进程与线程">一、进程与线程</h2><h3 id="(一)进程与线程的基本概念">(一)进程与线程的基本概念</h3><h3 id="(二)进程的状态与转换">(二)进程的状态与转换</h3><h3 id="(三)线程的实现">(三)线程的实现</h3><h4 id="1-内核支持的线程">1. 内核支持的线程</h4><h4 id="2-线程库支持的线程">2. 线程库支持的线程</h4><h3 id="(四)进程与线程的组织与控制">(四)进程与线程的组织与控制</h3><h3 id="(五)-进程间通信">(五) 进程间通信</h3><h4 id="1-共享内存">1. 共享内存</h4><h4 id="2-消息传递">2. 消息传递</h4><h4 id="3-管道">3. 管道</h4><h2 id="二、CPU-调度与上下文切换">二、CPU 调度与上下文切换</h2><h3 id="(一)调度的基本概念">(一)调度的基本概念</h3><h3 id="(二)调度的目标">(二)调度的目标</h3><h3 id="(三)调度的实现">(三)调度的实现</h3><h4 id="1-调度器-调度程序-scheduler">1. 调度器/调度程序(scheduler)</h4><h4 id="2-调度的时机与调度方式">2. 调度的时机与调度方式</h4><p>(抢占式/非抢占式)</p><h4 id="3-闲逛进程">3. 闲逛进程</h4><h4 id="4-内核级线程与用户级线程调度">4. 内核级线程与用户级线程调度</h4><h3 id="(四)典型调度算法">(四)典型调度算法</h3><h4 id="1-先来先服务调度算法">1. 先来先服务调度算法</h4><h4 id="2-短作业(短进程、短线程)优先调度算法">2. 短作业(短进程、短线程)优先调度算法</h4><h4 id="3-时间片轮转调度算法">3. 时间片轮转调度算法</h4><h4 id="4-优先级调度算法">4. 优先级调度算法</h4><h4 id="5-高响应比优先调度算法">5. 高响应比优先调度算法</h4><h4 id="6-多级队列调度算法">6. 多级队列调度算法</h4><h4 id="7-多级反馈队列调度算法。">7. 多级反馈队列调度算法。</h4><h4 id="(五)上下文及其切换机制">(五)上下文及其切换机制</h4><h2 id="三、同步与互斥">三、同步与互斥</h2><h3 id="(一)同步与互斥的基本概念">(一)同步与互斥的基本概念</h3><h3 id="(二)基本的实现方法">(二)基本的实现方法</h3><h4 id="1-软件方法">1. 软件方法</h4><h4 id="2-硬件方法">2. 硬件方法</h4><h3 id="(三)锁">(三)锁</h3><h3 id="(四)信号量">(四)信号量</h3><h3 id="(五)条件变量">(五)条件变量</h3><h3 id="(六)经典同步问题">(六)经典同步问题</h3><h4 id="1-生产者-消费者问题">1. 生产者-消费者问题</h4><h4 id="2-读者-写者问题">2. 读者-写者问题</h4><h4 id="3-哲学家进餐问题">3. 哲学家进餐问题</h4><h2 id="四、死锁">四、死锁</h2><h3 id="(一)死锁的基本概念">(一)死锁的基本概念</h3><h3 id="(二)死锁预防">(二)死锁预防</h3><h3 id="(三)死锁避免">(三)死锁避免</h3><h3 id="(四)死锁检测和解除">(四)死锁检测和解除</h3>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>进程管理</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——数据的表示和运算</title>
<link href="/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E7%9A%84%E8%A1%A8%E7%A4%BA%E5%92%8C%E8%BF%90%E7%AE%97/"/>
<url>/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E7%9A%84%E8%A1%A8%E7%A4%BA%E5%92%8C%E8%BF%90%E7%AE%97/</url>
<content type="html"><![CDATA[<h1>数据的表示和运算</h1><h2 id="一、数制与编码">一、数制与编码</h2><h3 id="(一)定点计数制及其数据之间的相互转换">(一)定点计数制及其数据之间的相互转换</h3><h3 id="(二)定点数的编码表示">(二)定点数的编码表示</h3><h2 id="二、运算方法和运算电路">二、运算方法和运算电路</h2><h3 id="(一)基本运算部件">(一)基本运算部件</h3><h4 id="1-加法器">1. 加法器</h4><h4 id="2-算数逻辑单元-ALU">2. 算数逻辑单元(ALU)</h4><h3 id="(二)加-减运算">(二)加/减运算</h3><h4 id="1-补码加-减运算器">1. 补码加/减运算器</h4><h4 id="2-标志位的生成">2. 标志位的生成</h4><h3 id="(三)乘-除运算">(三)乘/除运算</h3><h4 id="1-乘-除法运算的的基本原理">1. 乘/除法运算的的基本原理</h4><h4 id="2-乘法电路和除法电路的基本结构">2. 乘法电路和除法电路的基本结构</h4><h2 id="三、整数的表示和运算">三、整数的表示和运算</h2><h3 id="(一)无符号整数的表示和运算">(一)无符号整数的表示和运算</h3><h3 id="(二)带符号整数的表示和运算">(二)带符号整数的表示和运算</h3><h2 id="四、浮点数的表示和运算">四、浮点数的表示和运算</h2><h3 id="(一)浮点数的表示">(一)浮点数的表示</h3><p>IEEE 754标准。</p><h3 id="(二)浮点数的加-减运算">(二)浮点数的加/减运算</h3>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>数据的表示和运算</tag>
</tags>
</entry>
<entry>
<title>数据结构——树与二叉树</title>
<link href="/2024/08/19/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%91%E4%B8%8E%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
<url>/2024/08/19/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%91%E4%B8%8E%E4%BA%8C%E5%8F%89%E6%A0%91/</url>
<content type="html"><![CDATA[<h1>树与二叉树</h1><h2 id="一、树的基本概念">一、树的基本概念</h2><h2 id="二、二叉树">二、二叉树</h2><h3 id="(一)二叉树的定义及其主要特征">(一)二叉树的定义及其主要特征</h3><h3 id="(二)二叉树的顺序存储结构和链式存储结构">(二)二叉树的顺序存储结构和链式存储结构</h3><h3 id="(三)二叉树的遍历">(三)二叉树的遍历</h3><h3 id="(四)线索二叉树的基本概念和构造">(四)线索二叉树的基本概念和构造</h3><h2 id="三、树、森林">三、树、森林</h2><h3 id="(一)树的存储结构">(一)树的存储结构</h3><h3 id="(二)森林与二叉树的转换">(二)森林与二叉树的转换</h3><h3 id="(三)树和森林的遍历">(三)树和森林的遍历</h3><h2 id="四、树与二叉树的应用">四、树与二叉树的应用</h2><h3 id="(一)哈夫曼-Huffman-树和哈夫曼编码">(一)哈夫曼(Huffman)树和哈夫曼编码</h3><h3 id="(二)并查集及其应用">(二)并查集及其应用</h3>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>树与二叉树</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——操作系统基础</title>
<link href="/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80/"/>
<url>/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80/</url>
<content type="html"><![CDATA[<h1>操作系统基础</h1><h2 id="一、操作系统的基本概念">一、操作系统的基本概念</h2><p>操作系统(operating system,OS)是配置在计算机硬件上的<strong>第一层软件</strong>,是对硬件系统的首次扩充,其主要作用是管理硬件设备,提高它们的利用率和系统吞吐量,并为用户和应用程序提供一个简单的接口,以便于用户和应用程序使用硬件设备。OS是现代计算机系统中最基本和最重要的<strong>系统软件</strong>,而其他的诸如编译软件、数据库管理软件等系统软件以及大量的应用软件,都直接依赖于OS的支持,并须取得OS所提供的服务。事实上OS已成为现代计算机系统、多处理机系统、计算机网络等都必须配置的系统软件。</p><h3 id="(一)操作系统的目标">(一)操作系统的目标</h3><h4 id="1-方便性">1. 方便性</h4><p>一台配置了操作系统的计算机可以方便的通过操作系统的工具和命令来操作使用计算机,极大方便了用户使用计算机硬件,也使计算机更加易学易用。</p><h4 id="2-有效性">2. 有效性</h4><p>有效性有两层含义,有效性所包含的第一层含义是提高系统资源的利用率。在早期未配置OS的计算机系统中,诸如处理机、输入/输出(input/output,I/O)设备等都经常处于空闲状态,各种资源无法得到充分利用,因此在当时,提高系统资源利用率是推动OS发展最主要的动力。有效性的第二层含义是提高系统的吞吐量。OS可以通过合理地组织计算机的工作流程,加速程序的运行,缩短程序的运行周期来提高系统的吞吐量。</p><p>方便性和有效性是设计OS时最重要的两个目标。在过去很长一段时间内,由于计算机系统非常昂贵,有效性显得特别重要。然而,近十几年来,随着硬件越来越便宜,在设计配置在微机上的OS时,似乎更加重视如何提高用户使用计算机的方便性。因此,在微机操作系统中都配置了深受用户欢迎的图形用户界面,并为程序员提供了大量的系统调用,方便了用户对计算机的使用。</p><h4 id="3-可扩充性">3. 可扩充性</h4><p>为适应计算机硬件、体系结构以及应用发展的要求,OS必须具有很好的可扩充性。可扩充性的好坏与OS的结构有着十分紧密的联系,由此推动了OS结构的不断发展。OS从早期的无结构发展成模块化结构,进而又发展成分层式结构,近年来OS已广泛采用微内核结构。该结构能方便地增添新的功能和模块,以及对原有功能和模块进行修改,具有良好的可扩充性。</p><h4 id="4-开放性">4. 开放性</h4><p>所谓开放性,是指系统能够遵循国际标准,特别是遵循开放系统互连(open system interconnect,OSI)参考模型。事实上,凡遵循国际标准而开发的硬件和软件都能彼此兼容,并方便地实现互连。开放性已成为20世纪90年代以后计算机技术的一个核心问题,也是衡量一个新推出的系统或软件能否被广泛应用的重要因素。</p><h3 id="(二)操作系统的作用">(二)操作系统的作用</h3><h4 id="1-人机交互">1. 人机交互</h4><p>OS作为用户与计算机硬件系统之间的接口,其含义是:OS处于用户与计算机硬件系统之间,用户通过OS来使用计算机硬件系统;或者说,用户在OS的帮助下能够方便、快捷、可靠地操纵计算机硬件和运行自己的程序。通常操作系统提供的人机交互有以下几种方式。</p><ol><li>命令接口:分为联机命令接口与脱机命令接口两种方式,其中联机命令接口又叫交互式命令接口,用户通过终端向操作系统提交命令,执行完成后返回终端控制权等待命令;脱机命令接口又称作批处理命令接口,由一组作业控制命令组成,批量提交给系统并逐条命令解释执行。</li><li>程序接口:程序接口由一组系统调用(广义指令)组成,用户在程序中使用这些系统调用来请求操作系统提供服务,例如用户使用图形用户界面(GUI)方便地使用操作系统。</li></ol><h4 id="2-资源管理">2. 资源管理</h4><p>OS作为计算机系统资源的管理者。在一个计算机系统中,通常含有多种硬件和软件资源。归纳起来可将这些资源分为4类:处理机、存储器、I/O设备以及信息(数据和程序)。相应地,OS的主要功能也正是对这4类资源进行有效的管理。处理机管理负责处理机的分配与控制;存储器管理负责内存的分配与回收;I/O设备管理负责I/O设备的分配(回收)与操纵;文件管理负责文件的存取、共享与保护等。可见,OS的确是计算机系统资源的管理者。</p><p>值得进一步说明的是,当一台计算机系统同时供多个用户使用时,诸多用户对系统中共享资源(包括数量和时间)的需求有可能会发生冲突。为此,OS必须对共享资源的使用请求进行授权,以协调诸多用户对共享资源的使用。</p><h4 id="3-资源抽象(资源扩充)">3. 资源抽象(资源扩充)</h4><p>操作系统(OS)通过对计算机资源的抽象,让用户更容易使用计算机。想象一下,如果你面对的是一台完全没有任何软件的电脑,你需要直接和硬件打交道,比如操作硬盘、内存、I/O设备等等。这需要你对硬件非常了解,操作起来非常复杂。</p><p>为了解决这个问题,人们在裸机上添加了I/O软件,这些软件把硬件设备的复杂操作隐藏起来,提供了一些简单的命令(比如读取或写入命令)供用户使用。这样,用户可以通过这些命令和数据结构来进行操作,而不用关心硬件是如何具体工作的。这个过程就像是给计算机穿上了一层外衣,让它变得更容易使用。</p><p>不仅如此,在I/O软件的基础上,人们还可以继续添加文件管理软件和窗口软件等,这些软件进一步抽象和简化了对硬件的操作。比如,文件管理软件让用户可以轻松地管理文件,而不必担心文件在硬盘上的存储细节;窗口软件则提供了图形界面,让用户可以通过点击图标来操作计算机。</p><p>因此,操作系统实际上是由多层软件组成的,它们通过逐层抽象,把复杂的硬件操作隐藏起来,提供了更强大的功能和更简单的使用方式。最终,用户只需要通过这些简化的接口和命令,就可以方便地使用计算机,而不必了解底层硬件的工作原理。用户最终看到的是功能更强、使用方便的虚机器。</p><h3 id="(三)操作系统的发展动力">(三)操作系统的发展动力</h3><h4 id="1-提高计算机系统资源的利用率">1. 提高计算机系统资源的利用率</h4><p>提升CPU、I/O设备及存储器系统的利用率。</p><h4 id="2-方便用户">2. 方便用户</h4><p>方便人机交互,推进计算机的迅速普及和广泛应用。</p><h4 id="3-器件换代">3. 器件换代</h4><p>适应微机芯片向16位、32位、64为以及多处理机的发展,以及计算机外设类型的增多,操作系统的功能和性能也在逐渐变强。</p><h4 id="4-计算机体系结构的不断发展">4. 计算机体系结构的不断发展</h4><p>多处理机OS与网络OS。</p><h4 id="5-不断提出新的应用需求">5. 不断提出新的应用需求</h4><p>计算机走进各行各业,操作系统随不同应用需求的增加而发展。</p><h3 id="(四)操作系统的基本特性">(四)操作系统的基本特性</h3><p>尽管各种操作系统有着各自不同的特征,但是总体上都具备以下四个基本特性。</p><h4 id="1-并发">1. 并发</h4><p><strong>并发</strong>与<strong>并行</strong>是既相似又有区别的两个概念。并行是指两个或多个事件在同一时刻发生(实际上的同时进行),而并发是指两个或多个事件在同一时间间隔内发生(微观上交替执行,宏观上并行执行)。</p><p>并发是指多个任务(或进程、线程)可以在同一时间段内同时进行。这种并发性并不意味着任务真正同时执行,因为单处理机系统每一时刻仅能有一道程序运行,而操作系统通过时间片轮转等调度机制,让多个任务在微观上交替执行,给用户一种“同时运行”的感觉。并发性提高了资源的利用率,使计算机能够同时处理多个任务,如在一个程序下载文件的同时,另一个程序处理文本。</p><ul><li>进程并发:不同的进程在同一时间段内执行。</li><li>线程并发:同一进程中的多个线程在同一时间段内执行。</li></ul><blockquote><p>在一个未引入进程的系统中,同属于一个应用程序的计算程序和I/O程序只能顺序执行,即只有在计算程序的执行告一段落后才允许I/O程序执行;换言之,在执行I/O程序时,计算程序也不能执行。但在为计算程序和I/O程序分别建立一个进程(process)后,这两个进程便可并发执行。若对内存中的多个程序都分别建立一个进程,则它们就可以并发执行,这样便能极大限度地提高系统资源的利用率,以及增加系统的吞吐量。</p><p>所谓进程,是指在系统中能独立运行并能作为资源分配对象的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。多个进程之间可以并发执行和交换信息。事实上,进程和并发是现代OS中最重要的基本概念,也是OS运行的基础。</p></blockquote><p>操作系统通过进程调度、线程调度等机制来实现并发性,同时避免因资源竞争导致的死锁、竞争条件等问题。倘若在计算机系统中有多个处理机,那么这些能并发执行的程序,便可被分配到<strong>多个处理机</strong>上实现<strong>并行</strong>执行,即利用每个处理机来处理一个可并发执行的程序。这样,多个程序便可同时执行。</p><h4 id="2-共享">2. 共享</h4><p>共享是指计算机系统中的资源可以被多个任务同时使用,这里的资源共享指的是<strong>资源复用</strong>,是指系统中的资源可供内存中多个并发执行的进程共同使用。共享的资源包括CPU、内存、磁盘、I/O设备等。操作系统通过资源管理机制,确保不同任务在使用共享资源时不发生冲突,并且每个任务都能有效地访问资源。共享的主要目标是提高系统资源的利用率,同时保证系统的稳定性和公平性。实现资源共享有以下两种方式:</p><ol><li>互斥共享:某些资源(如打印机)只能在同一时间被一个任务使用,操作系统通过锁机制或信号量机制来实现互斥访问。</li><li>同时共享:某些资源(如硬盘、内存)可以被多个任务同时访问,操作系统通过虚拟化等技术实现了同时共享,并确保任务之间的互不干扰。</li></ol><blockquote><p>并发和共享是多用户(多任务)OS的两个最基本的特征。它们互为对方存在的条件,即一方面,资源共享是以进程的并发执行为条件的,若系统不允许并发执行,也就不存在资源共享问题;另一方面,若系统不能对资源共享实施有效的管理,以协调好各进程对共享资源的访问,则必然会影响各进程间并发执行的程度,甚至会使它们根本无法并发执行。</p></blockquote><h4 id="3-虚拟">3. 虚拟</h4><p><strong>虚拟</strong>是指通过某种技术手段,将物理实体(如处理器、存储器、设备等)转化为若干个逻辑上的对应物,使用户或应用程序能够感知到一个不存在的“虚拟”资源。虚拟化技术通过优化资源的使用方式,提高资源利用率,为多任务处理和用户隔离提供了可能性。</p><p>操作系统中,虚拟技术广泛应用于处理器、内存和I/O设备的管理。它通过时分复用和空分复用,将有限的物理资源转化为多个虚拟资源,从而提高系统的整体性能。</p><h5 id="时分复用技术">时分复用技术</h5><p><strong>时分复用</strong>(Time Division Multiplexing, TDM)是通过在不同时间片内分配资源,实现资源共享的技术。它在操作系统中主要用于虚拟处理器和虚拟设备的实现。</p><ul><li><p><strong>虚拟处理器技术</strong>:在多道程序设计中,操作系统为每个程序建立进程,并通过时分复用技术在处理器上轮流运行这些进程。虽然物理上只有一个处理器,但由于操作系统的快速切换,使得每个用户都感受到自己独占了一个处理器,这就是虚拟处理器的概念。</p></li><li><p><strong>虚拟设备技术</strong>:类似的,时分复用也用于将一个物理设备(如打印机)虚拟成多个逻辑设备。通过为不同用户分配时间片,多个用户可以“同时”使用同一物理设备,感知上好像每个人都有一台专属设备。</p></li></ul><h5 id="空分复用技术">空分复用技术</h5><p><strong>空分复用</strong>(Space Division Multiplexing, SDM)通过在空间上划分资源来实现共享。</p><ul><li><strong>虚拟内存技术</strong>:空分复用在内存管理中的应用尤为显著。通过将物理内存划分为多个虚拟内存页,并利用空闲的内存空间存放其他程序数据,操作系统不仅提高了内存的利用率,还通过虚拟存储技术实现了逻辑上的内存扩展。</li></ul><p>虚拟存储的核心在于分时复用,即通过按需调度程序的不同部分到内存中执行,使得即使物理内存小于程序的需求,程序依然可以顺利运行。举例来说,一个100MB的程序可以在仅有30MB内存的环境中运行,原因是操作系统会根据需要动态调度程序的部分内容进出内存。</p><p>采用虚拟技术,操作系统可以将物理设备“分割”为多个虚拟设备,显著提高了资源的利用率。然而,这也意味着每个虚拟资源的性能通常等于或小于物理资源性能的1/N(N为虚拟设备数量)。例如,虚拟处理器的平均速度会因为时分复用而低于物理处理器的速度。</p><h4 id="4-异步">4. 异步</h4><p>异步是指任务的执行并不是连续的,而是以不确定的速度向前推进的。由于系统资源有限,任务在执行过程中可能会因为等待I/O操作或资源竞争而被挂起,导致执行过程断断续续。</p><ul><li><p>任务的异步性:任务的执行可能会因为系统的调度机制被暂停,等资源可用时再继续执行。</p></li><li><p>事件驱动的异步:操作系统通过事件机制,处理用户输入、I/O操作等外部事件,使得系统能够及时响应这些事件。</p></li></ul><p>异步性保证了系统的灵活性和响应速度,使得操作系统能够在不确定性和复杂性中维持系统的稳定运行。它使得操作系统在处理多任务时能够高效应对各种突发情况和资源调度问题。</p><h2 id="二、操作系统的发展历程">二、操作系统的发展历程</h2><p>另见<a href="https://blog.cxhap.top/2024/07/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%91%E5%B1%95%E5%8E%86%E7%A8%8B/">笔记</a></p><h2 id="三、程序的运行环境">三、程序的运行环境</h2><h3 id="(一)CPU-运行环境">(一)CPU 运行环境</h3><p>内核模式,用户模式。</p><h3 id="(二)中断和异常的处理">(二)中断和异常的处理</h3><h3 id="(三)系统调用">(三)系统调用</h3><h3 id="(四)程序的链接与装入">(四)程序的链接与装入</h3><h3 id="(五)程序运行时的内存映像与地址空间">(五)程序运行时的内存映像与地址空间</h3><h2 id="四、操作系统结构">四、操作系统结构</h2><p>分层,模块化,宏内核,微内核,外核。</p><h2 id="五、操作系统引导">五、操作系统引导</h2><h2 id="六、虚拟机">六、虚拟机</h2>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>操作系统基础</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理——计算机系统概述</title>
<link href="/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%BF%B0/"/>
<url>/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%BF%B0/</url>
<content type="html"><![CDATA[<h1>计算机系统概述</h1><h2 id="一、计算机系统层次结构">一、计算机系统层次结构</h2><h3 id="(一)计算机系统的基本组成">(一)计算机系统的基本组成</h3><h3 id="(二)计算机硬件的基本结构">(二)计算机硬件的基本结构</h3><h3 id="(三)计算机软件和硬件的关系">(三)计算机软件和硬件的关系</h3><h3 id="(四)计算机系统的工作原理">(四)计算机系统的工作原理</h3><p>“存储程序”工作方式,高级语言程序与机器语言程序之间的转换,程序和指令的执行过程。</p><h2 id="二、计算机的性能指标">二、计算机的性能指标</h2><p>吞吐量、响应时间;CPU 时钟周期、主频、CPI、CPU 执行时间;MIPS、 MFLOPS 、GFLOPS、TFLOPS、PFLOPS、EFLOPS、ZFLOPS。</p>]]></content>
<categories>
<category>计算机组成原理</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机组成原理</tag>
<tag>计算机系统概述</tag>
</tags>
</entry>
<entry>
<title>数据结构——栈、队列和数组</title>
<link href="/2024/08/18/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%88%E3%80%81%E9%98%9F%E5%88%97%E5%92%8C%E6%95%B0%E7%BB%84/"/>
<url>/2024/08/18/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%88%E3%80%81%E9%98%9F%E5%88%97%E5%92%8C%E6%95%B0%E7%BB%84/</url>
<content type="html"><![CDATA[<h1>栈、队列和数组</h1><h2 id="一、栈和队列的基本概念">一、栈和队列的基本概念</h2><h2 id="二、栈和队列的顺序存储结构">二、栈和队列的顺序存储结构</h2><h2 id="三、栈和队列的链式存储结构">三、栈和队列的链式存储结构</h2><h2 id="四、多维数组的存储">四、多维数组的存储</h2><h2 id="五、特殊矩阵的压缩存储">五、特殊矩阵的压缩存储</h2><h2 id="六、栈、队列和数组的应用">六、栈、队列和数组的应用</h2>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>栈</tag>
<tag>队列</tag>
<tag>数组</tag>
</tags>
</entry>
<entry>
<title>计算机网络——应用层</title>
<link href="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E5%BA%94%E7%94%A8%E5%B1%82/"/>
<url>/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E5%BA%94%E7%94%A8%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>应用层</h1><h2 id="一、网络应用模型">一、网络应用模型</h2><h3 id="(一)客户-服务端-C-S-模型">(一)客户/服务端(C/S)模型</h3><p>客户/服务器模型中,客户端发送请求到服务器端,服务器处理请求并返回数据给客户端。这种模型通常用于需要集中式管理数据和资源的场景。客户端和服务器通常使用固定的网络协议进行通信,例如HTTP或FTP。</p><h3 id="(二)对等-P2P-模型">(二)对等(P2P)模型</h3><p>在对等网络模型中,每个节点既是客户端也是服务器,能够直接与网络中的其他节点进行数据交换。P2P模型适用于分布式数据共享,如文件共享或分布式计算。它降低了服务器的负载,并可以提供更强的数据容错能力。</p><h2 id="二、DNS系统">二、DNS系统</h2><h3 id="(一)层次域名空间">(一)层次域名空间</h3><p>DNS使用层次化的域名空间结构来管理域名。这一结构从根域名开始,向下分为顶级域名(TLDs),再到二级域名,直至最低级的主机名。例如,在域名“<a href="http://www.example.com">www.example.com</a>”中,“.com”是顶级域名,"example"是二级域名,"www"是主机名。</p><h3 id="(二)域名服务器">(二)域名服务器</h3><p>域名服务器负责存储与域名相关的信息,并解析域名到对应的IP地址。主要有根域名服务器、顶级域名服务器、权威域名服务器和本地域名服务器。</p><h3 id="(三)域名解析过程">(三)域名解析过程</h3><p>域名解析通常开始于本地DNS服务器的查询,如果本地DNS服务器无法解析,则请求被转发到根服务器,然后是顶级域名服务器,最后是权威域名服务器,直到找到相应的IP地址。</p><h2 id="三、FTP">三、FTP</h2><h3 id="(一)FTP协议的工作原理">(一)FTP协议的工作原理</h3><p>FTP(File Transfer Protocol)是一个用于在网络上进行文件传输的标准网络协议。用户通过FTP客户端连接到FTP服务器,进行文件上传或下载。FTP支持匿名访问或经验证的访问。</p><h3 id="(二)控制连接与数据连接">(二)控制连接与数据连接</h3><p>FTP使用两个独立的连接:控制连接和数据连接。控制连接用于传输命令和响应,保持整个会话期间打开。数据连接是临时的,用于传输文件或目录内容。</p><h2 id="四、电子邮件">四、电子邮件</h2><h3 id="(一)电子邮件系统的组成结构">(一)电子邮件系统的组成结构</h3><p>电子邮件系统包括邮件客户端、邮件服务器和邮件协议。用户通过邮件客户端创建、发送和接收邮件。邮件服务器处理邮件的存储和转发。</p><h3 id="(二)电子邮件的结构与MIME">(二)电子邮件的结构与MIME</h3><p>电子邮件基本结构包括头部和正文。头部包含发送者、接收者、主题等信息。MIME(Multipurpose Internet Mail Extensions)扩展了电子邮件标准,支持发送非文本附件如图片、音频和视频文件。</p><h3 id="(三)SMTP协议与POP3协议">(三)SMTP协议与POP3协议</h3><p>SMTP(Simple Mail Transfer Protocol)用于发送邮件,而POP3(Post Office Protocol version 3)用于接收邮件。SMTP服务器处理发送到或从邮箱中的邮件,而POP3服务器允许邮件客户端访问服务器上的邮件。</p><h2 id="五、WWW">五、WWW</h2><h3 id="(一)WWW的概念与组成结构">(一)WWW的概念与组成结构</h3><p>万维网(WWW)是信息和资源的集合,通过互联网访问,基于HTML和HTTP/HTTPS协议。其主要组成包括网页、网站和Web浏览器。</p><h3 id="(二)HTTP协议">(二)HTTP协议</h3><p>HTTP(Hypertext Transfer Protocol)是WWW中使用的主要协议,用于在Web服务器和浏览器之间传输超文本。HTTP定义了客户端(用户代理)发送请求到服务器及服务器返回响应的方式。</p>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>应用层</tag>
</tags>
</entry>
<entry>
<title>计算机网络——传输层</title>
<link href="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E4%BC%A0%E8%BE%93%E5%B1%82/"/>
<url>/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E4%BC%A0%E8%BE%93%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>传输层</h1><h2 id="一、传输层提供的服务">一、传输层提供的服务</h2><h3 id="(一)传输层的功能">(一)传输层的功能</h3><h3 id="(二)传输层寻址与端口">(二)传输层寻址与端口</h3><h3 id="(三)无连接服务与面向连接服务">(三)无连接服务与面向连接服务</h3><h2 id="二、UDP-协议">二、UDP 协议</h2><h3 id="(一)UDP-数据报">(一)UDP 数据报</h3><h3 id="(二)UDP-校验">(二)UDP 校验</h3><h2 id="三、TCP-协议">三、TCP 协议</h2><h3 id="(一)TCP-段">(一)TCP 段</h3><h3 id="(二)TCP-连接管理">(二)TCP 连接管理</h3><h3 id="(三)TCP-可靠传输">(三)TCP 可靠传输</h3><h3 id="(四)TCP-流量控制">(四)TCP 流量控制</h3><h3 id="(五)TCP-拥塞控制">(五)TCP 拥塞控制</h3>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>传输层</tag>
</tags>
</entry>
<entry>
<title>计算机网络——网络层</title>
<link href="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%BD%91%E7%BB%9C%E5%B1%82/"/>
<url>/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%BD%91%E7%BB%9C%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>网络层</h1><h2 id="一、网络层的功能">一、网络层的功能</h2><h3 id="(一)异构网络互连">(一)异构网络互连</h3><h3 id="(二)路由和转发">(二)路由和转发</h3><h3 id="(三)SDN-基本概念">(三)SDN 基本概念</h3><h3 id="(四)阻塞控制">(四)阻塞控制</h3><h2 id="二、路由算法">二、路由算法</h2><h3 id="(一)静态路由与动态路由">(一)静态路由与动态路由</h3><h3 id="(二)距离-向量路由算法">(二)距离-向量路由算法</h3><h3 id="(三)链路状态路由算法">(三)链路状态路由算法</h3><h3 id="(四)层次路由">(四)层次路由</h3><h2 id="三、IPv4">三、IPv4</h2><h3 id="(一)IPv4-分组">(一)IPv4 分组</h3><h3 id="(二)IPv4-地址与-NAT">(二)IPv4 地址与 NAT</h3><h3 id="(三)子网划分、路由聚集、子网掩码与-CIDR">(三)子网划分、路由聚集、子网掩码与 CIDR</h3><h4 id="1-子网划分">1. 子网划分</h4><h4 id="2-路由聚集">2. 路由聚集</h4><h4 id="3-子网掩码">3. 子网掩码</h4><h4 id="4-CIDR">4. CIDR</h4><h3 id="(四)ARP-协议、DHCP-协议与-ICMP-协议">(四)ARP 协议、DHCP 协议与 ICMP 协议</h3><h4 id="1-ARP协议">1.ARP协议</h4><h4 id="2-DHCP协议">2. DHCP协议</h4><h4 id="3-ICMP协议">3. ICMP协议</h4><h2 id="四、IPv6">四、IPv6</h2><h3 id="(一)Ipv6-的主要特点">(一)Ipv6 的主要特点</h3><h3 id="(二)IPv6-地址">(二)IPv6 地址</h3><h2 id="五、路由协议">五、路由协议</h2><h3 id="(一)自治系统">(一)自治系统</h3><h3 id="(二)域内路由与域间路由">(二)域内路由与域间路由</h3><h3 id="(三)RIP-路由协议">(三)RIP 路由协议</h3><h3 id="(四)OSPF-路由协议">(四)OSPF 路由协议</h3><h3 id="(五)BGP-路由协议">(五)BGP 路由协议</h3><h2 id="六、IP组播">六、IP组播</h2><h3 id="(一)组播的概念">(一)组播的概念</h3><h3 id="(二)IP-组播地址">(二)IP 组播地址</h3><h2 id="七、移动-IP">七、移动 IP</h2><h3 id="(一)移动-IP-的概念">(一)移动 IP 的概念</h3><h3 id="(二)移动-IP-的通信过程">(二)移动 IP 的通信过程</h3><h2 id="八、网络层设备">八、网络层设备</h2><h3 id="(一)路由器的组成和功能">(一)路由器的组成和功能</h3><h3 id="(二)路由表与分组转发">(二)路由表与分组转发</h3>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>网络层</tag>
</tags>
</entry>
<entry>
<title>计算机网络——数据链路层</title>
<link href="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/"/>
<url>/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>数据链路层</h1><p>数据链路层属于计算机网络的低层。数据链路层使用的信道主要有以下两种类型:</p><ol><li>点对点信道。这种信道使用一对一的点对点通信方式。PPP协议则是目前使用最广泛的点对点协议。</li><li>广播信道。这种信道使用一对多的广播通信方式,因此过程比较复杂。广播信道上连接的主机很多,因此必须使用专用的共享信道协议来协调这些主机的数据发送。对于采用共享广播信道的有线局域网普遍使用CSMA/CD协议,而无线局域网则使用CSMA/CA协议,将在后文介绍。</li></ol><p>局域网虽然是个网络,但我们并不把局域网放在网络层中讨论。这是因为在网络层要讨论的间题是多个网络互连的间题,是讨论分组怎样从一个网络,通过路由器,转发到另一个网络。在本章中我们研究的是在同一个局域网中,分组怎样从一台主机传送到另一台主机,但并不经过路由器转发。从整个的互联网来看,局域网仍属于数据链路层的范围。</p><p>本章首先介绍点对点信道和在这种信道上最常用的点对点协议PPP。然后再用较大的篇幅讨论共享信道的局域网和有关的协议。</p><p>本章最重要的内容是:</p><ol><li>数据链路层的点对点信道和广播信道的特点,以及这两种信道所使用的协议(PPP协议以及CSMA/CD协议)的特点。</li><li>数据链路层的三个基本问题:封裝成帧,透明传输和差错检测。</li><li>以太网MAC层的硬件地址。</li><li>适配器,转发器,集线器,网桥,以太网交换机的作用以及使用场合。</li></ol><h2 id="一、数据链路层的功能">一、数据链路层的功能</h2><p>数据链路层是五层参考模型中的第二层,位于物理层之上,网络层之下。它在整个网络通信过程中扮演着至关重要的角色,主要负责确保在同一网络内两个相邻节点之间的数据能够可靠地传输。这一层的工作包括管理和控制数据的传输,以防止在传输过程中发生数据丢失、错误或重复,从而为网络层提供高质量的服务。</p><p>为了深入理解数据链路层的功能,我们需要先弄清楚几个核心概念:链路、数据链路和帧。</p><h3 id="链路、数据链路、帧的概念">链路、数据链路、帧的概念</h3><ol><li><p><strong>链路</strong>:<br>链路是指两个直接相连的网络设备(如计算机、交换机等)之间的物理连接介质。链路可以是铜缆、光纤,或者无线电波等传输媒介。链路的作用是提供一个物理通道,使得两个设备能够在其上进行数据传输。</p></li><li><p><strong>数据链路</strong>:<br>数据链路不仅包括物理链路,还涉及在该链路上传输的数据的逻辑控制,也就是通信协议。数据链路定义了如何在物理链路上组织、管理和控制数据的传输。数据链路层的主要任务就是通过这些逻辑控制机制,保证数据在链路上的可靠传输。</p></li><li><p><strong>帧</strong>:<br>数据链路层对等实体之间进行逻辑通信的协议数据单元,帧是数据链路层传输的基本单位。在数据链路层,数据包被封装成帧,以便在网络中传输。每一帧包含了数据本身以及控制信息,如源地址、目的地址、帧序号、校验和等。这些控制信息有助于接收方识别数据、验证数据的完整性,以及在必要时进行错误恢复。</p></li></ol><h3 id="(一)为网络层提供服务">(一)为网络层提供服务</h3><p>数据链路层的一个关键任务是为网络层提供服务。具体来说,数据链路层的服务类型通常分为三种:无确认无连接服务、有确认无连接服务和面向连接的服务。</p><ul><li><p><strong>无确认无连接服务</strong>:这种服务类似于“尽力而为”的传输,数据链路层不提供帧的确认和重传机制。数据帧在传输过程中可能会丢失、重复或出现错误,但数据链路层并不对这些问题进行处理,由高层处理。这种服务通常用于那些对传输可靠性要求不高或者是误码率较低的场合,速度快,但缺乏保障,例如用于以太网。</p></li><li><p><strong>有确认无连接服务</strong>:在这种服务中,数据链路层为每一个帧提供确认机制。当接收方收到帧后,会发送确认信号给发送方。如果发送方未收到确认,将会重传该帧。这种服务适用于需要一定传输可靠性的场合,该服务用于误码率较高的信道,例如无线通信。</p></li><li><p><strong>面向连接的服务</strong>:这种服务在传输前需要建立连接,并在数据传输完成后释放连接。它提供了一种可靠的传输机制,通过流量控制和差错控制,确保数据帧按序到达,并且没有丢失或重复。这种服务适用于需要高度可靠传输的场合,如远程登录或数据库访问。</p></li></ul><blockquote><p>不存在无确认面向连接的服务,因为要建立连接一定要相互确认。</p></blockquote><h3 id="(二)链路管理">(二)链路管理</h3><p>链路管理是数据链路层的重要功能之一。它主要负责在两个相邻节点之间建立、维护和释放链路,以确保数据能够顺利传输。在链路的建立阶段,数据链路层会进行必要的协商,确保链路的配置符合传输需求。在传输过程中,数据链路层通过持续监控链路状态,来维持链路的有效性和可靠性。如果在传输过程中链路发生故障,数据链路层将采取相应措施,如重新建立链路或报告错误。当数据传输完成后,数据链路层负责释放链路资源,确保不会对后续通信产生干扰。这主要用于面向连接的服务。</p><h3 id="(三)封装成帧">(三)封装成帧</h3><p>封装成帧是指在一段数据的前后分别添加首部和尾部,构成帧。封装成帧是数据链路层的核心功能之一,帧是数据链路层的数据传送单元。在数据链路层,来自网络层的数据包被封装成帧,添加了包括源地址、目的地址、帧序号、校验和等控制信息。这些控制信息对数据传输的正确性和有效性至关重要。</p><p>帧的封装过程不仅仅是对数据进行简单的打包,还涉及到数据链路层对数据传输的管理。比如,通过添加帧序号,接收方可以判断帧的顺序,确保数据按序重组;通过校验和,接收方可以验证数据的完整性,发现并纠正传输过程中可能出现的错误。</p><p>下面是一些重要的概念:</p><ul><li><p><strong>帧长</strong>:帧长是指一个帧的总长度,它由数据部分的长度和帧首部与尾部的长度之和构成。帧首部和尾部包含了用于控制和管理数据传输的关键信息,如地址信息、校验码等,因此帧长不仅仅取决于数据的长度,还包括这些控制信息的长度。</p></li><li><p><strong>帧定界</strong>:帧定界指的是通过在帧的首部和尾部添加特定的控制信息来标识帧的边界。这些控制信息使得接收方能够明确区分每个帧的起始和结束位置,确保数据传输的完整性和正确性。</p></li><li><p><strong>帧同步</strong>:帧同步是指接收方能够在接收到的连续二进制比特流中,准确地识别出帧的起始和终止位置。例如,在HDLC(高级数据链路控制)协议中,标志位F(01111110)用于表示帧的开始和结束。在数据传输过程中,一旦检测到标志位F,接收方便认为这是一个帧的开始;当再次检测到标志位F时,则认为这是帧的结束。这种机制确保了接收方能够正确同步并解析收到的数据帧。</p></li><li><p><strong>最大传送单元(MTU)</strong>:最大传送单元(MTU)是指数据链路层中帧的数据部分所允许的最大长度。设定MTU的目的在于平衡数据传输的效率与可靠性。帧长过大会增加传输错误的概率,因为较长的帧在传输过程中更容易受到干扰和错误影响。然而,帧的数据长度过短则会导致传输效率的降低,因为在较小的数据帧中,控制信息占据了相对较大的比例。因此,MTU规定了帧的数据部分的长度上限,以确保在传输过程中既能保持较高的传输效率,又能将错误率控制在合理范围内。</p></li></ul><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/HDLC%E6%A0%87%E5%87%86%E5%B8%A7%E6%A0%BC%E5%BC%8F.png" class="" title="HDLC标准帧格式.png(王道)"><h3 id="(四)透明传输">(四)透明传输</h3><p>在数据传输过程中,数据链路层需要保证帧能够被透明地传输到接收方。这意味着帧在传输过程中,不应受到传输介质的限制,必须能够无损地到达接收方。然而,在某些情况下,帧的数据内容可能会与帧的控制信息(如帧的起始或结束标志01111110)产生冲突,从而导致帧的传输出现问题。</p><p>为了避免这种情况,数据链路层引入了“透明传输”技术。例如,在HDLC(高级数据链路控制)协议中,通过在帧的内容中出现的标志位前插入“转义字符”来解决冲突问题。这种方法确保了接收方能够正确识别帧的边界,并且不会将帧的数据内容误认为是控制信息。因此,透明传输保障不论所传的数据是什么样的比特组合,都能够按原样无差错地在数据链路上进行传输。</p><h3 id="(五)流量控制">(五)流量控制</h3><p>流量控制是数据链路层的一项关键功能,其主要目的是协调发送方和接收方之间的数据传输速率,防止由于发送方传输速度过快而导致接收方的缓冲区溢出,从而造成数据丢失或出错。由于链路两端的节点在工作速率和缓存空间上存在差异,发送方的发送能力可能会超过接收方的接收能力。如果不对发送方的发送速率进行适当的限制,前面尚未接收完毕的帧将会被后续不断发送来的帧“淹没”,导致数据的丢失。因此,流量控制的本质在于通过某种机制限制发送方的发送速率,使其不会超过接收方的接收能力。</p><p>这种流量控制的实现依赖于某种反馈机制,通过该机制,接收方可以通知发送方当前的接收状态。发送方据此决定是否可以继续发送下一帧,或者需要暂时停止发送,等待接收方处理完当前的数据帧后再继续发送。在OSI参考模型中,流量控制的功能位于数据链路层,它主要控制的是相邻节点之间的数据链路上的流量。而在TCP/IP体系结构中,流量控制的功能则被移到了传输层,负责控制从源端到目的端之间的整体流量。两者虽然在控制对象上有所不同,但其核心目标都是确保数据传输的稳定性和可靠性。</p><p>在数据链路层中,常用的流量控制机制包括“停止-等待协议”和“滑动窗口协议”。</p><ul><li><p><strong>停止-等待协议</strong>:这种协议的工作原理非常简单。发送方每发送一个帧后,必须等待接收方的确认信号(ACK),才能继续发送下一个帧。如果发送方没有收到确认,则会重发该帧。尽管这种方法可以有效地防止数据丢失,但由于发送方必须在每次发送后都等待确认,因此传输效率较低,尤其是在高延迟的链路上,等待时间可能会大幅降低整体数据传输速率。</p></li><li><p><strong>滑动窗口协议</strong>:为了提高传输效率,滑动窗口协议允许发送方在未收到确认的情况下连续发送多个帧。发送方维护一个滑动窗口,窗口内的帧可以一次性发送出去,而无需等待每个帧的确认。接收方则通过发送确认帧(ACK)来逐步“滑动”窗口,确认哪些帧已正确接收。滑动窗口的大小决定了发送方可以连续发送的帧的数量,从而在发送效率和可靠性之间取得平衡。该协议大幅提高了数据传输的效率,同时也增强了传输过程中的可靠性。</p></li></ul><p>后面将会详细介绍这些<a href="#%E5%9B%9B%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6%E4%B8%8E%E5%8F%AF%E9%9D%A0%E4%BC%A0%E8%BE%93%E6%9C%BA%E5%88%B6">流量控制与可靠传输机制</a>。</p><h3 id="(六)差错检测">(六)差错检测</h3><p>差错检测是数据链路层的另一项核心功能,旨在确保数据在传输过程中的完整性和准确性。在数据传输的过程中,由于信道噪声、干扰等多种原因,帧可能会发生错误。如果这些错误未能被及时检测并处理,可能会引发严重的通信问题,导致数据的丢失或不正确的处理。</p><p>错误主要分为两类:<strong>位错</strong>和<strong>帧错</strong>。</p><ol><li><p><strong>位错</strong>:位错是指帧中的某些比特在传输过程中发生了错误,导致接收到的比特与发送时的比特不一致。为了检测这些位错误,数据链路层通常使用循环冗余校验(CRC)技术。CRC是一种高效的检错机制,在发送方,数据链路层对帧的数据部分进行CRC运算,生成一个校验和,将其附加在帧的末尾。接收方接收到帧后,使用相同的CRC算法对帧的数据部分重新计算校验和,并与帧中附带的校验和进行比较。如果两者不一致,说明帧在传输过程中发生了位错,接收方可以选择丢弃该帧并请求发送方重传。</p></li><li><p><strong>帧错</strong>:帧错包括帧丢失、帧重复以及帧失序等错误。帧错通常被归类为传输差错。这些问题可能导致接收方无法正确解析收到的数据,影响通信的可靠性。为了解决这些问题,传统的OSI模型中,数据链路层不仅使用CRC来检测位错,还引入了帧编号、确认和重传机制。每个发送的帧都带有一个唯一的编号,接收方在正确接收帧后,向发送方发送确认。如果发送方在一定时间内没有收到确认,则认为帧出现了错误并会重新发送该帧。这种机制确保了帧的可靠传输,尤其是在通信质量较差的网络环境中,如无线网络。</p></li></ol><p>然而,随着有线通信技术的进步,尤其是在通信质量较高的有线链路中,数据链路层的设计理念也发生了变化。在这些环境中,数据链路层通常不再负责帧的确认和重传,而是仅依赖CRC进行差错检测。如果检测到错误,接收方会简单地丢弃该帧,不再尝试重传,确保上层接收到的帧都是没有错误的。这种设计将数据的可靠性交由传输层的协议(如TCP)来处理。传输层通过其自身的确认和重传机制来保证从源端到目的端的数据可靠传输,这样可以简化数据链路层的设计,并提高网络传输的整体效率。</p><h2 id="二、组帧">二、组帧</h2><p>在<a href="#%E4%B8%89%E5%B0%81%E8%A3%85%E6%88%90%E5%B8%A7">封装成帧</a>部分已经介绍了如何将网络层传来的数据包转换为数据链路层的帧格式,其中涉及添加首部和尾部、帧定界、帧同步等步骤。需要注意的是,封装成帧和组帧是两个相关但不同的过程。</p><p><strong>封装成帧</strong>关注的是如何将网络层传来的数据包转换为数据链路层的帧格式。这个过程包括添加帧的首部和尾部、确保帧的定界和同步,以及帧的格式化等。封装成帧的核心任务是将一个完整的网络层数据包包装成数据链路层能够识别和处理的帧。</p><p><strong>组帧</strong>则是在封装成帧的基础上进一步处理帧的生成和管理。组帧主要关注的是如何将原始数据划分为适当大小的数据块,如何对这些数据块进行处理以形成帧,以及如何有效地管理这些帧的发送和接收过程。与封装成帧不同,组帧更多地侧重于数据块的处理和帧的生成策略,这包括数据流的组织、帧之间的顺序控制以及错误控制等。</p><h3 id="(一)透明传输">(一)透明传输</h3><p>透明传输是指在数据链路层实现的一个重要功能,它确保数据可以不受内容限制地在链路上传输。具体来说,透明传输需要解决帧定界符与数据内容之间的冲突问题,以避免帧边界被错误地识别。</p><h4 id="1-字符填充">1. 字符填充</h4><p>在字符填充过程中,如果数据部分包含与帧定界符相同的字符,发送方会在这些字符前插入一个特殊的转义字符,以避免它们被误认为帧定界符。这个转义字符通常是一个预定义的控制字符,例如ASCII码中的<code>ESC</code>字符。</p><p>当接收方收到数据时,它会检查数据流中的每个字符。如果检测到转义字符,接收方会将紧随其后的字符视为数据的一部分,而不会将其误认为帧的定界符。通过这种方式,即使数据中包含与帧定界符相同的字符,也能够确保这些字符被正确处理,不会干扰帧的定界。举例来说,若帧定界符是FLAG字符,且数据部分包含FLAG,发送方会在该<code>FLAG</code>字符前插入一个<code>ESC</code>字符。接收方在遇到<code>ESC</code>字符时,会理解后面的<code>FLAG</code>只是数据而非定界符,从而保证帧的透明传输。</p><h4 id="2-比特填充">2. 比特填充</h4><p>在比特填充中,当数据链路层使用特定的比特序列(例如<code>01111110</code>)作为帧的定界符时,如果数据部分包含了与该定界符相同的比特序列,为避免冲突,发送方会在这个序列中的特定位置插入一个额外的比特。</p><p>具体来说,在数据部分的比特流中,每当发送方检测到连续的五个<code>1</code>时,便会自动插入一个<code>0</code>,以破坏可能形成的定界符序列。这种插入通常称为“零比特填充”。接收方在解析数据时,同样会检查连续的五个<code>1</code>,并在这种情况下自动删除紧随其后的一个<code>0</code>。这样做能够确保即使数据部分包含与定界符相似的比特序列,也不会被误识别为帧的边界。</p><p>例如,如果原始数据包含比特序列<code>01111110</code>,发送方会在检测到连续的<code>11111</code>之后插入一个<code>0</code>,变为<code>011111010</code>。接收方收到该数据时,在发现五个连续的<code>1</code>后,删除紧跟的0,还原出原始的比特序列。这种机制有效避免了数据中的比特序列被误认为定界符,保证了数据链路层的透明传输。</p><h3 id="(二)组帧的方法">(二)组帧的方法</h3><p>组帧是数据链路层中将数据划分为帧并进行传输的重要步骤,确保数据能够正确地从发送方传递到接收方。根据具体需求和通信环境,可以使用多种组帧方法。以下是几种常见的组帧方法的详细描述:</p><h4 id="1-定长帧法">1. 定长帧法</h4><p><strong>定长帧法</strong>是最简单的组帧方法之一。在这种方法中,帧的长度是固定的,每个帧包含一个固定数量的字节。这种方法的优点在于接收方不需要额外的处理步骤即可识别帧的边界,因为帧的长度是预先已知的。</p><ul><li><p><strong>优点</strong>:</p><ul><li>实现简单,易于硬件支持。</li><li>接收方可以轻松地根据固定长度进行帧的分离,无需额外的定界符。</li><li>因为帧的长度固定,计算和处理时间相对较短且稳定。</li></ul></li><li><p><strong>缺点</strong>:</p><ul><li>如果实际数据的长度小于帧的长度,可能会造成帧的浪费,需要填充冗余数据。</li><li>如果数据长度超过帧的长度,则必须将数据拆分到多个帧中,增加了复杂性。</li><li>不适用于数据长度变化较大的场景。</li></ul></li></ul><h4 id="2-字符计数法">2. 字符计数法</h4><p><strong>字符计数法</strong>是在帧的首部添加一个计数字段,用于指示帧中数据部分的字节数。接收方根据这个计数值来确定帧的边界,从而分离出每一个帧。</p><ul><li><p><strong>优点</strong>:</p><ul><li>能够支持变长帧,适应不同长度的数据。</li><li>比定长帧法更灵活,减少了因数据填充带来的空间浪费。</li></ul></li><li><p><strong>缺点</strong>:</p><ul><li>计数字段可能会出错,导致帧定界的错误(例如,由于传输错误导致计数字段被篡改)。</li><li>如果计数字段错误,接收方可能会误判帧的长度,导致数据失真或丢失。</li></ul></li></ul><h4 id="3-字符标志法">3. 字符标志法</h4><p><strong>字符标志法</strong>通过在帧的开始和结束位置插入特定的标志字符来指示帧的边界。通常,ASCII码中的一些特殊字符(如STX表示帧的开始,ETX表示帧的结束)被用作标志字符。</p><ul><li><p><strong>优点</strong>:</p><ul><li>直观简单,容易理解和实现。</li><li>可以支持变长帧,适用于数据长度不固定的场景。</li><li>适用于简单的通信协议和有限的数据环境。</li></ul></li><li><p><strong>缺点</strong>:</p><ul><li>如果数据中包含与标志字符相同的字符,可能会导致帧定界的混淆,需引入字符填充技术。</li><li>帧定界依赖于标志字符,容易受到传输错误或干扰的影响。</li></ul></li></ul><h4 id="4-比特标志法">4. 比特标志法</h4><p><strong>比特标志法</strong>与字符标志法类似,但使用一串特定的比特序列作为帧的定界符。常见的比特标志为01111110,作为帧的起始和结束标志。这种方法常用于高级数据链路控制(HDLC)协议中。</p><ul><li><p><strong>优点</strong>:</p><ul><li>在传输高效的同时提供数据透明性,可以通过比特填充来避免标志比特序列出现在数据中。</li><li>可以处理变长帧,支持灵活的数据传输。</li></ul></li><li><p><strong>缺点</strong>:</p><ul><li>需要额外的处理来实现比特填充和剥离,增加了复杂性。</li><li>如果标志序列受到干扰或传输错误,可能导致帧定界错误。</li></ul></li></ul><h4 id="5-违反编码法">5. 违反编码法</h4><p><strong>违反编码法</strong>利用编码规则的故意破坏来标识帧的边界。在某些编码方法中(例如曼彻斯特编码),正常数据传输遵循特定的编码规则,但在帧的开始和结束处,故意制造不符合编码规则的比特模式,以此来标识帧的边界。</p><ul><li><p><strong>优点</strong>:</p><ul><li>高度可靠,能够在物理层级别上区分帧的开始和结束。</li><li>因为是基于物理层的编码特性,数据链路层处理更为简单直接。</li></ul></li><li><p><strong>缺点</strong>:</p><ul><li>需要特殊的硬件支持来识别和处理编码规则的违反。</li><li>编码规则复杂,且不容易调试和实现。</li><li>只适用于某些特定的物理层和链路层协议,通用性较差。</li></ul></li></ul><h2 id="三、差错控制">三、差错控制</h2><p>现实的通信链路都不会是理想的,在传输过程中总会无法避免的出现差错,如<code>0</code>变成<code>1</code>,<code>1</code>变成<code>0</code>,这就叫做<strong>比特差错</strong>。</p><h3 id="(一)检错编码">(一)检错编码</h3><h3 id="(二)纠错编码">(二)纠错编码</h3><h2 id="四、流量控制与可靠传输机制">四、流量控制与可靠传输机制</h2><h3 id="(一)流量控制、可靠传输与滑动窗口机制">(一)流量控制、可靠传输与滑动窗口机制</h3><h3 id="(二)停止-等待协议">(二)停止 - 等待协议</h3><h3 id="(三)后退N帧协议-GBN">(三)后退N帧协议( GBN )</h3><h3 id="(四)选择重传协议-SR">(四)选择重传协议( SR )</h3><h2 id="五、介质访问控制">五、介质访问控制</h2><h3 id="(一)信道划分">(一)信道划分</h3><blockquote><p>信道复用技术的概念在第8版课本物理层中p56-p61</p></blockquote><h4 id="1-频分多路复用">1. 频分多路复用</h4><h4 id="2-时分多路复用">2. 时分多路复用</h4><h4 id="3-波分多路复用">3. 波分多路复用</h4><h4 id="4-码分多路复用">4. 码分多路复用</h4><h3 id="(二)随机访问">(二)随机访问</h3><h4 id="1-ALOHA-协议">1. ALOHA 协议</h4><h4 id="2-CSMA-协议">2. CSMA 协议</h4><h4 id="3-CSMA-CD-协议">3. CSMA/CD 协议</h4><h4 id="4-CSMA-CA-协议">4. CSMA/CA 协议</h4><h3 id="(三)轮询访问">(三)轮询访问</h3><p>令牌传递协议。</p><h2 id="六、局域网">六、局域网</h2><h3 id="(一)局域网的基本概念与体系结构">(一)局域网的基本概念与体系结构</h3><h3 id="(二)以太网与IEEE-802-3">(二)以太网与IEEE 802.3</h3><h3 id="(三)IEEE-802-11无线局域网">(三)IEEE 802.11无线局域网</h3><h3 id="(四)VLAN-基本概念与基本原理">(四)VLAN 基本概念与基本原理</h3><h2 id="七、广域网">七、广域网</h2><h3 id="(一)广域网的基本概念">(一)广域网的基本概念</h3><h3 id="(二)PPP-协议">(二)PPP 协议</h3><h2 id="八、数据链路层设备">八、数据链路层设备</h2><h3 id="(一)以太网交换机">(一)以太网交换机</h3><h3 id="(二)以太网交换机工作原理">(二)以太网交换机工作原理</h3>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>数据链路层</tag>
</tags>
</entry>
<entry>
<title>计算机网络——物理层</title>
<link href="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/"/>
<url>/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>物理层</h1><blockquote><p>返回<a href="https://blog.cxhap.top/2024/07/11/2024-7-11-2024%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AD%A6%E7%A7%91%E4%B8%93%E4%B8%9A%E5%9F%BA%E7%A1%80-408-%E8%80%83%E8%AF%95%E5%A4%A7%E7%BA%B2/">大纲</a>?</p></blockquote><p>首先要强调指出,物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体。大家知道,现有的计算机网络中的硬件设备和传输媒体的种类非常繁多,而通信手段也有许多不同方式。物理层的作用正是要尽可能地屏敲掉这些传输媒体和道信手段的差异,使物理层上面的数据链路层感觉不到这些差异,这样就可使数据链路层只需要考虑如何完成本层的协议和服务,而不必考虑网络具体的传输媒体和通信手段是什么。用于物理层的协议也常称为物理层规程(procedure)。其实物理层规程就是物理层协议。只是在 “协议” 这个名词出现之前人们就先使用了 “规程” 这一名词。</p><p>可以将物理层的主要任务描述为确定与传输媒体的接口有关的一些特性,即:</p><ol><li>机械特性:指明接口所用接线器的形状和尺寸,引脚数目和排列,固定和锁定装置等。平时常见的各种规格的接插件都有严格的标准化的规定。</li><li>电气特性:指明在接口电缆的各条线上出现的电压的范围。</li><li>功能特性:指明某条线上出现的某一电平的电压的意义。</li><li>过程特性:指明对于不同功能的各种可能事件的出现顺序。</li></ol><p>以上便是物理层接口的特性。</p><p>大家知道,数据在计算机内部多采用并行传输方式。但数据在通信线路(传输媒体)上的传输方式一般都是串行传输(这是出于经济上的考虑),即逐个比特按照时间顺序传输。因此物理层还要完成传输方式的转换。</p><p>具体的物理层协议种类较多。这是因为物理连接的方式很多(例如,可以是点对点的,也可以采用多点连接或广播连接),而传输媒体的种类也非常之多(如架空明线。双绞线,对称电缆,同轴电缆,光缆,以及各种波段的无线信道等)。因此在学习物理层时,应将重点放在掌握基本概念上。</p><h2 id="一、通信基础">一、通信基础</h2><h3 id="(一)信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念">(一)信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念</h3><p>通信的目的是在信源和信宿之间传送<strong>消息(message)</strong>。消息可以是语音、文字、图像、视频等各种信息表现形式,而 <strong>数据(data)</strong> 是承载和传递消息的实体。数据是经过特定方式编码后的信息,通常表现为有意义的符号序列或二进制序列。</p><h4 id="1-数据">1. 数据</h4><p><strong>数据</strong>是用于表示消息的符号序列或比特序列。在计算机网络中,数据通常以二进制的形式表示,即由“0”和“1”组成的比特序列。数据可以表示文字、音频、视频、图像等各种信息。</p><h4 id="2-信号">2. 信号</h4><p><strong>信号(signal)</strong> 是数据的电气或电磁表现形式。信号用于在传输介质上传递数据,根据信号的不同形式,可以将其分为以下两类:</p><ul><li><p><strong>模拟信号(或连续信号)</strong> :信号的参数(如幅度、频率、相位等)的取值是连续的。在模拟信号中,代表信息的物理量在一个范围内可以取任意值。例如,声音在空气中的传播是一种模拟信号。</p></li><li><p><strong>数字信号(或离散信号)</strong> :信号的参数的取值是离散的。在数字信号中,信息用有限的、离散的电平表示,通常是二进制形式(如0和1)。数字信号在现代计算机网络中应用广泛。</p></li></ul><p>此外,根据信号的频谱范围和传输方式,信号可以进一步分为基带信号和宽带信号:</p><ul><li><p><strong>基带信号</strong> 是原始的未经过调制的信号,通常直接表示数据的形式,如计算机输出的二进制数据流直接用不同的电压来表示。基带信号的频率范围从零开始,并且其最高频率通常等于其数据速率。基带信号通常用于短距离的有线传输,例如以太网。</p></li><li><p><strong>宽带信号</strong> 则是经过调制后的信号,频率范围较宽,适合在更高频率上传输数据。宽带信号常用于远距离的有线或无线传输,例如通过调制将基带信号转换为高频信号,以适应长距离传输需求。</p></li></ul><blockquote><p>基带信号使用不同的电压表示数字信号0和1,然后送到数字信道上运输,称为<strong>基带传输</strong>,宽带信号首先将基带信号进行调制,形成频分复用模拟信号,然后送到模拟信道上进行传输,称为<strong>宽带传输</strong>。</p></blockquote><h4 id="3-信道">3. 信道</h4><p><strong>信道(channel)</strong> 是传输信号的介质或路径,一般用来表示向某个方向传送信息的媒体,因此一条通信电路一般包含一条发送信道和一条接收信道。信道按传输介质分类,可以是有线信道(如双绞线、电缆、光纤)或无线信道(如无线电波、微波);按传输信号形式的不同,信道分为传输模拟信号的模拟信道和传输数字信号的数字信道。信道的主要功能是将信号从发送端传递到接收端。在信道上传输信号时,可能会受到噪声、干扰和衰减等影响,导致信号的失真或丢失。</p><p>从通信的双方信息交互的方式来看,可以有以下三种基本方式:</p><ol><li>单向通信:又称为单工通信,即只能有一个方向的通信而没有反方向的交互。无线电广播或有线电广攝以及电视广攝就属于这种类型。</li><li>双向交替通信:又称为半双工通信,即通信的双方都可以发送信息,但不能双方同时发送(当然也就不能同时接收)。这种通信方式是一方发送另一方接收,过一段时间后可以再反过来。</li><li>双向同时通信:又称为全双工通信,即通信的双方可以同时发送和接收信息。单向通信只需要一条信道,而双向交替通信或双向同时通信则都需要两条信道(每个方向各一条),显然,双向同时通信的传输效率最高。</li></ol><blockquote><p>有时人们也常用“单工”这个名词表示“双向交替通信”,如常说的“单工电台”并不是只能进行单向通信。正因为如此,ITU-T才不采用“单工”“半双工”和“全双工”这些容易弄混的术语作为正式的名词。</p></blockquote><blockquote><p>数据传输方式分为串行传输和并行传输。串行传输是指逐比特地按序依次传输,并行传输是指若干比特通过多个通信信道同时传输。<code>串行传输适用于长距离通信,如计算机网络。</code>并行传输适用于近距离通信,常用于计算机内部,如CPU 与主存之间。</p></blockquote><h4 id="4-带宽">4. 带宽</h4><p><strong>带宽(bandwidth)</strong> 通常有两个含义:</p><ol><li>在模拟信号系统中是指信道能够传输的信号频率范围,即最高频率与最低频率只差,通常以赫兹(Hz)为单位表示。</li><li>在通信中,带宽也常用于表示单位时间内传输数据的最大速率,通常以比特每秒(bps或b/s)为单位。带宽越大,信道的传输能力越强,可以传输更高的数据速率。</li></ol><h4 id="5-码元">5. 码元</h4><p><strong>码元(symbol)</strong> 是信号的基本单位,每一个码元代表了若干比特的数据。码元的取值决定了数字信号的具体形式。常见的码元形式包括电压、电流、频率等不同的电气信号。</p><blockquote><p>码元与比特的区别?</p><ul><li><p>码元是用于表示信息的最小单元。在数字通信系统中,码元可以是一个电压水平、一段时间的光脉冲、或者任何能够在通信系统中传输和被接收的信号。</p></li><li><p>比特是信息的最小单位,它只能表示两种状态之一,通常用0和1来表示。一个比特可以看作是一个简单的“开”或“关”状态、一个“是”或“否”的决定、或者是“0”和“1”中的一个。</p></li><li><p>码元和比特是不同的概念,但它们之间有关系。一个码元可以包含一个或多个比特。比如,在一个通信系统中,假设一个码元有4种不同的状态(比如4种不同的电压),那么这些状态可以用2个比特(00、01、10、11)来表示。因此,一个码元可能包含多个比特信息。</p></li><li><p>如果一个码元有n种状态,则其最多可以表示出<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><msub><mi>g</mi><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">log_2(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>位比特数。</p></li></ul></blockquote><h4 id="6-波特">6. 波特</h4><p><strong>波特 (Baud)</strong> 是码元传输速率的单位,表示每秒钟传输的码元数。一个码元可以表示一个或多个比特,因此波特率与数据速率(比特率)密切相关,但两者并不完全相同。波特率仅指每秒钟传输的码元数,而数据速率则考虑了每个码元所表示的比特数。如果一个码元表示多个比特,则数据速率(比特率)会高于波特率。例如,在一个调制方式中,每个码元表示2个比特,那么如果波特率是1000波特,数据速率将是2000 bps。</p><h4 id="7-速率">7. 速率</h4><p><strong>速率 (Rate)</strong> 在通信中通常指<strong>数据速率 (Data Rate)</strong>,即单位时间内传输的数据量。速率通常以比特每秒(bps)为单位表示。数据速率包括两个重要的概念:</p><ul><li><p><strong>码元传输速率 (Symbol Rate)</strong>:也称为波特率,表示每秒钟传输的码元数量,单位为波特(Baud)。码元传输速率决定了信号的基本传输速率,但不直接反映传输的实际信息量。</p></li><li><p><strong>信息传输速率 (Information Rate)</strong>:也称为比特率,表示每秒钟传输的比特数,单位为bps(比特每秒)。信息传输速率考虑了每个码元中携带的比特数,因此比特率通常等于码元传输速率乘以每个码元携带的比特数。信息传输速率直接影响通信的效率和传输质量。</p></li></ul><h4 id="8-信源与信宿">8. 信源与信宿</h4><p><strong>信源(source)</strong> 是产生和发送消息的设备或系统,而 <strong>信宿(destination)</strong> 是接收和处理消息的设备或系统。在一个通信系统中,信源和信宿之间通过信道进行数据传输。信源生成数据并将其转换为信号,通过信道传输到信宿,信宿接收到信号并将其解码还原为原始数据。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E9%80%9A%E4%BF%A1%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9E%8B.png" class="" title="通信系统模型.png(王道)"><h3 id="(二)奈奎斯特定理与香农定理">(二)奈奎斯特定理与香农定理</h3><p>奈氏准则和香农公式的意义是不同的,奈氏准则激励工程人员不断探索更加先进的编码技术,使每一个码元携带更多比特的信息量。香农公式则告诚工程人员,在有噪声的实际信道上,不论采用多么复杂的编码技术,都不可能突破信息传输速率的绝对极限。</p><h4 id="1-奈奎斯特定理">1. 奈奎斯特定理</h4><p>奈奎斯特定理在1924年由奈奎斯特提出,又成奈氏准则。奈氏准则给出了理想条件下码元传输速率的上限值,即:</p><p>在带宽为W(z)的低通信道中,若不考虑噪声影响,则码元传输的最高速率是2W(码元/秒)。传输速率超过此上限,就会出现严重的码间串扰的问题,使接收端对码元的判决(即识别)成为不可能。</p><h4 id="2-香农定理">2. 香农定理</h4><p>实际的信道都是有噪声的,因此奈氏准则始终是理想情况,1948年香农推导出的香农准则则更好的刻画出了真实情况下的信道极限信息传输速率。香农公式指出:</p><p>信道的极限信息传输速率C是</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>C</mi><mo>=</mo><mi>W</mi><mo>∗</mo><mi>l</mi><mi>o</mi><msub><mi>g</mi><mn>2</mn></msub><mo stretchy="false">(</mo><mn>1</mn><mo>+</mo><mi>S</mi><mi mathvariant="normal">/</mi><mi>N</mi><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mi>b</mi><mi>i</mi><mi>t</mi><mi mathvariant="normal">/</mi><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">C = W*log_2(1+S/N)(bit/s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord mathnormal">bi</span><span class="mord mathnormal">t</span><span class="mord">/</span><span class="mord mathnormal">s</span><span class="mclose">)</span></span></span></span></span></p><p>式中,W为信道的帶宽(以Hz为单位),S为信道内所传信号的平均功率,N为信道内部的高斯噪声功率。</p><p>香农公式表明,信道的带宽或信道中的信噪比越大,信息的极限传输速率就越高。香农公式指出了信息传输速率的上限。香农公式的意义在于:只要信息传输速率低于信道的极限信息传输速率,就一定存在某种办法来实现无差错的传输。</p><blockquote><p>信噪比</p><p>噪声存在于所有的电子设备和通信信道中。由于噪声是随机产生的,它的瞬时值有时会很大,因此噪声会使接收端对码元的判決产生错误(1误判为0或0误判为1)。但噪声的影响是相对的。如果信号相对较强,那么噪声的影响就相对较小,因此,信噪比就很重要。所谓信噪比就是信号的平均功率和噪声的平均功率之比,常记为S/N。但通常大家都是使用分贝(dB)作为度量单位。即</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>10</mn><mo>∗</mo><mi>l</mi><mi>o</mi><msub><mi>g</mi><mn>1</mn></msub><mn>0</mn><mo stretchy="false">(</mo><mi>S</mi><mi mathvariant="normal">/</mi><mi>N</mi><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mi>d</mi><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">10*log_10(S/N) (dB)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord">0</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></p><p>例如,当S/N=10时,信噪比等于10dB,当S/N=1000时,信噪比为30dB。</p></blockquote><h3 id="(三)编码与调制">(三)编码与调制</h3><blockquote><p>建议参考<a href="https://www.bilibili.com/video/BV1c4411d7jb?p=17&vd_source=7dc2d8cc8f3730d0c9e372b2b2a8bff2">湖科大教书匠计算机网络微课堂</a></p></blockquote><p>在通信系统中,数据可以分为模拟数据和数字数据。信号是数据的具体表现形式,它可以是模拟信号,也可以是数字信号。将数据转换为模拟信号的过程称为<strong>调制</strong>,将数据转换为数字信号的过程称为编码。</p><p>数字数据可通过数字发送器转换为数字信号传输,也可通过调制器转换成模拟信号传输;同样,模拟数据可通过PCM编码器转换成数字信号传输,也可通过放大器调制器转换成模拟信号传输。这样,就形成了如下4种编码与调制方式。</p><h4 id="1-模拟数据的模拟调制">1. 模拟数据的模拟调制</h4><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E6%A8%A1%E6%8B%9F%E4%BF%A1%E5%8F%B7%E7%9A%84%E6%A8%A1%E6%8B%9F%E8%B0%83%E5%88%B6.gif" class="" title="模拟信号的模拟调制.gif(维基百科)"><p>模拟数据的模拟调制是指将模拟数据通过调制器转换为模拟信号进行传输的过程。由于输入的数据本身是模拟形式的,因此在调制过程中,常采用以下几种常见的调制方式:</p><ol><li><p><strong>幅度调制(Amplitude Modulation, AM)</strong><br>幅度调制通过改变载波信号的幅度来传输信息,信号的振幅根据输入的模拟数据而变化,而载波信号的频率和相位保持不变。AM 调制方式简单,主要用于广播电台的无线电波传输。</p></li><li><p><strong>频率调制(Frequency Modulation, FM)</strong><br>频率调制通过改变载波信号的频率来传递信息,信号的频率根据输入的模拟数据而变化,而载波信号的幅度和相位保持不变。FM 调制具有抗干扰能力强、传输效果好等优点,常用于调频广播、电视音频信号传输等场合。</p></li><li><p><strong>相位调制(Phase Modulation, PM)</strong><br>相位调制通过改变载波信号的相位来传递信息,信号的相位根据输入的模拟数据而变化,而载波信号的幅度和频率保持不变。PM 调制相对较为复杂,应用范围有限,但在某些特定通信系统中具有重要作用。</p></li></ol><p>模拟数据的模拟调制已经具有广泛的应用,例如:</p><ul><li><strong>广播</strong>:AM 和 FM 是广播中最常见的调制方式,AM 适合远距离传输,而 FM 提供更好的音质。</li><li><strong>电视</strong>:传统电视信号的音频部分采用 FM 调制,视频部分则使用其他调制方式。</li><li><strong>卫星通信</strong>:在某些卫星通信系统中,模拟数据的模拟调制仍然被使用,尤其是在需要大范围覆盖的情况下。</li></ul><p>这种方式的优点是技术相对成熟,实现简单,但缺点是信号容易受噪声影响,尤其是在幅度调制中,信号衰减和干扰会明显影响接收质量。</p><h4 id="2-模拟数据的数字编码">2. 模拟数据的数字编码</h4><p><strong>模拟数据的数字编码</strong> 是将模拟数据转换为数字信号的过程。这一过程通常包括采样、量化和编码三个步骤,常用于对音频信号进行编码的PCM编码。</p><ol><li><strong>采样 (Sampling)</strong>:对模拟信号在时间轴上进行定时采样,将连续的模拟信号离散化为一系列时间点的信号值。</li><li><strong>量化 (Quantization)</strong>:将采样得到的离散电平幅值按照一定的分级标度转换为对应的数值并取整,这样就将连续的电平幅值转换为离散的数字量。采样和量化的实质就是分割和转换。</li><li><strong>编码 (Encoding)</strong>:将量化后的信号值转换为数字码字,通常是二进制码。这种数字码字可以用来表示原始的模拟数据。</li></ol><p>采样定理(奈奎斯特定理):在将模拟信号转换成数字信号时,假设原始信号中的最大频率为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi></mrow><annotation encoding="application/x-tex">f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span></span></span></span>,那么采样率必须大于或等于最大频率<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi></mrow><annotation encoding="application/x-tex">f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span></span></span></span>的2倍,才能保证采样后的数字信号完整保留原模拟信号的信息 。</p><p>数字编码后的信号可以传输在数字信道中,常见的应用场景包括音频信号的数字化(如PCM)和图像信号的数字化。</p><h4 id="3-数字数据的模拟调制">3. 数字数据的模拟调制</h4><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E6%95%B0%E5%AD%97%E4%BF%A1%E5%8F%B7%E7%9A%84%E6%A8%A1%E6%8B%9F%E8%B0%83%E5%88%B6%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" class="" title="数字信号的模拟调制示意图.jpg(课本)"><p><strong>数字数据的模拟调制</strong> 是将数字数据转换为模拟信号的过程,常用于将数字数据传输在模拟信道中。常见的调制方式有:</p><ul><li><p><strong>ASK (Amplitude Shift Keying, 幅移键控)</strong>:也叫调幅(AM),通过改变载波的幅度来表示数字数据。常见的二进制ASK中,0和1分别对应两种不同的载波幅度。<strong>这种方式抗干扰能力较差</strong>。</p></li><li><p><strong>FSK (Frequency Shift Keying, 频移键控)</strong>:也叫调频(FM),通过改变载波的频率来表示数字数据。常见的二进制FSK中,0和1分别对应两种不同的载波频率。这种方式容易实现,抗干扰能力强,应用广泛。</p></li><li><p><strong>PSK (Phase Shift Keying, 相移键控)</strong>:也叫调相(PM),通过改变载波的相位来表示数字数据。常见的二进制PSK中,0和1分别对应两种不同的载波相位。</p></li></ul><blockquote><p>PSK(相移键控)是一种通过改变载波相位来表示数字数据的调制方式。常见的二进制PSK(BPSK)中,数字信号“0”和“1”分别对应两种不同的载波相位。PSK 是一种广泛使用的数字调制技术,具有抗干扰能力强、频谱利用率高等优点。其分为绝对调相(Absolute Phase Shift Keying)和相对调相(Differential Phase Shift Keying, DPSK)两种形式。</p><p>绝对调相是 PSK 的一种形式,其中载波的相位直接与数字数据的状态关联。在二进制 PSK (BPSK) 中,这通常意味着“0”和“1”分别对应于载波的两个固定相位(例如,0 度和 180 度)。每次调制时,载波的相位都会根据当前的数字数据位切换到相应的固定相位。绝对调相的特点是相位变化直接对应数据位的值,因此解调器通过检测当前载波的绝对相位即可恢复原始数据。绝对调相由于其实现简单、易于理解的特点,常用于一些基本的通信系统中,如无线电通信和低速数据传输。</p><p>相对调相(也称为差分相移键控,DPSK)是 PSK 的另一种形式,其中数字数据通过载波相位的变化相对于前一比特的相位进行编码。换句话说,当前的数字数据位“0”或“1”决定了载波相位相对于上一比特相位的增量。这样,相位的变化而非绝对相位用于表示数据。</p><ul><li><strong>DPSK示例</strong>:<ul><li>“0”表示载波相位与上一比特相位相同。</li><li>“1”表示载波相位相对于上一比特相位变化 180 度。</li></ul></li></ul><p>相对调相的优势在于,在接收端不需要同步载波,因为解调只需要检测相邻比特之间的相位差异,而不是绝对相位。相对调相更适用于环境噪声较大的场合或移动通信中。DPSK 常用于无线通信和卫星通信中,特别是在信道容易受到多径效应和相位抖动影响的场景下。</p></blockquote><ul><li><strong>QAM (Quadrature Amplitude Modulation, 正交幅度调制)</strong>:通过同时改变载波的幅度和相位来表示数字数据。QAM结合了ASK和PSK的特点,具有更高的频谱效率,常用于现代通信系统,如无线通信和有线调制解调器。</li></ul><blockquote><p>设波特率为B,采用m个相位,每个相位有n种振幅,则该QAM的数据传输速率R为</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>R</mi><mo>=</mo><mi>B</mi><mo>∗</mo><mi>l</mi><mi>o</mi><msub><mi>g</mi><mn>2</mn></msub><mo stretchy="false">(</mo><mi>m</mi><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">R=B*log_2(mn)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">mn</span><span class="mclose">)</span></span></span></span></span></p></blockquote><p>这些调制方式广泛应用于将数字数据传输在模拟信道中,适应各种无线和有线传输环境。</p><h4 id="4-数字数据的数字编码">4. 数字数据的数字编码</h4><p><strong>数字数据的数字编码</strong> 是指将数字数据转换为另一种形式的数字信号,通常为了适应传输信道的要求或提高传输效率。常见的编码方式有以下几种,如图:</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E6%95%B0%E5%AD%97%E6%95%B0%E6%8D%AE%E7%BC%96%E7%A0%81%E6%96%B9%E5%BC%8F.png" class="" title="数字数据编码方式.png(王道)"><h5 id="1-归零编码-Return-to-Zero-RZ">(1)归零编码 (Return to Zero, RZ)</h5><p>归零编码是一种信号编码方式,在每个比特周期内信号都会返回到零电平(归零)。在 RZ 编码中,每个比特周期分为两个部分:</p><ul><li><strong>高电平</strong>:表示“1”时,信号在比特周期的前半部分为高电平,后半部分返回到零电平。</li><li><strong>低电平</strong>:表示“0”时,信号在比特周期的前半部分为低电平,后半部分返回到零电平。</li></ul><p>RZ 编码的优点包括:</p><ul><li><strong>同步性强</strong>:由于信号在每个比特周期内都会返回到零电平,接收器能够通过检测信号的回归位置实现自同步。</li><li><strong>直流分量低</strong>:信号在每个比特周期内返回零电平,减少了直流分量的出现。</li></ul><p>缺点:</p><ul><li><strong>带宽占用高</strong>:由于信号频繁变化,带宽需求较高。</li></ul><h5 id="2-非归零编码-Non-Return-to-Zero-NRZ">(2)非归零编码 (Non-Return to Zero, NRZ)</h5><p>非归零编码是一种简单的数字编码方式,其中数字数据直接映射为高低电平,而没有中间的归零状态,因此NRZ编码的收发双方存在同步问题,为此需要双方都带有时钟同步线。NRZ 信号在比特周期内保持恒定电平,表示“1”和“0”时,信号分别为高电平和低电平。</p><ul><li><strong>NRZ-L(NRZ-Level)</strong>:最常见的 NRZ 编码方式,“1” 对应高电平,“0” 对应低电平。</li><li><strong>NRZ-I(NRZ-Inverted)</strong>:表示“1”时信号电平发生变化,表示“0”时信号电平保持不变。</li></ul><p>优点:</p><ul><li><strong>带宽效率高</strong>:由于信号不需要频繁变化,带宽利用效率较高。</li></ul><p>缺点:</p><ul><li><strong>同步性差</strong>:长时间的连续“1”或“0”可能导致接收器失去同步。</li><li><strong>直流分量大</strong>:连续的“1”或“0”可能导致较大的直流分量。</li></ul><h5 id="3-反向非归零编码-NRZI-Non-Return-to-Zero-Inverted">(3)反向非归零编码 (NRZI, Non-Return to Zero Inverted)</h5><p>反向非归零编码(NRZI)是一种通过电平变化而非绝对电平来表示数据位的编码方式。它是对传统 NRZ 编码的一种改进,旨在增强信号的同步性和抗干扰性。NRZI 编码的关键特征在于它并不直接用高低电平表示“1”或“0”,而是通过电平是否翻转来表示比特值。</p><h6 id="编码规则">编码规则</h6><ul><li><strong>表示“1”</strong>:在 NRZI 编码中,数据位“1”表示信号电平在当前比特周期的起始位置发生翻转(即从高电平变为低电平,或从低电平变为高电平)。</li><li><strong>表示“0”</strong>:数据位“0”表示信号电平在当前比特周期的起始位置保持不变(即电平与前一个比特周期的结束电平相同)。</li></ul><h6 id="示例">示例</h6><p>假设初始状态为低电平(0),对于比特序列 <code>10110</code> 的 NRZI 编码过程如下:</p><ol><li><strong>初始状态:低电平 (0)</strong></li><li><strong>第一个比特 (1)</strong>:电平翻转 → 高电平 (1)</li><li><strong>第二个比特 (0)</strong>:电平保持不变 → 高电平 (1)</li><li><strong>第三个比特 (1)</strong>:电平翻转 → 低电平 (0)</li><li><strong>第四个比特 (1)</strong>:电平翻转 → 高电平 (1)</li><li><strong>第五个比特 (0)</strong>:电平保持不变 → 高电平 (1)</li></ol><p>结果的 NRZI 信号为:<code>1 1 0 1 1</code>(电平变化表示的信号)</p><h6 id="优点">优点</h6><ul><li><strong>提高同步性</strong>:由于“1”会引起电平变化,即使是长时间的连续“0”也不会导致同步丢失。接收器可以通过检测信号的变化来保持同步。</li><li><strong>抗干扰能力强</strong>:电平变化比绝对电平更容易在噪声环境中识别,从而增强了抗干扰能力。</li></ul><h6 id="缺点">缺点</h6><ul><li><strong>复杂性略高</strong>:与传统的 NRZ 编码相比,NRZI 编码和解码的过程稍微复杂,因为它依赖于前一个比特的电平状态。</li><li><strong>依赖初始状态</strong>:NRZI 编码的结果取决于初始电平状态,因此初始电平的选择可能影响整个序列的编码。</li></ul><h6 id="应用场景">应用场景</h6><p>NRZI 编码广泛应用于需要高可靠性和抗干扰能力的通信系统中。它常见于磁带存储、光纤通信和 USB 协议等场景。NRZI 编码特别适合那些信号恢复难度较大的环境,因为它可以通过电平变化简化信号的检测和恢复过程。</p><h5 id="4-曼彻斯特编码-Manchester-Encoding">(4)曼彻斯特编码 (Manchester Encoding)</h5><p>曼彻斯特编码是一种自同步的数字信号编码技术,广泛应用于通信系统中,尤其是在以太网标准中。曼彻斯特编码通过在每个比特周期内产生一次电平跳变,利用跳变的位置来表示比特值。由于每个比特周期内都有一个电平变化,这种编码方式能够提供强大的自同步能力,并且不会产生直流分量。</p><h6 id="编码原理">编码原理</h6><p>曼彻斯特编码通过以下方式来表示数字数据:</p><ul><li><strong>表示“1”</strong>:在比特周期的中间位置,信号从低电平跳变到高电平。这意味着,在一个完整的比特周期内,前半周期是低电平,后半周期是高电平。</li><li><strong>表示“0”</strong>:在比特周期的中间位置,信号从高电平跳变到低电平。在一个完整的比特周期内,前半周期是高电平,后半周期是低电平。</li></ul><h6 id="编码示例">编码示例</h6><p>假设一个比特序列 <code>101</code> 的曼彻斯特编码过程如下:</p><ul><li><strong>比特“1”</strong>:前半周期为低电平 (0),后半周期跳变为高电平 (1),结果为 <code>↓↑</code>。</li><li><strong>比特“0”</strong>:前半周期为高电平 (1),后半周期跳变为低电平 (0),结果为 <code>↑↓</code>。</li><li><strong>比特“1”</strong>:前半周期为低电平 (0),后半周期跳变为高电平 (1),结果为 <code>↓↑</code>。</li></ul><p>输出信号:<code>↓↑ ↑↓ ↓↑</code></p><h6 id="优点-2">优点</h6><ul><li><strong>自同步能力</strong>:由于每个比特周期内都会发生一次跳变,接收器可以通过检测跳变位置来保持与发送器的同步。这种自同步特性使得曼彻斯特编码在不需要额外的同步信号的情况下,也能实现精确的数据传输。</li><li><strong>无直流分量</strong>:每个比特周期内都包含高电平和低电平,信号的平均电平接近于零,这消除了直流分量的产生。无直流分量的特性使得曼彻斯特编码在长距离传输中更加稳定。</li></ul><h6 id="缺点-2">缺点</h6><ul><li><strong>带宽需求高</strong>:由于曼彻斯特编码每个比特周期内有两次电平变化,实际传输的波形频率是原始数据速率的两倍。这意味着相比于其他编码方式,曼彻斯特编码需要更高的带宽来传输相同的数据量。</li></ul><h5 id="5-差分曼彻斯特编码-Differential-Manchester-Encoding">(5)差分曼彻斯特编码 (Differential Manchester Encoding)</h5><p>差分曼彻斯特编码是一种基于曼彻斯特编码的变体,进一步增强了抗干扰能力和同步性。与曼彻斯特编码不同的是,差分曼彻斯特编码并不直接通过电平高低来表示数据位,而是通过相邻比特周期内的电平变化方向来编码数据。这种编码方式在信道质量较差或容易受到干扰的通信环境中表现出色。</p><h6 id="编码原理-2">编码原理</h6><p>差分曼彻斯特编码的编码规则如下:</p><ul><li><strong>跳变位置</strong>:每个比特周期的中间位置总是发生一次跳变,确保信号的自同步能力。</li><li><strong>表示“1”</strong>:如果当前比特是“1”,信号在比特周期的起始位置不发生电平翻转,即电平保持与上一个比特周期的结束电平相同。</li><li><strong>表示“0”</strong>:如果当前比特是“0”,信号在比特周期的起始位置发生电平翻转,即电平与上一个比特周期的结束电平相反。</li></ul><h6 id="编码示例-2">编码示例</h6><p>假设初始状态为低电平 (0),比特序列 <code>101</code> 的差分曼彻斯特编码过程如下:</p><ul><li><strong>比特“1”</strong>:起始位置与前一个比特周期结束位置相同,不翻转电平;中间位置跳变 → <code>1 0</code>。</li><li><strong>比特“0”</strong>:起始位置与前一个比特周期结束位置相反,翻转电平;中间位置跳变 → <code>0 1</code>。</li><li><strong>比特“1”</strong>:起始位置与前一个比特周期结束位置相同,不翻转电平;中间位置跳变 → <code>1 0</code>。</li></ul><p>输出信号:<code>1 0, 0 1, 1 0</code></p><h6 id="优点-3">优点</h6><ul><li><strong>抗干扰能力强</strong>:由于编码依赖于相邻比特周期间的电平变化,而非绝对电平,差分曼彻斯特编码在噪声较大的环境中更具优势。如果传输过程中发生了电平反转错误,影响仅限于当前比特,不会扩散到后续比特。</li><li><strong>自同步能力</strong>:与曼彻斯特编码类似,差分曼彻斯特编码在每个比特周期中都有一次跳变,这种特性保证了信号的自同步能力。</li></ul><h6 id="缺点-3">缺点</h6><ul><li><strong>带宽需求高</strong>:差分曼彻斯特编码与曼彻斯特编码一样,实际传输的频率是原始数据速率的两倍,因此需要较高的带宽来传输相同的数据量。</li></ul><p>这些数字编码方式广泛应用于数字通信系统中,以确保信号在传输过程中的稳定性和可靠性。</p><h3 id="(四)电路交换、报文交换与分组交换">(四)电路交换、报文交换与分组交换</h3><p>另见<a href="https://blog.cxhap.top/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/#%EF%BC%88%E4%BA%94%EF%BC%89%E7%94%B5%E8%B7%AF%E4%BA%A4%E6%8D%A2%E3%80%81%E6%8A%A5%E6%96%87%E4%BA%A4%E6%8D%A2%E3%80%81%E5%88%86%E7%BB%84%E4%BA%A4%E6%8D%A2">此文</a></p><h3 id="(五)数据报与虚电报">(五)数据报与虚电报</h3><p>另见<a href="">此文</a></p><h2 id="二、传输介质">二、传输介质</h2><p>传输媒体也称为传输介质或传输媒介,它就是数据传输系统中在发送器和接收器之间的物理通路。传输媒体可分为两大类,即<strong>导引型传输媒体</strong>和<strong>非导引型传输媒体</strong> (这里的 “导引型” 的英文就是 guided,也可译为 “导向传输媒体”),在导引型传输媒体中,电磁波被导引沿着固体媒体(铜线或光纤)传播:而非导引型传输媒体就是指自由空间,在非导引型传输媒体中电磁波的传输常称为无线传输。</p><blockquote><p>参考课本p48-p55</p></blockquote><h3 id="(一)双绞线、同轴电缆、光纤与无线传输介质">(一)双绞线、同轴电缆、光纤与无线传输介质</h3><h4 id="1-双绞线">1. 双绞线</h4><p>双绞线也称为双扭线,是最古老但又是最常用的传输媒体。把两根互相绝缘的铜导线并排放在一起,然后用规则的方法绞合(twist)起来就构成了双绞线。绞合可减少对相邻导线的电磁干扰。使用双绞线最多的地方就是到处都有的电话系统。几乎所有的电话都用双绞线连接到电话交换机。这段从用户电话机到交换机的双绞线称为用户线或用户环路(subscriber loop)。通常将一定数量的这种双绞线捆成电缆,在其外面包上护套。现在的以太网(主流的计算机局域网)基本上也是使用各种类型的双绞线电缆进行连接的。</p><p>在电话系统中使用的双绞线,其通信距离一般为几公里。如果使用较粗的导线,则传输距离也可以达到十儿公里。距离太长时就要加放大器以便将衰減了的信号放大到合适的数值 (对于模拟传输),或者加上中继器以便对失真了的数字信号进行整形 (对于数字传输)。导线越粗,其通信距离就越远,但价格也越高。</p><p>当局域网问世后,人们就研究怎样把原来用于传送话音信号的双绞线用来传送计算机网络中的高速数据。在传送高速数据的情況下,为了提高双绞线抗电磁干扰的能力以及减少电缆内不同双绞线对之间的串扰,可以采用增加双绞线的绞合度以及增加电磁屏藏的方法于是在市场上就陆续出现了多种不同类型的双绞线,可以使用在各种不同的情况。</p><p>无屏蔽双绞线UTP(Unshielded Twisted Pair)(如图 2-6(a)所示)的价格较便宜。当数据的传送速率增高时,可以采用屏蔽双绞线(Shielded Twisted Pair,简称为 STP)。如果是对整条双绞线电缆进行屏蔽,则标记为x/UTP。若x为F(Foiled),则表明采用铝箔屏蔽层(图 2-6(b)); 若x为S(braid Screen),则表明采用金属编织层进行屏蔽(这种电缆的弹性较好,便于弯曲,通常使用铜编织层):若x为SF,则表明在铝箔屏蔽层外面再加上金属编织层进行屏蔽。更好的办法是给电缆中的每一对双绞线都加上铝箔屏蔽层(记为FTP或U/FTP,U表明对整条电缆不另增加屏蔽层)。如果在此基础上再对整条电缆添加屏蔽层,则有F/FTP(整条电缆再加上铝箔屏蔽层)或S/FTP(整条电缆再加上金属编织层进行屏蔽)。所有的屏敵双绞线都必须有接地线。图2-6©表示5类线具有比3类线更高的绞合度(3类线的绞合长度是7.5~10 cm,而5类线的绞合长度则是0.6~0.85 cm)。绞合度越高的双绞线能够用越高的数据率传送数据。图2-6(d)所示的是三种10GBASE-T电缆,在抗干扰能力上,UFTP比F/UTP好,而F/FTP则是最好的。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%8F%8C%E7%BB%9E%E7%BA%BF.jpg" class="" title="双绞线.jpg(课本)"><p>表:常用的绞合线的类型、带宽和典型应用</p><table><thead><tr><th>绞合线类别</th><th>带宽</th><th>线缆特点</th><th>典型应用</th></tr></thead><tbody><tr><td>3</td><td>16 MHz</td><td>2对4芯双绞线</td><td>模拟电话;传统以太网(10 Mbit/s)</td></tr><tr><td>5</td><td>100 MHz</td><td>与3类相比增加了绞合度</td><td>传输速率100 Mbit/s(距离100m)</td></tr><tr><td>5E(超五类)</td><td>125 MHz</td><td>与5类相比衰减更小</td><td>传输速率1 Gbit/s(距离100m)</td></tr><tr><td>6</td><td>250 MHz</td><td>改善了串扰等性能,可使用屏蔽双绞线</td><td>传输速率10 Gbit/s(距离35-55m)</td></tr><tr><td>6A</td><td>500 MHz</td><td>改善了串扰等性能,可使用屏蔽双绞线</td><td>传输速率10 Gbit/s(距离100m)</td></tr><tr><td>7</td><td>600 MHz</td><td>必须使用屏蔽双绞线</td><td>传输速率超过10 Gbit/s(距离100m)</td></tr><tr><td>8</td><td>2000 MHz</td><td>必须使用屏蔽双绞线</td><td>传输速率25 Gbit/s或40Gbit/s,(距离30m)</td></tr></tbody></table><p>无论是哪种类别的双绞线,衰减都随频率的升高而增大。使用更粗的导线可以减小衰减,但却增加了导线的重量和价格。信号应当有足够大的振幅,以便在噪声干扰下能够在接收端正确地被检测出来。双绞线的最高速率还与数字信号的编码方法有很大的关系。</p><h4 id="2-同轴电缆">2. 同轴电缆</h4><p>同轴电缆由内导体铜质芯线(单股实心线或多股绞合线)、绝缘层、网状编织的外导体屏蔽层(也可以是单股的)以及绝缘保护套层所组成(如图2-7所示)。由于外导体屏蔽层的作用,同轴电缆具有很好的抗干扰特性,被广泛用于传输较高速率的数据。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%90%8C%E8%BD%B4%E7%94%B5%E7%BC%86.jpg" class="" title="同轴电缆.jpg(课本)"><p>在局域网发展的初期曾广泛地使用同轴电缆作为传输媒体。但随着技术的进步,在局域网领域基本上都采用双绞线作为传输媒体。目前同轴电缆主要用在有线电视网的居民小区中。同轴电缆的带宽取决于电缆的质量。目前高质量的同轴电缆的带宽已接近1 GHz。</p><h4 id="3-光纤">3. 光纤</h4><p>光纤通信就是利用光导纤维(以下简称为光纤)传递光脉冲来进行通信的。有光脉冲相当于1,而没有光脉冲相当于0。由于可见光的频率非常高,约为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><msup><mn>0</mn><mn>8</mn></msup></mrow><annotation encoding="application/x-tex">10^8</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">8</span></span></span></span></span></span></span></span></span></span></span>MHz的量级,因此一个光纤通信系统的传输带宽远远大于目前其他各种传输媒体的带宽。</p><p>光纤是光纤通信的传输媒体。在发送端有光源,可以采用发光二极管或半导体激光器,它们在电脉冲的作用下能产生出光脉冲。在接收端利用光电二极管做成光检测器,在检测到光脉冲时可还原出电脉冲。</p><p>光纤通常由非常透明的石英玻璃拉成细丝,主要由纤芯和包层构成双层通信圆柱体。纤芯很细,其直径只有 8~100 μm (1 μm=<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><msup><mn>0</mn><mrow><mo>−</mo><mn>6</mn></mrow></msup></mrow><annotation encoding="application/x-tex">10^{-6}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight">6</span></span></span></span></span></span></span></span></span></span></span></span> m)。光波正是通过纤芯进行传导的。包层较纤芯有较低的折射率。当光线从高折射率的媒体射向低折射率的媒体时,其折射角将大于入射角(如图2-8所示)。因此,如果入射角足够大,就会出现全反射,即光线碰到包层时就会折射回纤芯。这个过程不断重复,光也就沿着光纤传输下去。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%85%89%E7%BA%BF%E5%9C%A8%E5%85%89%E7%BA%A4%E4%B8%AD%E7%9A%84%E6%8A%98%E5%B0%84.jpg" class="" title="光线在光纤中的折射.jpg(课本)"><p>图2-9画出了光波在纤芯中传输的示意图。现代的生产工艺可以制造出超低损耗的光纤,即做到光线在纤芯中传输数公里而基本上没有什么衰耗。这一点乃是光纤通信得到飞速发展的最关键因素。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%85%89%E6%B3%A2%E5%9C%A8%E7%BA%A4%E8%8A%AF%E4%B8%AD%E7%9A%84%E4%BC%A0%E8%BE%93.jpg" class="" title="光波在纤芯中的传输.jpg(课本)"><p>图2-9中只画了一条光线。实际上,只要从纤芯中射到纤芯表面的光线的入射角大于某个临界角度,就可产生全反射。因此,可以存在多条不同角度入射的光线在一条光纤中传输。这种光纤就称为<strong>多模光纤</strong>(如图2-10(a)所示)。光脉冲在多模光纤中传输时会逐渐展宽,造成失真。因此多模光纤只适合于近距离传输。若光纤的直径减小到只有一个光的波长,则光纤就像一根波导那样,可使光线一直向前传播,而不会产生多次反射。这样的光纤称为<strong>单模光纤</strong>(如图2-10(b)所示)。单模光纤的纤芯很细,其直径只有几个微米,制造起来成本较高。同时单模光纤的光源要使用昂贵的半导体激光器,而不能使用较便宜的发光二极管。但单模光纤的衰耗较小,在100 Gbit/s的高速率下可传输100公里而不必采用中继器。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%8D%95%E6%A8%A1%E5%85%89%E7%BA%A4%E4%B8%8E%E5%A4%9A%E6%A8%A1%E5%85%89%E7%BA%A4%E6%AF%94%E8%BE%83.jpg" class="" title="单模光纤与多模光纤比较.jpg(课本)"><p>在光纤通信中常用的三个波段的中心分别位于850 nm,1300 nm和1550 nm。后两种情况的衰减都较小。850 nm波段的衰减较大,但在此波段的其他特性均较好。所有这三个波段都具有25000~30000 GHz的带宽,可见光纤的通信容量非常大。</p><p>由于光纤非常细,连包层一起的直径也不到0.2 mm。因此必须将光纤做成很结实的光缆。一根光缆少则只有一根光纤,多则可包括数十至数百根光纤,再加上加强芯和填充物就可以大大提高其机械强度。必要时还可放入远供电源线。最后加上包带层和外护套,就可以使抗拉强度达到几公斤,完全可以满足工程施工的强度要求。图2-11为四芯光缆剖面的示意图。</p><img src="/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/%E5%9B%9B%E8%8A%AF%E5%85%89%E7%BC%86%E5%89%96%E9%9D%A2%E7%9A%84%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" class="" title="四芯光缆剖面的示意图.jpg(课本)"><p>光纤不仅具有通信容量非常大的优点,而且还具有其他的一些特点:</p><ol><li>传输损耗小,中继距离长,对远距离传输特别经济。</li><li>抗雷电和电磁干扰性能好。这在有大电流脉冲干扰的环境下尤为重要。</li><li>无串音干扰,保密性好,也不易被窃听或截取数据。</li><li>体积小,重量轻。这在现有电缆管道己拥塞不堪的情況下特别有利。例如,1km长的1000对双绞线电缆约重8000kg,而同样长度但容量大得多的一对两芯光缆仅重100kg。但要把两根光纤精确地连接起来,需要使用专用设备。</li></ol><p>由于生产工艺的进步,光纤的价格不断降低,因此现在己经非常广泛地应用在计算机网络,电信网络和有线电视网络的主干网络中。光纤提供了很高的带宽,而且性价比很高,在高速局域网中也使用得很多。例如,2016年间世的OM5光纤(宽带多模光纤)使用短波分复用SWDM(Short WDM),可支持40 Gbit/s和100 Gbit/s的数据传输。</p><blockquote><p>具体的复用与分用的知识在考纲中数据链路层<a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%EF%BC%88%E4%B8%80%EF%BC%89%E4%BF%A1%E9%81%93%E5%88%92%E5%88%86">信道划分</a>部分体现,但教材在物理层中提出。</p></blockquote><p>最后要提一下,在导引型传输媒体中,还有一种是架空明线(铜线或铁线)。这是在20世纪初就已大量使用的方法——在电线杆上架设的互相绝缘的明线,架空明线安装简单,但通信质量差,受气候环境等影响较大。许多国家现在都己停止了铺设架空明线。目前在我国的一些农村和边远地区的通信仍使用架空明线。</p><h4 id="4-无线传输介质">4. 无线传输介质</h4><blockquote><p>本节课本介绍内容十分详细,这里仅简要概括。</p></blockquote><p>无线传输介质,也称为非导引型传输媒体,是指无需物理导体即可进行数据传输的通信媒介。与通过电缆传输数据的方式不同,无线传输依赖电磁波在空中传播。这种传输方式广泛应用于广播、卫星通信、无线局域网、蜂窝网络等领域,极大地推动了现代通信技术的发展。</p><h5 id="1-无线电波">(1)无线电波</h5><p>在无线传输介质中,无线电波是最为常见的一种。它的频率范围通常在3kHz到300GHz之间,具有长距离传播的特点。由于无线电波的低频特性,它们能够穿透建筑物和树木等障碍物,使得信号能够覆盖广泛的区域。然而,无线电波在传播过程中可能会遇到反射、折射和衍射等现象,导致信号通过多条路径到达接收器。这种多路径传播虽然能够增强信号覆盖范围,但也可能引起信号干扰和衰减,影响通信质量。因此,在无线电波应用中,如何有效处理多路径效应是一个重要的研究课题。无线电波被广泛应用于广播电视、AM/FM收音机、蜂窝网络和Wi-Fi等领域,成为人们日常生活中不可或缺的一部分。</p><h5 id="2-微波">(2)微波</h5><p>与无线电波相比,微波的频率范围较高,一般在1GHz至30GHz之间。微波信号的传播方式主要是沿直线传播,因此它们的传播距离受限于视距范围。由于地球的曲率影响,微波通信的覆盖范围相对有限,这就需要中继站或卫星来实现更远距离的通信。微波通信具有高带宽的优势,能够传输大量数据,因此常用于卫星通信、移动通信以及Wi-Fi和蓝牙等应用中。</p><h5 id="3-红外线">(3)红外线</h5><p>红外线作为另一种无线传输介质,频率范围通常在300GHz至400THz之间。与无线电波和微波不同,红外线的传播距离较短,且对直线传播要求较高,无法穿透墙壁等障碍物。红外线的高方向性使得它在信号传输时需要精确对准发射器和接收器。虽然红外线的应用范围较窄,但它在红外遥控器、红外数据传输和近场通信等领域发挥着重要作用。</p><h5 id="4-可见光">(4)可见光</h5><p>除了红外线,可见光也是一种常用的无线传输介质。可见光的频率范围在400THz至800THz之间,波长大约在400nm至700nm之间。与红外线类似,可见光波只能在视距内传播,并且容易受到障碍物的影响。可见光的优势在于其不会受到电磁干扰,这使得它在一些对电磁环境敏感的场景中具有独特的应用价值,如可见光通信(VLC)和基于光的无线通信(Li-Fi)。</p><h5 id="5-激光">(5)激光</h5><p>激光也是一种重要的无线传输介质。激光信号具有极高的方向性和集中性,能够在极长的距离上传输,但前提是发射器和接收器必须精确对准。由于激光信号的集中性,它容易受到天气条件的影响,如雨、雾和烟尘等都会对激光通信产生干扰。尽管如此,激光在卫星通信、光纤通信、激光测距和激光雷达等领域仍然有着广泛的应用。</p><h5 id="优缺点">优缺点</h5><p>无线传输介质在现代通信中具有许多优点。</p><ol><li>它具有很高的灵活性,不受电缆布局的限制,使得设备的移动和网络的扩展更加便捷。</li><li>无线传输无需铺设物理电缆,特别适用于一些难以布线或成本高昂的地区。</li><li>无线通信技术还可以覆盖大范围区域,适用于广域网和远程通信。</li></ol><p>然而,无线传输也存在一些缺点。</p><ol><li>由于无线信号容易受到电磁波、物理障碍和天气条件的干扰,导致信号质量下降。</li><li>同时,因无线信号易被截获,必须采取加密等安全措施来保护数据传输的机密性</li><li>此外,无线传输的带宽通常有限,尤其在多用户同时访问时,容易导致网络拥塞。</li></ol><h3 id="(二)物理层接口的特性">(二)物理层接口的特性</h3><p>物理层接口的特性主要是围绕如何在各种传输媒体上有效传输数据比特流展开的。物理层的重点在于屏蔽不同传输媒体和通信手段的差异,从而使数据链路层不必关心这些底层细节,专注于完成其自身的协议和服务。物理层所涉及的协议,通常也被称为物理层规程,其核心任务是确定与传输媒体接口相关的几个关键特性。</p><ol><li>机械特性:描述了接口的物理连接形式,这包括接线器的形状、尺寸、引脚数目和排列方式,以及固定和锁定装置的设计。比如我们日常见到的各种接插件,都有严格的标准化规定来确保它们可以正确连接并可靠工作。</li><li>电气特性:涉及接口电缆上出现的电压范围、传输速率和距离限制。这些特性确保在传输数据时,信号电平能够在不同设备之间正确传递,不会因电气不兼容而导致传输错误。</li><li>功能特性:它定义了某条线上出现的电平电压的意义,以及每条线的功能。例如,某一电平可能代表逻辑高或逻辑低,或者表示不同的控制信号。功能特性帮助通信双方理解和解释在物理介质上传输的信号。</li><li>过程特性:又叫规程特性,描述了不同功能的各种可能事件的出现顺序。它确保了在通信过程中,信号的发送、接收和处理都是按照预定的顺序进行的,从而避免冲突和混乱。</li></ol><h2 id="三、物理层设备">三、物理层设备</h2><p>在网络通信的物理层中,中继器和集线器是两个常见的设备,它们在不同的网络场景中扮演着关键角色,帮助信号在网络中有效传输。</p><h3 id="(一)中继器">(一)中继器</h3><p>中继器的主要功能是整形、放大并转发信号,以消除信号经过长距离传输后产生的失真和衰减。通过信号再生而不是简单放大,中继器能够恢复信号的波形和强度,从而扩大网络的传输距离。</p><ul><li><p><strong>工作原理</strong>:中继器有两个端口,信号从一个端口输入,经过整形和放大后,从另一个端口输出。中继器只作用于信号的电气部分,不关心数据内容是否正确或是否适合网段。</p></li><li><p><strong>应用场景</strong>:中继器是用于扩大网络规模的简单廉价的互连设备。它连接的网段仍属于同一个局域网,并不会划分广播域或冲突域。</p></li><li><p><strong>限制</strong>:中继器不能连接不同速率的局域网,因为它没有存储转发功能。理论上,中继器的使用数量是无限的,但实际上受到网络标准的限制。例如,10BASE5以太网规范中,中继器的数量不能超过4个,否则会导致网络故障。</p></li><li><p><strong>与放大器的区别</strong>:放大器放大的是模拟信号,而中继器放大的是数字信号。放大器仅仅是增强衰减的信号,而中继器通过再生信号,使其恢复到原始的状态。</p></li></ul><h3 id="(二)集线器-Hub">(二)集线器 (Hub)</h3><p>集线器实质上是一个多端口的中继器,它在网络中起到信号放大和转发的作用,帮助扩大网络的传输范围。</p><ul><li><p><strong>工作方式</strong>:当集线器接收到一个端口的信号时,它会将信号整形放大,然后转发到其他所有工作状态的端口。如果多个端口同时输入信号,集线器会发生冲突,使得这些数据都无效。</p></li><li><p><strong>网络结构</strong>:集线器将所有节点的通信集中在以其为中心的节点上,形成一个共享式网络。但逻辑上,这样的网络仍然是一个总线网。集线器只能在半双工状态下工作,这意味着它无法同时发送和接收数据。</p></li><li><p><strong>冲突域和广播域</strong>:集线器的所有端口都属于同一个冲突域。由于在一个时钟周期内,集线器只能传输一组信息,因此当连接的设备较多且同时通信时,集线器的工作效率会大大降低。例如,带宽为10Mbps的集线器连接8台计算机时,每台计算机实际可用的带宽只有1.25Mbps。</p></li></ul>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>物理层</tag>
</tags>
</entry>
<entry>
<title>计算机网络——计算机网络概述</title>
<link href="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/"/>
<url>/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/</url>
<content type="html"><![CDATA[<h1>计算机网络概述</h1><h2 id="一、计算机网络基本概念">一、计算机网络基本概念</h2><h3 id="(一)计算机网络的定义">(一)计算机网络的定义</h3><p>一般认为,计算机网络是一个将众多分散的、自治的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统。</p><h4 id="1-计算机网络-简称网络">1. 计算机网络(简称网络)</h4><p>由若干<strong>结点</strong>(node,或译为节点)和连接这些结点的<strong>链路</strong>(link)组成。网络中的结点可以是计算机、集线器、交换机或路由器等。</p><h4 id="2-internet-互连网">2. internet(互连网)</h4><p>是一个通用名词,泛指由多个计算机网络互连而成的计算机网络。计算机网络之间可通过路由器互连,构成一个覆盖范围更广的计算机网络,这样的网络称为互连网(internet),因此互连网通常被称为网络的网络。计算机网络把许多计算机连在一起,而互连网则把许多网络通过路由器连在一起。组成互连网的计算机网络之间可以使用<strong>任意的通信协议</strong>作为通信规则,不一定非要使用 TCP/IP 协议。</p><h4 id="3-Internet-互联网或因特网">3. Internet(互联网或因特网)</h4><p>是一个专用名词,指当前全球最大的、开放的、由众多网络和路由器互连而成的特定计算机网络,它采用 <strong>TCP/IP</strong> 协议族作为通信规则。</p><p>因此,(计算机)网络把许多计算机连接在一起,而互连网(internet)则把许多网络通过一些路由器连接在一起。与网络相连的计算机常称为主机。互联网(Internet)是全球性的也是最大范围的互连网。</p><h3 id="(二)计算机网络的组成">(二)计算机网络的组成</h3><p>从不同的角度看,可以将计算机网络看成不同的组成。</p><h4 id="1-从组成部分看">1. 从组成部分看</h4><p>计算机网络主要由<strong>硬件</strong>、<strong>软件</strong>、<strong>协议</strong>三大部分组成。</p><p>硬件主要由主机(也称端系统)、通信链路(如双绞线、光纤)、交换设备(如路由器、交换机等)和通信处理机(如网卡)等组成。</p><p>软件主要包括各种实现资源共享的软件和方便用户使用的各种工具软件(如E-mail 程序、FTP程序、聊天程序等)。</p><p>协议是计算机网络的核心,如同交通规则制约汽车驾驶一样,协议规定了网络传输数据时所遵循的规范。</p><h4 id="2-从工作方式看">2. 从工作方式看</h4><blockquote><p>课本p9-p12详细介绍了计算机网络的边缘部分,其中着重强调了端系统之间的两种通信方式,p12-p17着重介绍了计算机网络的核心部分以及介绍了三种交换方式的不同,三种交换方式的介绍放在后文第(五)部分中介绍。</p></blockquote><p>计算机网络(这里主要指 Internet,即互联网)可分为<strong>边缘部分</strong>和<strong>核心部分</strong>。</p><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E4%BA%92%E8%81%94%E7%BD%91%E7%9A%84%E8%BE%B9%E7%BC%98%E9%83%A8%E5%88%86%E4%B8%8E%E6%A0%B8%E5%BF%83%E9%83%A8%E5%88%86.jpg" class="" title="互联网的边缘部分与核心部分.jpg"><p><strong>边缘部分</strong>由所有连接到互联网上的供用户直接使用的主机组成,用来进行<strong>通信(如传输数据、音频或视频)和资源共享</strong>。</p><p>在网络边缘的端系统之间的通信方式通常可划分为两大类:客户-服务器方式(C/S方式)和对等方式(P2P方式)。</p><p><strong>核心部分</strong>由大量网络和连接这些网络的路由器组成,它为边缘部分<strong>提供连通性和交换服务</strong>。</p><p>网络核心部分是互联网中最复杂的部分,因为网络中的核心部分要向网络边缘部分中的大量主机提供连通性,使边缘部分中的任何一台主机都能够与其他主机通信。</p><p>在网络核心部分起特殊作用的是<strong>路由器</strong>(router),它是一种专用计算机(但不叫作主机)。路由器是实现<strong>分组交换</strong>(packet switching)的关键构件,其任务是转发收到的分组,这是网络核心部分最重要的功能。</p><h4 id="3-从功能组成上看">3. 从功能组成上看</h4><p>计算机网络由<strong>通信子网</strong>和<strong>资源子网</strong>组成。</p><p>通信子网由各种传输介质、通信设备和相应的网络协议组成,它使网络具有数据传输、交换、控制和存储的能力,实现联网计算机之间的数据通信。</p><p>资源子网是实现资源共享功能的设备及其软件的集合,向网络用户提供共享其他计算机上的硬件资源、软件资源和数据资源的服务。</p><h3 id="(三)计算机网络的功能">(三)计算机网络的功能</h3><p>计算机网络的功能很多,现今的很多应用都与网络有关,主要有以下五大功能。</p><h4 id="1-数据通信">1. 数据通信</h4><p>数据通信是计算机网络最基本和最重要的功能,用来实现联网计算机之间各种信息的传输,并联系分散在不同地理位置的计算机,进行统一的调配、控制和管理。例如,文件传输、电子邮件等应用,离开了计算机网络就无法实现。</p><h4 id="2-资源共享">2. 资源共享</h4><p>资源共享既可是软件共享、数据共享受又可是硬件共享,它使计算机网络中的资源互通有无、分工协作,从而极大地提高了硬件资源、软件资源和数据资源的利用率。</p><h4 id="3-分布式处理">3. 分布式处理</h4><p>当计算机网络中的某个计算机系统负荷过重时,可将其处理的某个复杂任务分配给网络中的其他计算机系统,从而利用空闲计算机资源来提高整个系统的利用率。</p><h4 id="4-提高可靠性">4. 提高可靠性</h4><p>计算机网络中的各台计算机可以通过网络互为替代机。</p><h4 id="5-负载均衡">5. 负载均衡</h4><p>将工作任务均衡地分配给计算机网络中的各台计算机。</p><p>除了以上几大主要功能,计算机网络还可实现电子化办公与服务、远程教育、娱乐等功能,满足了社会的需求,方便了人们的学习、工作和生活,具有巨大的经济效益。</p><h3 id="(四)互联网的基本特点">(四)互联网的基本特点</h3><h4 id="1-连通性">1. 连通性</h4><p>所谓连通性(connectivity),就是互联网使上网用户之间,不管相距多远(例如,相距数千公里),都可以非常便捷、非常经济地(在很多情况下甚至是免费的)交换各种信息(数据,以及各种音频、视频),好像这些用户终端都彼此直接连通一样。这与使用传统的电信网络有着很大的区别。我们知道,传统的电信网向用户提供的最重要的服务就是人与人之间的电话通信,因此电信网也具有连通性这个特点。但使用电信网的电话用户,往往要为此向电信网的运营商缴纳相当昂贵的费用,特别是长距离的越洋通信。但应注意,互联网具有虚拟的特点。例如,当你从互联网上收到一封电子邮件时,你可能无法准确知道对方是谁(朋友还是骗子),也无法知道发信人的地点(在附近,还是在地球对面)。</p><h4 id="2-共享">2. 共享</h4><p>所谓共享就是指资源共享。资源共享的含义是多方面的,可以是信息共享、软件共享,也可以是硬件共享。例如,互联网上有许多服务器(就是一种专用的计算机)存储了大量有价值的电子文档(包括音频和视频文件),可供上网的用户很方便地读取或下载(无偿或有偿)。由于网络的存在,这些资源好像就在用户身边一样,使用非常方便。</p><h3 id="(五)电路交换、报文交换、分组交换">(五)电路交换、报文交换、分组交换</h3><p>在网络核心部分起重要作用的是路由器(router),它对收到的分组进行存储转发来实现分组交换。要了解分组交换的原理,首先就要学习电路交换的相关概念。</p><h4 id="1-电路交换">1. 电路交换</h4><h5 id="1-电路交换的概念">(1)电路交换的概念</h5><p>最典型的电路交换网是传统电话网,如下图所示。从通信资源分配的角度看,交换就是按照某种方式动态地分配传输线路的资源。电路交换分为三步:连接建立、数据传输和连接释放。在进行数据传输前,两个结点之间必须先建立一条专用(双方独占)的物理通信路径(由通信双方之间的交换设备和链路逐段连接而成),该路径可能经过许多中间结点。在数据传输过程中,这一物理通信路径始终被用户独占,直到通信结束后才被释放。</p><p>在电路交换的整个通信阶段,比特流连续地从源点直达终点,就好像在一个管道中传送。</p><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E7%94%B5%E8%B7%AF%E4%BA%A4%E6%8D%A2.jpg" class="" title="电路交换.jpg"><h5 id="2-电路交换的优点">(2)电路交换的优点</h5><ol><li>通信时延小。因为通信线路为通信双方专用,数据直达,所以传输时延非常小。</li><li>有序传输。双方通信时按发送顺序传送数据,不存在失序问题。</li><li>没有冲突。不同的通信双方拥有不同的信道,不会出现争用物理信道的问题。</li><li>适用范围广。电路交换既适用于传输模拟信号,又适用于传输数字信号。</li><li>实时性强。通信双方之间的物理通路一旦建立,双方就可随时通信。</li><li>控制简单。电路交换的交换设备(交换机等)及控制均较简单。</li></ol><h5 id="3-电路交换的缺点">(3)电路交换的缺点</h5><ol><li>建立连接时间长。电路交换的平均连接建立时间对计算机通信来说太长。</li><li>线路利用率低。物理通路被通信双方独占,即使线路空闲,也不能供其他用户使用。</li><li>灵活性差。物理通路中的任何一点出现故障,就必须重新拨号建立新的连接。</li><li>难以规格化。不同类型、不同规格、不同速率的终端很难相互进行通信。</li><li>难以实现差错控制。中间结点不具备存储和检验数据的能力,无法发现并纠正错误</li></ol><h4 id="2-报文交换">2. 报文交换</h4><h5 id="1-报文交换的概念">(1)报文交换的概念</h5><p>数据交换的单位是报文,用户数据加上源地址、目的地址等信息后,后封装成报文(message)。报文交换采用存储转发技术,整个报文先传送到相邻的结点,全部存储后查找转发表,转发到下一个结点,如此重复,直至到达目的结点。每个报文都可单独选择到达目的结点的路径。</p><h5 id="2-报文交换技术的优点">(2)报文交换技术的优点</h5><ol><li>无须建立连接。通信前无须建立连接,没有建立连接时延,用户可随时发送报文。</li><li>动态分配线路。交换设备存储整个报文后,选择一条合适的空闲线路,转发报文。</li><li>线路可靠性高。若某条传输路径发生故障,则可重新选择另一条路径传输数据。</li><li>线路利用率高。报文在哪段链路上传送时才占用这段链路的通信资源。</li><li>提供多目标服务。一个报文可以同时发送给多个目的地址。</li></ol><h5 id="3-报文交换技术的缺点">(3)报文交换技术的缺点</h5><ol><li>转发时延高。交换结点要将报文整体接收完后,才能查找转发表转发到下一个结点。</li><li>缓存开销大。报文的大小没有限制,这就要求交换结点拥有较大的缓存空间。</li><li>错误处理低效。报文较长时,发生错误的概率相对更大,重传整个报文的代价也很大。</li></ol><h4 id="3-分组交换">3. 分组交换</h4><h5 id="1-分组交换的概念">(1)分组交换的概念</h5><p>分组交换也采用存储转发技术,但解决了报文交换中报文过长的问题。若报文太长,则对交换结点的缓存容量就有很大的需求,在错误处理方面也比较低效。源结点在发送之前,先把较长的报文划分成若干较小的等长数据段,在每个数据段前面添加一些由必要控制信息(如源地址、目的地址和编号信息等)组成的首部,构成分组(Packet),如下图所示。</p><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E5%88%86%E7%BB%84%E4%BA%A4%E6%8D%A2.jpg" class="" title="分组交换.jpg"><p>源结点将分组发送到分组交换网中,分组交换网中的分组交换机收到一个分组后,先将其缓存,然后从其首部中提取目的地址,据此查找自己的转发表,再后将分组转发给下一个分组交换机。经过多个分组交换机的存储转发后,分组最终到达目的结点。</p><h5 id="2-分组交换的优点">(2)分组交换的优点</h5><ol><li>无建立时延。通信前无须建立连接,没有建立连接时延,用户可随时发送分组。</li><li>线路利用率高。分组在哪段链路上传送时才占用这段链路的通信资源。相比采用电路交换传送突发式的计算机数据,分组交换的通信线路利用率大大提高。</li><li>简化了存储管理(相对于报文交换)。因为分组的长度固定,相应缓冲区的大小也固定,在交换结点中存储器的管理通常被简化为对缓冲区的管理,相对比较容易。</li><li>加速传输。分组是逐个传输的,可以使后一个分组的存储操作与前一个分组的转发操作并行,这种流水线方式减少了报文的传输时间。此外,传输一个分组比传输一次报文所需的缓冲区小得多,这样,因缓冲区不足而等待发送的概率及时间必然也少得多。</li><li>减小了出错概率和重发数据量。因为分组较短,其出错概率必然减小,所以每次重发的数据量也就大大减少,这样不仅提高了可靠性,而且减小了传输时延。</li></ol><h5 id="3-分组交换的缺点">(3)分组交换的缺点</h5><ol><li>存在存储转发时延。尽管分组交换比报文交换的传输时延小,但相对于电路交换仍存在存储转发时延,且其结点交换机必须具有更强的处理能力。</li><li>需要传输额外的信息量。每个小数据段都要加上控制信息以构成分组,这使得传送的信息量增大了5%~10%,进而使得控制复杂,降低了通信效率,增大了处理的时延。</li><li>当分组交换网采用数据报服务时,可能出现失序、丢失或重复分组的情况,分组到达目的结点时,要对分组按编号进行排序等工作,而这些工作很麻烦。若采用虚电路服务,则虽然没有失序问题,但有呼叫建立、数据传输和虚电路释放三个过程。</li></ol><h4 id="4-三种交换技术的示意图">4. 三种交换技术的示意图</h4><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E4%B8%89%E7%A7%8D%E4%BA%A4%E6%8D%A2%E5%AF%B9%E6%AF%94.jpg" class="" title="三种交换对比.jpg"><h3 id="(六)计算机网络的分类">(六)计算机网络的分类</h3><h4 id="1-按分布范围分类">1. 按分布范围分类</h4><ol><li>广域网(WAN)。广域网的任务是提供长距离通信,运送主机所发送的数据,其覆盖范围通常是直径为几十到几千千米的区域。广域网是互联网的核心部分。连接广域网的各结点交换机的链路一般都是高速链路,具有较大的通信容量。</li><li>城域网(MAN)。城域网的覆盖范围可以跨越几个街区甚至整个城市,覆盖区域的直径为5~50km。城域网大多采用以太网技术,因此有时也常并入局域网的范围讨论。</li><li>局域网(LAN)。局域网一般用主机通过高速线路相连,覆盖范围较小,通常是直径为几十到几千米的区域。传统上,局域网使用广播技术,而广域网使用交换技术。</li><li>个人区域网(PAN)。个人区域网是指在个人工作的地方将消费电子设备(如平板电脑、智能手机等)用无线技术连接起来的网络,也称无线个人区域网(WPAN)。</li></ol><h4 id="2-按传输技术分类">2. 按传输技术分类</h4><ol><li>广播式网络。所有联网计算机都共享一个公共通信信道。当一台计算机利用共享通信信道发送报文分组时,所有其他计算机都会“收听”到这个分组。接收到该分组的计算机将通过检查目的地址来决定是否接收该分组。局域网基本上都采用广播式通信技术,广域网中的无线、卫星通信网络也采用广播式通信技术。</li><li>点对点网络。每条物理线路连接一对计算机。若通信的两台主机之间没有直接连接的路,则它们之间的分组传输就要通过中间结点进行存储和转发,直至目的结点。</li></ol><h4 id="3-按拓扑结构分类">3. 按拓扑结构分类</h4><p>网络拓扑结构是指由网中结点(路由器、主机等)与通信线路之间的几何关系表示的网络主要指通信子网的拓扑结构。按网络的拓扑结构,可分为总线形、星形、环形和网状网络等。如下图所示。星形、总线形和环形网络多用于局域网,网状网络多用于广域网。</p><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E5%87%A0%E7%A7%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E6%8B%93%E6%89%91%E7%BB%93%E6%9E%84.jpg" class="" title="几种不同的网络拓扑结构.jpg"><ol><li>总线形网络。用单根传输线把计算机连接起来。优点是建网容易、增/减结点方便、节省线路。缺点是重负载时通信效率不高、总线任意一处对故障敏感。</li><li>星形网络。每个终端或计算机都以单独的线路与中央设备相连。中央设备一般是交换机或路由器。优点是便于集中控制和管理。缺点是成本高、中央设备对故障敏感。</li><li>环形网络。所有计算机接口设备连接成一个环。环形网络最典型的例子是令牌环局域网。环既可以是单环,又可以是双环,环中信号是单向传输的。</li><li>网状网络。一般情况下,每个结点至少有两条路径与其他结点相连,多用在广域网中。其有规则型和非规则型两种。优点是可靠性高。缺点是控制复杂、线路成本高。</li></ol><p>以上4种基本的网络拓扑结构可以互连为更复杂的网络。</p><h4 id="4-按使用者分类">4. 按使用者分类</h4><ol><li>公用网(Publie Network)。指电信公司出资建造的大型网络。“公用”的意思是指所有愿意按电信公司的规定缴纳费用的人都可使用这种网络。</li><li>专用网(Private Network)。指某个部门为满足本单位特殊业务的需要而建造的网络。这种网络不向本单位外的人提供服务,如铁路、电力、军队等部门的专用网。</li></ol><h4 id="5-按传输介质分类">5. 按传输介质分类</h4><p>传输介质可分为有线和无线两大类,因此网络可分为有线网络和无线网络。有线网络又可分双绞线网络、同轴电缆网络等,而无线网络又可分为蓝牙、微波、无线电等类型。</p><h3 id="(七)计算机网络的主要性能指标">(七)计算机网络的主要性能指标</h3><p>性能指标从不同方面度量计算机网络的性能。常用的性能指标如下。</p><ol><li>速率(Speed)。指连接到网络上的结点在数字信道上传送数据的速率,也称数据传输速率、数据传输率、数据率或比特率,单位为b/s(比特/秒)或bit/s(有时也写为bps)。当数据率较高时,可用kb/s(k=10)、Mb/s (M=10)或Gb/s(G=10)表示。</li><li>带宽(Bandwidth)。带宽原本表示通信线路允许通过的信号频率范围,单位是赫兹(Hz)。但在计算机网络中,带宽表示网络的通信线路所能传送数据的能力,是数字信道所能传送的“最高数据传输速率”的同义语,单位是比特/秒(b/s)。</li><li>吞吐量(Throughput)。指单位时间内通过某个网络(或吐量)常用在对实际网络的测量中,受网络带宽的限制。</li><li>时延(Delay)。指数据(一个报文或分组)从网络(或链路)的一端传送到另一端所需的总时间,它由4部分构成:发送时延、传播时延、处理时延和排队时延。</li></ol><blockquote><p>分组交换网中各种时延的计算(2010、2013、2023)</p><ul><li>发送时延,也称传输时延。结点将分组的所有比特推向链路所需的时间,即从发送分组的第一个比特算起,到该分组的最后一个比特发送完毕所需的时间。</li></ul><p>发送时延=分组长度/发送速率</p><ul><li>传播时延。电磁波在信道(传输介质)中传播一定的距离所花的时间,即一个比特从链路的一端传播到另一端所需的时间。</li></ul><p>传播时延=信道长度/电磁波在信道上的传播速率</p><p>区分传输时延和传播时延。传输时延是路由器将分组推出所需的时间,是分组长度和链路谕速率的函数。传播时延是一个比特从一台路由器传播至另一台路由器所需的时间,是两台由器之间距离的函数,而与分组长度或链路传输速率无关。</p><ul><li>处理时延。数据在交换结点为存储转发而进行的一些必要处理所花的时间。例如,分析分组的首部、从分组中提取数据、差错检验或查找合适的路由等。</li><li>排队时延。分组在进入路由器后要先在输入队列中排队等待处理。路由器确定转发端口后,还要在输出队列中排队等待转发。这就产生了排队时延。因此,数据在网络中经历的总时延就是以上4部分时延之和:<br>总时延=发送时延+传播时延+处理时延+排队时延</li></ul><p>处理时延和排队时延通常可忽略不计(除非另有说明)。</p></blockquote><ol start="5"><li>时延带宽积。指发送端发送的第一个比特即将到达终点时,发送端已发出了多少比特,又称以比特为单位的链路长度,即时延带宽积=传播时延x信道带宽。如下图所示,考虑一个代表链路的圆柱形管道,其长度表示链路的传播时延,横截面积表示链路带宽,则时延带宽积表示该管道可以容纳的比特数量。</li></ol><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E6%97%B6%E5%BB%B6%E5%B8%A6%E5%AE%BD%E7%A7%AF.jpg" class="" title="时延带宽积.jpg"><ol start="6"><li>往返时延(Round-Trip Time,RTT)。指从发送端发出一个短分组,到发送端收到来自接收端的确认(接收端收到数据后立即发送确认)总共经历的时延。在互联网中,往返时延还包括各中间结点的处理时延、排队时延及转发数据时的发送时延。</li><li>信道利用率。用以指出某个信道有百分之多少的时间是有数据通过的。</li></ol><p>信道利用率=有数据通过时间/(有+无)数据通过时间</p><h2 id="二、计算机网络体系结构">二、计算机网络体系结构</h2><h3 id="(一)计算机网络分层结构">(一)计算机网络分层结构</h3><p>计算机网络的各层及其协议的集合称为网络的体系结构(Architecture)。换言之,计算机网络的体系结构就是这个计算机网络及其所应完成的功能的精确定义。要强调的是,这些功能究竟是用何种硬件或软件完成的,是一个遵循这种体系结构的实现(Implementation)问题。体系结构是抽象的,而实现则是具体的,是真正在运行的计算机硬件和软件。计算机网络体系结构通常都具有可分层的特性,它将复杂的大系统分成若干较容易实现的层次。</p><p>分层的基本原则如下:</p><ol><li>每层都实现一种相对独立的功能,降低大系统的复杂度。</li><li>各层之间的接口自然清晰,易于理解,相互交流尽可能少。</li><li>各层功能的精确定义独立于具体的实现方法,可以采用最合适的技术来实现。</li><li>保持下层对上层的独立性,上层单向使用下层提供的服务。</li><li>整个分层结构应能促进标准化工作。</li></ol><p>在计算机网络分层结构中,第n层中的活动元素通常称为第n层<strong>实体</strong>。具体来说,实体指任何可发送或接收信息的硬件或软件进程,通常是某个特定的软件模块。不同机器上的同一层称为<strong>对等层</strong>,同一层的实体称为<strong>对等实体</strong>。第n层实体实现的服务为第n+1层所用。在这种情况下,第n层称为服务提供者,第n+1层则服务于用户。</p><p>在计算机网络体系结构中,对等层之间传送的数据单位称为该层的协议数据单元(PDU),第n层的 PDU 记为n-PDU。各层的 PDU 都分为数据和控制信息两部分。</p><p>服务数据单元(SDU):为完成用户所要求的功能而传送的数据。第n层的SDU记为n-SDU。</p><p>协议控制信息(PCI):控制协议操作的信息。第n层的PCI记为n-PCI。</p><p>每层的协议数据单元都有一个通俗的名称,如物理层的PDU称为比特流,数据链路层的PDU称为帧,网络层的PDU称为分组,传输层的PDU称为报文段。当在各层之间传输数据时,将从第n+1层收到的PDU作为第n层的SDU,加上第n层的PCI,就封装成了第n层的PDU,交给第n-1层后作为SDU发送,接收方接收时做相反的处理,因此可知三者的关系为<strong>n-SDU+n-PCI=n-PDU=(n-1)-SDU</strong>,其变换过程如下图所示。</p><p>具体地,层次结构的含义包括如下几方面:</p><ol><li>第n层的实体不仅要使用第n-1层的服务来实现自身定义的功能,而且要向第n+1层提供本层的服务,该服务是第n层及其下面各层提供的服务总和。</li><li>最低层只提供服务,是整个层次结构的基础:最高层面向用户提供服务。</li><li>上一层只能通过相邻层间的接口使用下一层的服务,而不能调用其他层的服务。</li><li>当两台主机通信时,对等层在逻辑上有一个直接信道,表现为能直接将信息传送到对方。</li></ol><h3 id="(二)计算机网络协议、接口、和服务的概念">(二)计算机网络协议、接口、和服务的概念</h3><h4 id="1-协议">1. 协议</h4><p>要在网络中做到有条不紊地交换数据,就必须遵循一些事先约定好的规则,其规定了所交换数据的格式及有关的同步问题。为了在网络中进行数据交换而建立的这些规则、标准或约定称为网络协议(Network Protocol),是控制在<strong>对等实体</strong>之间进行通信的规则的集合,是水平的。不对等实体之间是没有协议的,如用TCP/IP协议栈通信的两个结点A和结点B,结点A的传输层和结点B的传输层之间存在协议,但结点A的传输层和结点B的网络层之间不存在协议。</p><p>协议由语法、语义和同步三部分组成。</p><ol><li>语法。数据与控制信息的格式。例如,TCP报文段格式就是由TCP协议的语法定义的。</li><li>语义。即需要发出何种控制信息、完成何种动作及做出何种应答。例如,在建立TCP连接的三次握手时所执行的操作就是由TCP协议的语义定义的。</li><li>同步(或时序)。执行各种操作的条件、时序关系等,即事件实现顺序的详细说明。例如,建立TCP连接的三次握手操作的时序关系就是由TCP协议的同步定义的。</li></ol><h4 id="2-接口">2. 接口</h4><p>同一结点内相邻两层的实体交换信息的逻辑接口称为服务访问点(Service Access Point,SAP)。每层只能为紧邻的层之间定义接口,而不能跨层定义接口。服务是通过SAP提供给上层使用的,第n层的SAP就是第n+1层可以访问第n层服务的地方。</p><p>再次强调5个不得不知的专业术语:</p><ol><li>服务数据单元(SDU)。第n层的服务数据单元,记作 n-SDU。</li><li>协议控制信息(PCI)。第n层的协议控制信息,记作n-PCI。</li><li>接口控制信息(ICI)。第n层的接口控制信息,记作n-ICI。</li><li>协议数据单元(PDU)。第n层的服务数据单元(SDU)+第n层的协议控制信息(PCI)=第n层的协议数据单元,即n-SDU+n-PCI=n-PDU,表示的是同等层对等实体间传送的数据单元。另外,n-PDU=(n-1)-SDU。这个公式看完,后面的内容就会很清楚。例如,网络层的整个IP分组交到数据链路层,整个IP分组成为数据链路层的数据部分(现在不理解可直接跳过)。</li><li>接口数据单元(IDU)。第n层的服务数据单元(SDU)+第n层的接口控制信息(ICI)=第n层的接口数据单元,即n-SDU±ICI=n-IDU,表示的是在相邻层接口间传送的数据单元。</li></ol><h4 id="3-服务">3. 服务</h4><p>服务是指下层为紧邻的上层提供的功能调用,是垂直的。对等实体在协议的控制下,使得本层能为上层提供服务,但要实现本层协议,还需要使用下层提供的服务。当上层使用下层提供的服务时,必须与下层交换一些命令,这些命令称为服务原语。OSI参考模型将原语划分为四类:</p><ol><li>请求(Request)。由服务用户发往服务提供者,请求完成某项工作。</li><li>指示(Indication)。由服务提供者发往服务用户,指示用户做某件事情。</li><li>响应(Response)。由服务用户发往服务提供者,作为对指示的响应。</li><li>证实(Confirmation)。由服务提供者发往服务用户,作为对请求的证实。</li></ol><p>这四类原语用于不同的功能,如建立连接、传输数据和断开连接等。有应答服务包括全部四类原语,而无应答服务则只有请求和指示两类原语。</p><p>注意,协议和服务概念上是不一样的。首先,只有本层协议的实现才能保证向上一层提供服务。本层的服务用户只能看见服务而无法看见下面的协议,即下面的协议对上层的服务用户是透明的。其次,协议是“水平的”,即协议是控制对等实体之间通信的规则。但是,服务是“垂真的”,即服务是由下层通过层间接口向上层提供的。另外,并非在一层内完成的全部功能都称为服务,只有那些能够被高一层实体“看得见”的功能才称为服务。</p><h5 id="三种计算机网络提供的服务">三种计算机网络提供的服务</h5><p>计算机网络提供的服务可按以下三种方式分类。</p><h6 id="1-面向连接服务与无连接服务">(1)面向连接服务与无连接服务</h6><p>在面向连接服务中,通信前双方必须先建立连接,分配相应的资源(如缓冲区),以保证通信能正常进行,传输结束后释放连接和占用的资源。因此这种服务可分为连接建立、数据传输和连接释放三个阶段。例如,TCP就是一种面向连接服务的协议。</p><p>在无连接服务中,通信前双方不需要先建立连接,需要发送数据时可直接发送,将每个带有目的地址的包(报文分组)传送到线路上,由系统选定路线进行传输。这种服务常被描述为“尽最大努力交付”,是一种不可靠的服务。例如,IP、UDP 就是一种无连接服务的协议。</p><h6 id="2-可靠服务和不可靠服务">(2)可靠服务和不可靠服务</h6><p>可靠服务是指网络具有纠错、检错、应答机制,能保证数据正确、可靠地传送到目的地。不可靠服务是指网络只是尽量让数据正确、可靠地传送到目的地,是一种尽力而为的服务。</p><p>对于提供不可靠服务的网络,其网络的正确性、可靠性要由应用或用户来保障。例如,用户收到信息后要判断信息的正确性,若不正确,则用户就要把出错信息报告给信息的发送者,以便发送者采取纠正措施。通过用户的这些措施,可将不可靠服务变成可靠服务。</p><h6 id="3-有应答服务和无应答服务">(3)有应答服务和无应答服务</h6><p>有应答服务是指接收方在收到数据后向发送方给出相应的应答,该应答由传输系统内部自动实现,而不由用户实现。发送的应答既可以是肯定应答,又可以是否定应答,通常在接收到的数据有错误时发送否定应答。例如,文件传输服务就是一种有应答服务。</p><p>无应答服务是指接收方收到数据后不自动给出应答。若需要应答,则由高层实现。例如,对于 WWW服务,客户端收到服务器发送的页面文件后不给出应答。</p><h3 id="(三)ISO-OSI参考模型和TCP-IP模型">(三)ISO/OSI参考模型和TCP/IP模型</h3><p>OSI的七层协议体系结构的概念清楚,理论也较完整,但它既复杂又不实用。TCP/IP体系结构则不同,它现在得到了非常广泛的应用。TCP/IP 是一个四层的体系结构,它包含应用层,运输层,网际层和链路层 (网络接口层)。用网际层这个名字是强调本层解决不同网络的互连间题。在互联网的标准文栏[RFC 1122, STD3]中,体系结构中的底层叫作链路层,但接着又说明了链路层就是媒体接入层。但也有把链路层称为网络接口层的[COME06]或子网层的[PETE12]。从实质上讲,TCP/IP只有最上面的三层,因为最下面的链路层并没有属于 TCP/IP 体系的具体协议。链路层所使用的各种局域网标准,并非由IETF而是由IEEE的802委员会下属的各工作组负责制定的。在讲授计算机网络原理时往往采取另外的办法,即综合OSI和TCP/IP的优点,采用如图所示的五层协议的体系结构,这对阐述计算机网络的原理是十分方便的。</p><img src="/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/%E5%8F%82%E8%80%83%E6%A8%A1%E5%9E%8B%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" class="" title="参考模型示意图.jpg"><h4 id="1-OSI参考模型">1. OSI参考模型</h4><p>国际标准化组织 (ISO) 提出的网络体系结构模型称为开放系统互连参考模型 (OSI/RM),通常简称为OSI参考模型。OSI参考模型有 7层,自下而上依次为物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。低三层统称通信子网,是为联网而附加的通信设备,完成数据的传输功能:高三层统称资源子网,相当于计算机系统,完成数据的处理等功能。传输层承上启下。</p><table><thead><tr><th>层级</th><th>名称</th><th>功能描述</th><th>常见协议/技术</th><th>数据单位</th></tr></thead><tbody><tr><td>7</td><td>应用层 (Application)</td><td>提供网络服务给用户应用程序,如文件传输、电子邮件、远程登录等。</td><td>HTTP, FTP, SMTP, DNS</td><td>数据 (Data)</td></tr><tr><td>6</td><td>表示层 (Presentation)</td><td>负责数据格式的转换、加密解密、数据压缩等工作,确保数据在应用层可以被正确理解。</td><td>SSL/TLS, JPEG, MPEG</td><td>数据 (Data)</td></tr><tr><td>5</td><td>会话层 (Session)</td><td>管理应用程序之间的会话,负责建立、管理和终止会话,支持对话控制和数据同步。</td><td>RPC, NetBIOS, PPTP</td><td>数据 (Data)</td></tr><tr><td>4</td><td>传输层 (Transport)</td><td>提供端到端的数据传输服务,确保数据包的完整性与顺序,支持流量控制、差错检测与纠正。</td><td>TCP, UDP</td><td>段 (Segment)</td></tr><tr><td>3</td><td>网络层 (Network)</td><td>负责数据包的路由选择和转发,通过逻辑地址(如IP地址)将数据包从源节点发送到目的节点,可能跨越多个网络。</td><td>IP, ICMP, OSPF, BGP</td><td>数据包 (Packet)</td></tr><tr><td>2</td><td>数据链路层 (Data Link)</td><td>负责将数据封装成帧,并提供物理地址(MAC地址)的访问和控制,确保数据帧的无误传输,处理错误检测和纠正。</td><td>Ethernet, PPP, MAC</td><td>帧 (Frame)</td></tr><tr><td>1</td><td>物理层 (Physical)</td><td>定义了物理设备的标准,如电缆、信号、电压等,负责比特流在物理介质上的传输。</td><td>光纤, 同轴电缆, RJ-45, USB</td><td>比特 (Bit)</td></tr></tbody></table><h4 id="2-TCP-IP模型">2. TCP/IP模型</h4><table><thead><tr><th>层级</th><th>名称</th><th>功能描述</th><th>常见协议/技术</th><th>数据单位</th></tr></thead><tbody><tr><td>4</td><td>应用层 (Application Layer)</td><td>提供应用程序之间的通信服务,涵盖了OSI模型中的应用层、表示层和会话层的功能。支持各种应用协议如HTTP、FTP、DNS、SMTP等。</td><td>HTTP, FTP, SMTP, DNS, SSH, Telnet</td><td>数据 (Data)</td></tr><tr><td>3</td><td>传输层 (Transport Layer)</td><td>负责端到端的数据传输,确保数据的可靠性和顺序传递。提供流量控制、差错检测与纠正。主要协议有TCP和UDP。</td><td>TCP, UDP</td><td>段 (Segment)</td></tr><tr><td>2</td><td>网络层 (Internet Layer)</td><td>负责逻辑地址的处理(如IP地址),数据包的路由选择和转发。确保数据包能够跨越不同的网络到达目的地。对应OSI模型中的网络层。</td><td>IP, ICMP, ARP, RIP, OSPF, BGP</td><td>数据包 (Packet)</td></tr><tr><td>1</td><td>网络接口层 (Network Interface Layer)</td><td>处理数据链路层和物理层的功能,负责将数据帧通过物理介质进行传输。确保数据在同一局域网或链路上传输,包含数据帧的封装、地址访问和物理传输。</td><td>Ethernet, Wi-Fi, Token Ring, PPP</td><td>帧/比特 (Frame/Bit)</td></tr></tbody></table><h4 id="3-TCP-IP模型与OSI参考模型的比较">3. TCP/IP模型与OSI参考模型的比较</h4><ul><li><strong>层级数量</strong>:OSI模型有七层,而TCP/IP模型只有四层。</li><li><strong>表示层与会话层</strong>:在TCP/IP模型中,这两层的功能被整合到应用层中,而在OSI模型中,它们是独立的层。</li><li><strong>实际应用</strong>:OSI模型主要是一个理论框架,而TCP/IP模型则是互联网协议的实际实现,更加简洁实用。</li><li><strong>物理层与数据链路层</strong>:在TCP/IP模型中,这两层合并为网络接口层,处理数据的物理传输和链路层的功能。</li></ul><h4 id="4-结合两种模型的五层参考模型">4. 结合两种模型的五层参考模型</h4><table><thead><tr><th>层级</th><th>名称</th><th>对应OSI模型的层级</th><th>对应TCP/IP模型的层级</th><th>功能描述</th></tr></thead><tbody><tr><td>5</td><td>应用层 (Application)</td><td>应用层、表示层、会话层</td><td>应用层</td><td>提供各种网络服务与应用程序的交互。</td></tr><tr><td>4</td><td>传输层 (Transport)</td><td>传输层</td><td>传输层</td><td>提供端到端的数据传输服务,确保数据完整性与可靠传递。</td></tr><tr><td>3</td><td>网络层 (Network)</td><td>网络层</td><td>网络层</td><td>负责逻辑地址的处理与路由选择,确保数据包到达正确的目的地。</td></tr><tr><td>2</td><td>数据链路层 (Data Link)</td><td>数据链路层</td><td>网络接口层</td><td>负责数据帧的封装与传输,处理物理地址的访问与控制。</td></tr><tr><td>1</td><td>物理层 (Physical)</td><td>物理层</td><td>网络接口层</td><td>处理数据在物理介质上的传输,如电缆和信号。</td></tr></tbody></table>]]></content>
<categories>
<category>计算机网络</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>计算机网络</tag>
<tag>计算机网络概述</tag>
</tags>
</entry>
<entry>
<title>编程基础——C++语言基础知识</title>
<link href="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<url>/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</url>
<content type="html"><![CDATA[<h1>C++语言基础知识</h1><h2 id="一、控制台程序的基本结构">一、控制台程序的基本结构</h2><p>C++控制台程序通常从一个简单的"Hello World"示例开始,这有助于初学者理解程序的基本结构和工作方式。</p><h3 id="示例代码:">示例代码:</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Hello World!!!"</span> << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><ul><li><code>#include <iostream></code>:这是一个预处理指令,用于包含标准输入输出流库,使得可以使用<code>cout</code>进行输出。</li><li><code>using namespace std;</code>:这条语句允许我们直接使用标准命名空间中的名称,如<code>cout</code>和<code>endl</code>,而无需在前面加<code>std::</code>。</li><li><code>int main()</code>:定义了主函数,这是每个C++程序的入口点。<code>int</code>表示函数返回一个整数给操作系统。</li><li><code>cout << "Hello World!!!" << endl;</code>:使用插入操作符<code><<</code>向控制台输出文本。<code>endl</code>是一个操纵符,用于插入一个换行符并刷新输出缓冲区。</li><li><code>return 0;</code>:表示程序正常结束。</li></ul><h2 id="二、输入输出语句">二、输入输出语句</h2><p>C++使用<code>cout</code>和<code>cin</code>进行标准输出和输入。</p><h3 id="(1)输出语句cout">(1)输出语句<code>cout</code></h3><ul><li><code>cout</code>用于向控制台输出文本或变量。</li><li><code>endl</code>用于结束当前行并刷新输出缓冲区。</li></ul><h4 id="示例:">示例:</h4><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs C++">cout << <span class="hljs-string">"Hello world"</span> << endl;<br><span class="hljs-type">int</span> a = <span class="hljs-number">122</span>;<br>cout << a << endl;<br></code></pre></td></tr></table></figure><h3 id="(2)输入语句cin">(2)输入语句<code>cin</code></h3><ul><li><code>cin</code>用于从标准输入(通常是键盘)读取数据。</li></ul><h4 id="示例:-2">示例:</h4><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">int</span> a;<br><span class="hljs-type">char</span> b;<br>cin >> a >> b;<br></code></pre></td></tr></table></figure><h2 id="三、变量和常量">三、变量和常量</h2><h3 id="(1)常量">(1)常量</h3><p>在C++中,常量是一旦初始化后其值不可改变的实体。</p><h4 id="1-整数">1. 整数</h4><p>使用<code>const</code>关键字定义整数常量:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">const</span> <span class="hljs-type">int</span> maxStudents = <span class="hljs-number">30</span>;<br></code></pre></td></tr></table></figure><h4 id="2-浮点数">2. 浮点数</h4><p>定义浮点数常量:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">const</span> <span class="hljs-type">double</span> pi = <span class="hljs-number">3.14159</span>;<br></code></pre></td></tr></table></figure><h3 id="(2)变量">(2)变量</h3><p>变量是可以在程序执行期间改变值的实体。</p><h4 id="1-整型(int)">1. 整型(<code>int</code>)</h4><p>用于存储整数。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">int</span> age = <span class="hljs-number">25</span>;<br></code></pre></td></tr></table></figure><h4 id="2-浮点型(float-double)">2. 浮点型(<code>float</code>, <code>double</code>)</h4><p>用于存储带小数点的数字。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">double</span> salary = <span class="hljs-number">4589.50</span>;<br></code></pre></td></tr></table></figure><h4 id="3-布尔型(bool)">3. 布尔型(<code>bool</code>)</h4><p>表示逻辑真(<code>true</code>)或假(<code>false</code>)。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">bool</span> isOnline = <span class="hljs-literal">true</span>;<br></code></pre></td></tr></table></figure><h4 id="4-字符型(char)">4. 字符型(<code>char</code>)</h4><p>用于存储单个字符。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-type">char</span> grade = <span class="hljs-string">'A'</span>;<br></code></pre></td></tr></table></figure><h4 id="5-字符串类型(string)">5. 字符串类型(<code>string</code>)</h4><p>用于存储一系列字符。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs C++">string name = <span class="hljs-string">"Alice"</span>;<br></code></pre></td></tr></table></figure><h2 id="四、基本程序结构">四、基本程序结构</h2><h3 id="1-顺序结构">(1)顺序结构</h3><p>顺序结构是最基本的程序结构,程序按照代码的书写顺序从上到下执行指令。在C++中,每条指令通常以分号(<code>;</code>)结束,表示一条语句的结束。这种结构适用于所有基本操作,如变量声明、赋值、调用函数等。</p><h4 id="示例:-3">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-type">int</span> a = <span class="hljs-number">5</span>; <span class="hljs-comment">// 声明并初始化变量</span><br> a = a + <span class="hljs-number">3</span>; <span class="hljs-comment">// 修改变量的值</span><br> cout << a << endl; <span class="hljs-comment">// 输出变量的值</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; <span class="hljs-comment">// 返回操作系统0,表示程序正常结束</span><br>}<br></code></pre></td></tr></table></figure><h3 id="2-选择结构">(2)选择结构</h3><p>选择结构允许程序基于条件判断来选择不同的执行路径。C++提供了多种选择结构,包括<code>if</code>语句、<code>else</code>语句、<code>else if</code>语句以及<code>switch</code>语句。</p><h4 id="1-if语句">1. <code>if</code>语句</h4><p>用于基于条件执行代码块。如果条件为真(true),则执行<code>if</code>块内的代码。</p><h5 id="示例:-4">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">if</span> (a > <span class="hljs-number">0</span>) {<br> cout << <span class="hljs-string">"a is positive."</span> << endl;<br>}<br></code></pre></td></tr></table></figure><h4 id="2-else和else-if语句">2. <code>else</code>和<code>else if</code>语句</h4><p><code>else</code>用于当<code>if</code>条件为假(false)时执行的代码块。<code>else if</code>允许对多个条件进行检查。</p><h5 id="示例:-5">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">if</span> (a > <span class="hljs-number">0</span>) {<br> cout << <span class="hljs-string">"a is positive."</span> << endl;<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a < <span class="hljs-number">0</span>) {<br> cout << <span class="hljs-string">"a is negative."</span> << endl;<br>} <span class="hljs-keyword">else</span> {<br> cout << <span class="hljs-string">"a is zero."</span> << endl;<br>}<br></code></pre></td></tr></table></figure><h4 id="3-switch语句">3. <code>switch</code>语句</h4><p>用于基于变量的值执行多个代码块中的一个。每个代码块由<code>case</code>标签指定,并且通常在末尾使用<code>break</code>来防止执行流跳转到下一个<code>case</code>。</p><h5 id="示例:-6">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">switch</span> (a) {<br> <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:<br> cout << <span class="hljs-string">"One"</span> << endl;<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:<br> cout << <span class="hljs-string">"Two"</span> << endl;<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">default</span>:<br> cout << <span class="hljs-string">"Other"</span> << endl;<br>}<br></code></pre></td></tr></table></figure><h3 id="3-循环结构">(3)循环结构</h3><p>循环结构允许重复执行代码块直到满足特定条件。C++中主要的循环结构有<code>for</code>循环、<code>while</code>循环和<code>do-while</code>循环。</p><h4 id="1-for循环">1. <code>for</code>循环</h4><p>用于在已知循环次数的情况下重复执行代码块。它包括初始化表达式、循环条件和迭代表达式。</p><h5 id="示例:-7">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> cout << i << <span class="hljs-string">" "</span>;<br>}<br></code></pre></td></tr></table></figure><h4 id="2-while循环">2. <code>while</code>循环</h4><p>在循环开始前检查条件,只有条件为真时才执行循环体。</p><h5 id="示例:-8">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> i = <span class="hljs-number">0</span>;<br><span class="hljs-keyword">while</span> (i < <span class="hljs-number">5</span>) {<br> cout << i << <span class="hljs-string">" "</span>;<br> i++;<br>}<br></code></pre></td></tr></table></figure><h4 id="3-do-while循环">3. <code>do-while</code>循环</h4><p>至少执行一次循环体,因为条件检查在循环体之后进行。</p><h5 id="示例:-9">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> i = <span class="hljs-number">0</span>;<br><span class="hljs-keyword">do</span> {<br> cout << i << <span class="hljs-string">" "</span>;<br> i++;<br>} <span class="hljs-keyword">while</span> (i < <span class="hljs-number">5</span>);<br></code></pre></td></tr></table></figure><h2 id="五、高级数据类型">五、高级数据类型</h2><h3 id="1-整型">(1)整型</h3><ul><li><strong><code>int</code></strong>: 用于存储整数。占用通常是4个字节(但这依赖于编译器和计算机架构)。</li><li><strong><code>short</code></strong>: 用于存储较小的整数,通常是2个字节。</li><li><strong><code>long</code></strong>: 用于存储较大的整数,通常是至少4个字节。</li><li><strong><code>long long</code></strong>: 用于存储非常大的整数,通常是8个字节。</li></ul><h3 id="2-浮点型">(2)浮点型</h3><ul><li><strong><code>float</code></strong>: 单精度浮点数。用于存储有小数部分的数字,精度约为7位十进制数字。</li><li><strong><code>double</code></strong>: 双精度浮点数。用于存储大和/或非常精确的浮点数,精度约为15位十进制数字。</li><li><strong><code>long double</code></strong>: 扩展精度浮点数,精度和大小依赖于编译器和计算机架构。</li></ul><h3 id="3-字符型">(3)字符型</h3><ul><li><strong><code>char</code></strong>: 用于存储单个字符,如<code>'a'</code>或<code>'1'</code>。占用1个字节。</li><li><strong><code>wchar_t</code></strong>: 用于存储宽字符,通常用于Unicode字符,大小可能是2或4个字节。</li></ul><h3 id="4-布尔型">(4)布尔型</h3><ul><li><strong><code>bool</code></strong>: 用于表示逻辑值<code>true</code>或<code>false</code>。</li></ul><h3 id="5-其他类型">(5)其他类型</h3><ul><li><strong><code>void</code></strong>: 表示无类型,通常用于指定不返回值的函数的返回类型。</li><li><strong><code>auto</code></strong>: 自动类型推断,允许编译器根据初始化表达式推断变量的类型。</li></ul><h3 id="6-复合数据类型">(6)复合数据类型</h3><h4 id="1-数组">1. 数组</h4><ul><li>用于存储同类型元素的固定大小序列。</li><li>示例:<code>int numbers[10];</code> // 声明一个整型数组,包含10个整数。</li></ul><h4 id="2-结构体">2. 结构体</h4><ul><li>允许将不同的数据类型组合成一个单一实体。</li><li>示例:<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Person</span> {<br> string name;<br> <span class="hljs-type">int</span> age;<br>};<br></code></pre></td></tr></table></figure></li></ul><h4 id="3-联合">3. 联合</h4><ul><li>允许在相同的内存位置存储不同的数据类型,但一次只能使用一个。</li><li>示例:<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">union</span> <span class="hljs-title class_">Data</span> {<br> <span class="hljs-type">int</span> i;<br> <span class="hljs-type">float</span> f;<br> <span class="hljs-type">char</span> str[<span class="hljs-number">20</span>];<br>};<br></code></pre></td></tr></table></figure></li></ul><h4 id="4-枚举">4. 枚举</h4><ul><li>定义一个变量,它可以持有一组整型常数中的任意一个。</li><li>示例:<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">enum</span> <span class="hljs-title class_">Color</span> { red, green, blue };<br></code></pre></td></tr></table></figure></li></ul><h3 id="7-指针">(7)指针</h3><ul><li>存储变量地址的变量,可用于间接访问内存。</li><li>示例:<code>int* ptr = &variable;</code> // <code>ptr</code>现在指向<code>variable</code>的地址。</li></ul><h3 id="8-动态数据结构">(8)动态数据结构</h3><ul><li><strong>动态数组(向量)</strong>:使用<code>std::vector</code>可以动态地增减大小。</li><li><strong>链表</strong>:手动或使用<code>std::list</code>进行管理,允许元素的动态插入和删除。</li></ul><h3 id="9-类">(9)类</h3><ul><li>用户定义的数据类型,允许封装数据和相关操作。</li><li>示例:<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Car</span> {<br> <span class="hljs-keyword">private</span>:<br> string brand;<br> <span class="hljs-type">int</span> year;<br> <span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span></span>;<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span></span>;<br>};<br></code></pre></td></tr></table></figure></li></ul><h2 id="六、函数">六、函数</h2><h3 id="(1)函数的定义和声明">(1)函数的定义和声明</h3><p>函数是执行特定任务的一组语句的集合。函数通常包括返回类型、函数名、参数列表和函数体。</p><h4 id="示例:-10">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-comment">// 函数声明</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)</span></span>;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-type">int</span> result = <span class="hljs-built_in">add</span>(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);<br> cout << <span class="hljs-string">"Sum: "</span> << result << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-comment">// 函数定义</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)</span> </span>{<br> <span class="hljs-keyword">return</span> a + b;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)函数的参数传递">(2)函数的参数传递</h3><h4 id="1-值传递">1. 值传递</h4><p>参数的值传递给函数,不影响原变量。</p><h4 id="2-引用传递">2. 引用传递</h4><p>传递参数的引用,函数内修改会影响原变量。</p><h5 id="示例:-11">示例:</h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">swap</span><span class="hljs-params">(<span class="hljs-type">int</span> &x, <span class="hljs-type">int</span> &y)</span> </span>{<br> <span class="hljs-type">int</span> temp = x;<br> x = y;<br> y = temp;<br>}<br></code></pre></td></tr></table></figure><h3 id="(3)函数的返回值">(3)函数的返回值</h3><p>函数可以返回一个值,可以是基本数据类型、指针、引用或用户定义的类型。</p><h2 id="七、面向对象编程(OOP)">七、面向对象编程(OOP)</h2><h3 id="(1)类和对象">(1)类和对象</h3><p>类是用户定义的类型,用于封装数据和操作。对象是类的实例。</p><h4 id="示例:-12">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Car</span> {<br><span class="hljs-keyword">public</span>:<br> string brand;<br> <span class="hljs-type">int</span> year;<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Driving"</span> << endl;<br> }<br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> Car myCar;<br> myCar.brand = <span class="hljs-string">"Toyota"</span>;<br> myCar.year = <span class="hljs-number">2020</span>;<br> myCar.<span class="hljs-built_in">drive</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)构造函数和析构函数">(2)构造函数和析构函数</h3><p>构造函数在创建对象时初始化对象,析构函数在对象销毁时清理资源。</p><h4 id="示例:-13">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Car</span> {<br><span class="hljs-keyword">public</span>:<br> string brand;<br> <span class="hljs-type">int</span> year;<br><br> <span class="hljs-comment">// 构造函数</span><br> <span class="hljs-built_in">Car</span>(string b, <span class="hljs-type">int</span> y) {<br> brand = b;<br> year = y;<br> }<br><br> <span class="hljs-comment">// 析构函数</span><br> ~<span class="hljs-built_in">Car</span>() {<br> cout << <span class="hljs-string">"Car destroyed"</span> << endl;<br> }<br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">Car <span class="hljs-title">myCar</span><span class="hljs-params">(<span class="hljs-string">"Toyota"</span>, <span class="hljs-number">2020</span>)</span></span>;<br> myCar.<span class="hljs-built_in">drive</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(3)继承">(3)继承</h3><p>继承允许一个类从另一个类继承属性和方法,促进代码重用。</p><h4 id="示例:-14">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Vehicle</span> {<br><span class="hljs-keyword">public</span>:<br> string brand;<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">honk</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Honk!"</span> << endl;<br> }<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Car</span> : <span class="hljs-keyword">public</span> Vehicle {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> year;<br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> Car myCar;<br> myCar.brand = <span class="hljs-string">"Toyota"</span>;<br> myCar.year = <span class="hljs-number">2020</span>;<br> myCar.<span class="hljs-built_in">honk</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(4)多态性">(4)多态性</h3><p>多态性允许不同类的对象通过相同的接口调用各自的方法。</p><h4 id="示例:-15">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Animal</span> {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">sound</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Some sound"</span> << endl;<br> }<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span> : <span class="hljs-keyword">public</span> Animal {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">sound</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span> </span>{<br> cout << <span class="hljs-string">"Bark"</span> << endl;<br> }<br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> Animal *a = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Dog</span>();<br> a-><span class="hljs-built_in">sound</span>(); <span class="hljs-comment">// 输出 "Bark"</span><br> <span class="hljs-keyword">delete</span> a;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="八、标准模板库(STL)">八、标准模板库(STL)</h2><p>STL提供了丰富的数据结构和算法。</p><h3 id="(1)容器">(1)容器</h3><h4 id="1-向量(vector)">1. 向量(vector)</h4><p>动态数组,支持随机访问。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> vector<<span class="hljs-type">int</span>> nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br> nums.<span class="hljs-built_in">push_back</span>(<span class="hljs-number">6</span>);<br> cout << nums[<span class="hljs-number">0</span>] << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h4 id="2-列表(list)">2. 列表(list)</h4><p>双向链表,支持快速插入和删除。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><list></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> list<<span class="hljs-type">int</span>> nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br> nums.<span class="hljs-built_in">push_back</span>(<span class="hljs-number">6</span>);<br> cout << nums.<span class="hljs-built_in">front</span>() << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)迭代器">(2)迭代器</h3><p>迭代器用于遍历容器中的元素。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> vector<<span class="hljs-type">int</span>> nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br> <span class="hljs-keyword">for</span> (vector<<span class="hljs-type">int</span>>::iterator it = nums.<span class="hljs-built_in">begin</span>(); it != nums.<span class="hljs-built_in">end</span>(); ++it) {<br> cout << *it << <span class="hljs-string">" "</span>;<br> }<br> cout << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(3)算法">(3)算法</h3><p>STL提供了多种算法,如排序、查找、复制等。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><algorithm></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> vector<<span class="hljs-type">int</span>> nums = {<span class="hljs-number">5</span>, <span class="hljs-number">2</span>, <span class="hljs-number">9</span>, <span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>};<br> <span class="hljs-built_in">sort</span>(nums.<span class="hljs-built_in">begin</span>(), nums.<span class="hljs-built_in">end</span>());<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> num : nums) {<br> cout << num << <span class="hljs-string">" "</span>;<br> }<br> cout << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="九、异常处理">九、异常处理</h2><p>异常处理用于捕获和处理运行时错误,增强程序的鲁棒性。</p><h3 id="(1)try-catch块">(1)try-catch块</h3><h4 id="示例:-16">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-type">int</span> a = <span class="hljs-number">10</span>;<br> <span class="hljs-type">int</span> b = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">if</span> (b == <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-string">"Division by zero!"</span>;<br> }<br> <span class="hljs-type">int</span> c = a / b;<br> } <span class="hljs-built_in">catch</span> (<span class="hljs-type">const</span> <span class="hljs-type">char</span>* msg) {<br> cerr << <span class="hljs-string">"Error: "</span> << msg << endl;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)自定义异常类">(2)自定义异常类</h3><h4 id="示例:-17">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><exception></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyException</span> : <span class="hljs-keyword">public</span> exception {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">const</span> <span class="hljs-type">char</span>* <span class="hljs-title">what</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> <span class="hljs-title">throw</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"My custom exception"</span>;<br> }<br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-keyword">throw</span> <span class="hljs-built_in">MyException</span>();<br> } <span class="hljs-built_in">catch</span> (MyException& e) {<br> cout << e.<span class="hljs-built_in">what</span>() << endl;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="十、文件操作">十、文件操作</h2><p>文件操作允许程序读取和写入文件。</p><h3 id="(1)文件的读取">(1)文件的读取</h3><h4 id="示例:-18">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><fstream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">ifstream <span class="hljs-title">infile</span><span class="hljs-params">(<span class="hljs-string">"example.txt"</span>)</span></span>;<br> <span class="hljs-keyword">if</span> (infile.<span class="hljs-built_in">is_open</span>()) {<br> string line;<br> <span class="hljs-keyword">while</span> (<span class="hljs-built_in">getline</span>(infile, line)) {<br> cout << line << endl;<br> }<br> infile.<span class="hljs-built_in">close</span>();<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)文件的写入">(2)文件的写入</h3><h4 id="示例:-19">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><fstream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">ofstream <span class="hljs-title">outfile</span><span class="hljs-params">(<span class="hljs-string">"example.txt"</span>)</span></span>;<br> <span class="hljs-keyword">if</span> (outfile.<span class="hljs-built_in">is_open</span>()) {<br> outfile << <span class="hljs-string">"Hello, World!"</span> << endl;<br> outfile.<span class="hljs-built_in">close</span>();<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="十一、多线程编程">十一、多线程编程</h2><p>C++11引入了多线程支持,允许程序并行执行。</p><h3 id="(1)创建线程">(1)创建线程</h3><h4 id="示例:-20">示例:</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><thread></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">threadFunction</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Thread is running"</span> << endl;<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">thread <span class="hljs-title">t</span><span class="hljs-params">(threadFunction)</span></span>;<br> t.<span class="hljs-built_in">join</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(2)线程同步">(2)线程同步</h3><h4 id="互斥锁">互斥锁</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><thread></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br>mutex mtx;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">printThread</span><span class="hljs-params">(<span class="hljs-type">int</span> n)</span> </span>{<br> mtx.<span class="hljs-built_in">lock</span>();<br> cout << <span class="hljs-string">"Thread "</span> << n << <span class="hljs-string">" is running"</span> << endl;<br> mtx.<span class="hljs-built_in">unlock</span>();<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">thread <span class="hljs-title">t1</span><span class="hljs-params">(printThread, <span class="hljs-number">1</span>)</span></span>;<br> <span class="hljs-function">thread <span class="hljs-title">t2</span><span class="hljs-params">(printThread, <span class="hljs-number">2</span>)</span></span>;<br> t1.<span class="hljs-built_in">join</span>();<br> t2.<span class="hljs-built_in">join</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="十二、C-11及更高版本的新特性">十二、C++11及更高版本的新特性</h2><h3 id="(1)auto关键字">(1)auto关键字</h3><p>自动类型推断。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">auto</span> x = <span class="hljs-number">10</span>; <span class="hljs-comment">// int</span><br><span class="hljs-keyword">auto</span> y = <span class="hljs-number">3.14</span>; <span class="hljs-comment">// double</span><br></code></pre></td></tr></table></figure><h3 id="(2)Lambda表达式">(2)Lambda表达式</h3><p>匿名函数。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">auto</span> add = [](<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b) -> <span class="hljs-type">int</span> {<br> <span class="hljs-keyword">return</span> a + b;<br> };<br> cout << <span class="hljs-built_in">add</span>(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>) << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(3)智能指针">(3)智能指针</h3><p>管理动态内存。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><memory></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p1</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(<span class="hljs-number">10</span>))</span></span>;<br> cout << *p1 << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(4)范围for循环">(4)范围for循环</h3><p>遍历容器。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> vector<<span class="hljs-type">int</span>> nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> num : nums) {<br> cout << num << <span class="hljs-string">" "</span>;<br> }<br> cout << endl;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="(5)nullptr关键字">(5)nullptr关键字</h3><p>替代<code>NULL</code>。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span>* p = <span class="hljs-literal">nullptr</span>;<br></code></pre></td></tr></table></figure><h3 id="(6)线程支持库">(6)线程支持库</h3><p>多线程编程。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><thread></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">threadFunction</span><span class="hljs-params">()</span> </span>{<br> cout << <span class="hljs-string">"Thread is running"</span> << endl;<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-function">thread <span class="hljs-title">t</span><span class="hljs-params">(threadFunction)</span></span>;<br> t.<span class="hljs-built_in">join</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>C++基础</category>
</categories>
<tags>
<tag>编程基础</tag>
<tag>C++</tag>
<tag>语言基础</tag>
</tags>
</entry>
<entry>
<title>编程基础——C++开发与学习环境搭建</title>
<link href="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
<url>/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</url>
<content type="html"><![CDATA[<h1>C++开发与学习环境搭建</h1><blockquote><p>零门槛初识C++,用最简单的方式开始自己的第一行代码。</p></blockquote><h2 id="一、下载编译器-IDE-文本编辑器">一、下载编译器/IDE/文本编辑器</h2><p>为了方便起见,微软的经典集成开发环境Visual C++ 6.0非常适合入门,这里提供<a href="https://wwt.lanzouw.com/iV5Qp25s8xjg">下载链接</a>。</p><h2 id="二、安装Visual-C-6-0">二、安装Visual C++ 6.0</h2><p>1.双击安装包运行安装程序</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/1.png" class="" title="无描述"><p>2.点击下一步</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/2.png" class="" title="无描述"><p>3.修改安装路径,如果不想安装到C盘自行进行修改</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/3.png" class="" title="无描述"><p>4.快捷方式的勾默认打上,点击下一步</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/4.png" class="" title="无描述"><p>5.点击安装</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/5.png" class="" title="无描述"><p>6.安装完成点击完成,此时软件主界面应打开</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/6.png" class="" title="无描述"><p>7.主页面如下图</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/7.png" class="" title="无描述"><h2 id="三、创建项目">三、创建项目</h2><p>一个项目代表一个程序。</p><p>1.点击左上角FIle->New</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/8.png" class="" title="无描述"><p>2.在弹出窗口中选择Project->Win32 Console Applications</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/9.png" class="" title="无描述"><p>3.在窗口右侧给项目起名字,并为项目选择路径,路径默认即可。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/10.png" class="" title="无描述"><p>4.下面的页面一般选择第一个即可,但我们这里选择第三个,因为第三个选项内置了几行代码。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/11.png" class="" title="无描述"><p>5.下面点击OK</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/12.png" class="" title="无描述"><p>6.进入代码编辑页面</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/13.png" class="" title="无描述"><h2 id="四、界面-窗口介绍">四、界面/窗口介绍</h2><p>点击下方图中File View可以查看项目的文件,C++语言的代码一般头文件使用.hpp或者.h后缀,源程序本体则是.cpp,至于什么是头文件,与.cpp文件有什么区别,后面便知道。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/14.png" class="" title="无描述"><p>屏幕左侧显示文件,屏幕右侧显示代码编辑窗口,屏幕上方是菜单和工具栏。</p><h2 id="五、运行代码">五、运行代码</h2><p>点击上方菜单中的Build->Execute test1.exe即可执行编写的代码。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/17.png" class="" title="无描述"><p>如果弹出下面的窗口点击是即可,这个窗口的含义是还没有编译程序,是否进行编译。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/18.png" class="" title="无描述"><p>如出现兼容性问题如下图,勾选<code>不再显示此消息</code>后点击<code>运行而不获取帮助</code>即可运行。</p><img src="/2024/07/28/%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94C-%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/19.png" class="" title="无描述">]]></content>
<categories>
<category>C++基础</category>
</categories>
<tags>
<tag>编程基础</tag>
<tag>C++</tag>
<tag>开发环境</tag>
</tags>
</entry>
<entry>
<title>数据结构——源代码合集</title>
<link href="/2024/07/27/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%BA%90%E4%BB%A3%E7%A0%81%E5%90%88%E9%9B%86/"/>
<url>/2024/07/27/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%BA%90%E4%BB%A3%E7%A0%81%E5%90%88%E9%9B%86/</url>
<content type="html"><![CDATA[<h1>数据结构源代码合集</h1><h2 id="一、线性表">一、线性表</h2><blockquote><p>其他介绍详见<a href="https://blog.cxhap.top/2024/07/23/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%BA%BF%E6%80%A7%E8%A1%A8/">数据结构——线性表</a>。</p></blockquote><h3 id="(1)顺序表">(1)顺序表</h3><h4 id="静态分配">静态分配</h4> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-8f7bdefe" role="button" aria-expanded="false" aria-controls="collapse-8f7bdefe"> <div class="fold-arrow">▶</div>title </div> <div class="fold-collapse collapse" id="collapse-8f7bdefe"> <div class="fold-content"> <figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-comment">// 静态分配顺序表</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> MaxSize 10</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SqList</span> {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> data[MaxSize];<br> <span class="hljs-type">int</span> length;<br><br> <span class="hljs-built_in">SqList</span>() {<br> length = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < MaxSize; ++i) {<br> data[i] = <span class="hljs-number">0</span>;<br> }<br> }<br>};<br><br> <span class="hljs-comment">// 函数声明</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 初始化</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroyList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 销毁</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 重置为空表</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintList</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 打印</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListEmpty</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 判空</span><br> <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 获取长度</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 按位查找</span><br> <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 按值查找</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span></span>; <span class="hljs-comment">// 查找前驱</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span></span>; <span class="hljs-comment">// 查找后继</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 插入</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 删除</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span></span>; <span class="hljs-comment">// 遍历</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">LocateChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> e, <span class="hljs-type">int</span> em)</span></span>; <span class="hljs-comment">// 先按值查找后改值</span><br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> em)</span></span>; <span class="hljs-comment">// 先按位序查找后改值</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">testModule</span><span class="hljs-params">()</span></span>; <span class="hljs-comment">// 测试模块</span><br><br> <span class="hljs-comment">// 实现模块</span><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> L.length = <span class="hljs-number">0</span>;<br> }<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroyList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> <span class="hljs-comment">// 静态分配,无需显式销毁</span><br> }<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> L.length = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < MaxSize; ++i) {<br> L.data[i] = <span class="hljs-number">0</span>;<br> }<br> }<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintList</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> std::cout << <span class="hljs-string">"开始打印顺序表\n"</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> std::cout << <span class="hljs-string">"Data["</span> << i << <span class="hljs-string">"]=="</span> << L.data[i] << <span class="hljs-string">"\n"</span>;<br> }<br> std::cout << <span class="hljs-string">"打印结束!\n"</span>;<br> }<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListEmpty</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length == <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> }<br> e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == e)<br> <span class="hljs-keyword">return</span> i + <span class="hljs-number">1</span>; <span class="hljs-comment">// 返回位序</span><br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; <span class="hljs-comment">// 未找到返回0</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">1</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> pre_e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length - <span class="hljs-number">1</span>; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> next_e = L.data[i + <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length + <span class="hljs-number">1</span> || L.length >= MaxSize)<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> <br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = L.length; j >= i; --j) {<br> L.data[j] = L.data[j - <span class="hljs-number">1</span>];<br> }<br> L.data[i - <span class="hljs-number">1</span>] = e;<br> L.length++;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> }<br> e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = i; j < L.length; ++j) {<br> L.data[j - <span class="hljs-number">1</span>] = L.data[j];<br> }<br> L.length--;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-built_in">visit</span>(L.data[i]);<br> }<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">LocateChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> e, <span class="hljs-type">int</span> em)</span> </span>{<br> <span class="hljs-type">int</span> bitOrder = <span class="hljs-built_in">LocateElem</span>(L, e);<br> <span class="hljs-keyword">if</span> (bitOrder != <span class="hljs-number">0</span>) {<br> L.data[bitOrder - <span class="hljs-number">1</span>] = em;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> em)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">0</span> || i >= L.length) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> L.data[i] = em;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">visit</span><span class="hljs-params">(<span class="hljs-type">int</span> a)</span></span>{<br> std::cout<<a<<std::endl;<br>}<br><br><span class="hljs-comment">// 测试模块</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">testModule</span><span class="hljs-params">()</span> </span>{<br> SqList L;<br> <span class="hljs-built_in">InitList</span>(L);<br><br> <span class="hljs-comment">// 初始化一些值</span><br> <span class="hljs-built_in">ListInsert</span>(L, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>);<br> <span class="hljs-built_in">ListInsert</span>(L, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>);<br> <span class="hljs-built_in">ListInsert</span>(L, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>);<br><br> <span class="hljs-comment">// 插入操作</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">ListInsert</span>(L, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>)) {<br> std::cout << <span class="hljs-string">"插入成功了\n"</span>;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"插入失败了,i的位置不合法,请检查\n"</span>;<br> }<br><br> <span class="hljs-comment">// 删除操作</span><br> <span class="hljs-type">int</span> e = <span class="hljs-number">-1</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">ListDelete</span>(L, <span class="hljs-number">2</span>, e)) {<br> std::cout << <span class="hljs-string">"删除成功!删除的值是:"</span> << e << <span class="hljs-string">"\n"</span>;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"删除失败,请检查位序是否正确\n"</span>;<br> }<br><br> <span class="hljs-comment">// 数组当前长度</span><br> std::cout << <span class="hljs-string">"数组当前长度是多少?"</span> << <span class="hljs-built_in">ListLength</span>(L) << <span class="hljs-string">"\n"</span>;<br><br> <span class="hljs-comment">// 查找第一个元素是什么?</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">GetElem</span>(L, <span class="hljs-number">1</span>, e)) {<br> std::cout << <span class="hljs-string">"第一个元素是:"</span> << e << <span class="hljs-string">"\n"</span>;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"查找失败,位置不合法\n"</span>;<br> }<br><br> <span class="hljs-comment">// 查找值为3的元素在什么位置</span><br> std::cout << <span class="hljs-string">"第一个值为3的元素在什么位置?"</span> << <span class="hljs-built_in">LocateElem</span>(L, <span class="hljs-number">3</span>) << <span class="hljs-string">"\n"</span>;<br><br> <span class="hljs-comment">// 打印输出</span><br> <span class="hljs-built_in">PrintList</span>(L);<br><br> <span class="hljs-comment">// 测试改模块功能是否正常</span><br> <span class="hljs-type">int</span> e1 = <span class="hljs-number">2</span>;<br> <span class="hljs-type">int</span> em1 = <span class="hljs-number">6</span>;<br> <span class="hljs-type">int</span> i = <span class="hljs-number">1</span>;<br> <span class="hljs-type">int</span> em2 = <span class="hljs-number">7</span>;<br> std::cout << <span class="hljs-string">"开始测试【改】\n"</span><br> << <span class="hljs-string">"第一种方式先按值查找后改值\n"</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">LocateChangeElem</span>(L, e1, em1)) {<br> std::cout << <span class="hljs-string">"第一种先按值查找后改值成功啦,改变后的值如下:\n"</span>;<br> <span class="hljs-built_in">PrintList</span>(L);<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"第一种先按值查找后改值失败了,再检查一下吧!\n"</span>;<br> }<br> std::cout << <span class="hljs-string">"第二种先按位序查找后改值\n"</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">GetChangeElem</span>(L, i, em2)) {<br> std::cout << <span class="hljs-string">"第二种先按位序查找后改值的方式成功啦,改变后的值如下:\n"</span>;<br> <span class="hljs-built_in">PrintList</span>(L);<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"第二种先按位序查找后改值的方式失败了,再检查一下吧!\n"</span>;<br> }<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">ListEmpty</span>(L)) {<br> std::cout << <span class="hljs-string">"顺序表为空!\n"</span>;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"顺序表非空!\n"</span>;<br> }<br><br> <span class="hljs-comment">// 打印输出</span><br> <span class="hljs-built_in">PrintList</span>(L);<br> <span class="hljs-built_in">ListTraverse</span>(L,visit);<br>}<br><br><span class="hljs-comment">// 主函数</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-built_in">testModule</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></td></tr></table></figure> </div> </div> </div><h4 id="动态分配">动态分配</h4> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-dcdac752" role="button" aria-expanded="false" aria-controls="collapse-dcdac752"> <div class="fold-arrow">▶</div>title </div> <div class="fold-collapse collapse" id="collapse-dcdac752"> <div class="fold-content"> <figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-comment">// 动态分配顺序表</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> InitSize 10</span><br><br> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SeqList</span> {<br> <span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> *data; <span class="hljs-comment">// 指示动态分配数组的指针</span><br> <span class="hljs-type">int</span> MaxSize; <span class="hljs-comment">// 顺序表的最大容量</span><br> <span class="hljs-type">int</span> length; <span class="hljs-comment">// 顺序表当前的长度</span><br><br> <span class="hljs-built_in">SeqList</span>() : <span class="hljs-built_in">data</span>(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[InitSize]), <span class="hljs-built_in">MaxSize</span>(InitSize), <span class="hljs-built_in">length</span>(<span class="hljs-number">0</span>) {}<br> ~<span class="hljs-built_in">SeqList</span>() {<br> <span class="hljs-keyword">delete</span>[] data;<br> }<br> };<br><br><span class="hljs-comment">// 函数声明</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 初始化</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Empty</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 判空</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Full</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 判满</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">IncreaseSize</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> len)</span></span>; <span class="hljs-comment">// 动态扩展空间</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 插入</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> i)</span></span>; <span class="hljs-comment">// 按位查找</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 按值查找</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 删除</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroySqList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 销毁</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 清空</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 获取长度</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span></span>; <span class="hljs-comment">// 查找前驱</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span></span>; <span class="hljs-comment">// 查找后继</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span></span>; <span class="hljs-comment">// 遍历</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintSqList</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 打印顺序表</span><br><br><span class="hljs-comment">// 实现模块</span><br><br><span class="hljs-comment">// 初始化</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SeqList &L)</span> </span>{<br> L.data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[InitSize]; <br> <span class="hljs-keyword">if</span> (L.data == <span class="hljs-literal">nullptr</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> L.length = <span class="hljs-number">0</span>;<br> L.MaxSize = InitSize;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-comment">// 判空</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Empty</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length == <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-comment">// 判满</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Full</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length >= L.MaxSize;<br>}<br><br><span class="hljs-comment">// 扩展空间</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">IncreaseSize</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> len)</span> </span>{<br> std::cout << <span class="hljs-string">"开始扩展表存储空间..."</span> << std::endl;<br> <span class="hljs-type">int</span> *p = L.data;<br> L.data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[L.MaxSize + len];<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> L.data[i] = p[i];<br> }<br> L.MaxSize += len;<br> <span class="hljs-keyword">delete</span>[] p;<br> std::cout << <span class="hljs-string">"扩展完成,当前最大容量: "</span> << L.MaxSize << std::endl;<br>}<br><br><span class="hljs-comment">// 插入</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length + <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Full</span>(L)) <span class="hljs-built_in">IncreaseSize</span>(L, InitSize);<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = L.length; j >= i; --j) {<br> L.data[j] = L.data[j - <span class="hljs-number">1</span>];<br> }<br> L.data[i - <span class="hljs-number">1</span>] = e;<br> L.length++;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-comment">// 按位查找</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> i)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br> <span class="hljs-keyword">return</span> L.data[i - <span class="hljs-number">1</span>];<br>}<br><br><span class="hljs-comment">// 按值查找</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == e) <span class="hljs-keyword">return</span> i + <span class="hljs-number">1</span>;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br>}<br><br><span class="hljs-comment">// 删除</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = i; j < L.length; ++j) {<br> L.data[j - <span class="hljs-number">1</span>] = L.data[j];<br> }<br> L.length--;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-comment">// 销毁</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroySqList</span><span class="hljs-params">(SeqList &L)</span> </span>{<br> <span class="hljs-keyword">delete</span>[] L.data;<br> L.data = <span class="hljs-literal">nullptr</span>;<br> L.length = <span class="hljs-number">0</span>;<br> L.MaxSize = <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-comment">// 清空</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SeqList &L)</span> </span>{<br> L.length = <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-comment">// 获取长度</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length;<br>}<br><br><span class="hljs-comment">// 查找前驱</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">1</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> pre_e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-comment">// 查找后继</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length - <span class="hljs-number">1</span>; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> next_e = L.data[i + <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-comment">// 遍历</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-built_in">visit</span>(L.data[i]);<br> }<br>}<br><br><span class="hljs-comment">// 打印顺序表</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintSqList</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span> </span>{<br> <span class="hljs-keyword">if</span> (L.data == <span class="hljs-literal">nullptr</span> || L.length == <span class="hljs-number">0</span>) {<br> std::cout << <span class="hljs-string">"这是一个空表!"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"开始打印顺序表"</span> << std::endl;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> std::cout << <span class="hljs-string">"Data["</span> << i << <span class="hljs-string">"] == "</span> << L.data[i] << std::endl;<br> }<br> std::cout << <span class="hljs-string">"打印结束!"</span> << std::endl;<br> }<br>}<br><br><span class="hljs-comment">// 测试输出</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">TestPrint</span><span class="hljs-params">(<span class="hljs-type">bool</span> test, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *message)</span> </span>{<br> <span class="hljs-keyword">if</span> (test) {<br> std::cout << message << <span class="hljs-string">"成功啦!"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << message << <span class="hljs-string">"失败啦!"</span> << std::endl;<br> }<br>}<br><br><span class="hljs-comment">// 访问函数</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">visit</span><span class="hljs-params">(<span class="hljs-type">int</span> elem)</span> </span>{<br> std::cout << elem << <span class="hljs-string">" "</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">testModule</span><span class="hljs-params">()</span> </span>{<br> SeqList L;<br> <span class="hljs-built_in">TestPrint</span>(<span class="hljs-built_in">InitList</span>(L), <span class="hljs-string">"初始化"</span>);<br><br> <span class="hljs-comment">// 测试插入和打印</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">1</span>; i <= <span class="hljs-number">5</span>; ++i) {<br> <span class="hljs-built_in">TestPrint</span>(<span class="hljs-built_in">ListInsert</span>(L, i, i), <span class="hljs-string">"插入"</span>);<br> }<br> <span class="hljs-built_in">PrintSqList</span>(L);<br><br> <span class="hljs-comment">// 测试按位查找</span><br> std::cout << <span class="hljs-string">"第3个元素是: "</span> << <span class="hljs-built_in">GetElem</span>(L, <span class="hljs-number">3</span>) << std::endl;<br><br> <span class="hljs-comment">// 测试按值查找</span><br> std::cout << <span class="hljs-string">"值为4的元素的位序是: "</span> << <span class="hljs-built_in">LocateElem</span>(L, <span class="hljs-number">4</span>) << std::endl;<br><br> <span class="hljs-comment">// 测试删除</span><br> <span class="hljs-type">int</span> e;<br> <span class="hljs-built_in">TestPrint</span>(<span class="hljs-built_in">ListDelete</span>(L, <span class="hljs-number">2</span>, e), <span class="hljs-string">"删除"</span>);<br> std::cout << <span class="hljs-string">"删除的元素是: "</span> << e << std::endl;<br> <span class="hljs-built_in">PrintSqList</span>(L);<br><br> <span class="hljs-comment">// 测试清空</span><br> <span class="hljs-built_in">ClearList</span>(L);<br> <span class="hljs-built_in">TestPrint</span>(<span class="hljs-built_in">Empty</span>(L), <span class="hljs-string">"清空"</span>);<br> <span class="hljs-built_in">PrintSqList</span>(L);<br><br> <span class="hljs-comment">// 重新插入测试PriorElem和NextElem</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">1</span>; i <= <span class="hljs-number">5</span>; ++i) {<br> <span class="hljs-built_in">ListInsert</span>(L, i, i);<br> }<br> <span class="hljs-type">int</span> pre_e, next_e;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">PriorElem</span>(L, <span class="hljs-number">3</span>, pre_e)) {<br> std::cout << <span class="hljs-string">"元素3的前驱是: "</span> << pre_e << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"没有前驱元素"</span> << std::endl;<br> }<br><br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">NextElem</span>(L, <span class="hljs-number">3</span>, next_e)) {<br> std::cout << <span class="hljs-string">"元素3的后继是: "</span> << next_e << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"没有后继元素"</span> << std::endl;<br> }<br><br> <span class="hljs-comment">// 测试遍历</span><br> std::cout << <span class="hljs-string">"遍历顺序表: "</span>;<br> <span class="hljs-built_in">ListTraverse</span>(L, visit);<br> std::cout << std::endl;<br><br> <span class="hljs-comment">// 测试获取长度</span><br> std::cout << <span class="hljs-string">"顺序表长度是: "</span> << <span class="hljs-built_in">ListLength</span>(L) << std::endl;<br><br> <span class="hljs-comment">// 测试销毁</span><br> <span class="hljs-built_in">DestroySqList</span>(L);<br> <span class="hljs-built_in">TestPrint</span>(<span class="hljs-built_in">Empty</span>(L), <span class="hljs-string">"销毁"</span>);<br> <span class="hljs-built_in">PrintSqList</span>(L);<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-built_in">testModule</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></td></tr></table></figure> </div> </div> </div>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
</tags>
</entry>
<entry>
<title>组合数学——利用差分序列求高次数列前n项和</title>
<link href="/2024/07/26/%E7%BB%84%E5%90%88%E6%95%B0%E5%AD%A6%E2%80%94%E2%80%94%E5%88%A9%E7%94%A8%E5%B7%AE%E5%88%86%E5%BA%8F%E5%88%97%E6%B1%82%E9%AB%98%E6%AC%A1%E6%95%B0%E5%88%97%E5%89%8Dn%E9%A1%B9%E5%92%8C/"/>
<url>/2024/07/26/%E7%BB%84%E5%90%88%E6%95%B0%E5%AD%A6%E2%80%94%E2%80%94%E5%88%A9%E7%94%A8%E5%B7%AE%E5%88%86%E5%BA%8F%E5%88%97%E6%B1%82%E9%AB%98%E6%AC%A1%E6%95%B0%E5%88%97%E5%89%8Dn%E9%A1%B9%E5%92%8C/</url>
<content type="html"><![CDATA[<h1>利用差分序列求高次数列前n项和</h1><p>内容来自《组合数学》第五版(布鲁迪,冯速)。</p><p>这种方式求前n项和某些情况下十分好用,仅仅是自己在想到这个公式将使用时找不到相关资料,决定将书本截图保存至此,不多做解释。</p><p><img src="1.jpg" alt="1"></p><p><img src="2.jpg" alt="2"></p><p><img src="3.jpg" alt="3"></p><p><img src="4.jpg" alt="4"></p><p><img src="5.jpg" alt="5"></p><p><img src="6.jpg" alt="6"></p>]]></content>
<categories>
<category>组合数学</category>
</categories>
<tags>
<tag>数列求和</tag>
<tag>组合数学</tag>
<tag>差分序列</tag>
</tags>
</entry>
<entry>
<title>数据结构——算法效率的度量</title>
<link href="/2024/07/25/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%AE%97%E6%B3%95%E6%95%88%E7%8E%87%E7%9A%84%E5%BA%A6%E9%87%8F/"/>
<url>/2024/07/25/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%AE%97%E6%B3%95%E6%95%88%E7%8E%87%E7%9A%84%E5%BA%A6%E9%87%8F/</url>
<content type="html"><![CDATA[<h1>算法效率的度量</h1><blockquote><p>在这之前,首先介绍算法的五大特性与算法设计的要求。</p><p>五大特性</p><ol><li>有穷性:在有穷操作内完成</li><li>确定性:算法只有唯一的执行路径,每一种输入对应唯一的输出</li><li>可行性:算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的。</li><li>输入:零个或多个输入</li><li>输出:一个或多个输出</li></ol><p>算法设计的要求</p><ol><li>正确性</li><li>可读性</li><li>健壮性</li><li>效率与低存储量需求</li></ol></blockquote><p>算法效率的度量主要是通过时间维度和空间维度来考量的。</p><ul><li><p>时间维度:是指执行当前算法所消耗的时间,我们通常用<strong>时间复杂度</strong>来描述。</p></li><li><p>空间维度:是指执行当前算法需要占用多少内存空间,我们通常用<strong>空间复杂度</strong>来描述。</p></li></ul><p>通常情况下,算法的时间消耗和空间消耗是二者不可兼得的关系,因此要求我们在编写算法时根据实际情况仔细斟酌。</p><h2 id="一、时间复杂度">一、时间复杂度</h2><p>算法执行时间通过使用该算法编制程序在计算机上所消耗的时间来度量,而度量一个程序的执行时间通常有两种方法。</p><h3 id="(1)事后统计的方法">(1)事后统计的方法</h3><p>目前计算机操作系统所提供的统计方法已经将时间精确到毫秒级,通过比较程序统计的执行时间长短即可比较出算法的时间复杂度。但这种方法有两个缺陷,一是统计时间依赖运行程序来测量,无法通过算法直接得出结果;二是所得时间的统计量依赖于计算机硬件、软件等环境因素,在不同的条件下执行结果并不一致。因此人们更长使用另一种事前估计的方法。</p><h3 id="(2)事前分析估算的方法">(2)事前分析估算的方法</h3><p>同一种算法用不用的语言实现,或者用不同的编译程序进行编译,或者在不同的计算机运行,再或者问题的规模不同,这些因素都会导致算法的执行时间不尽相同,这表明使用绝对的时间量度来衡量算法的效率是不合适的。因此我们需要一种相对的衡量方法,只取决于问题的规模n来决定,或者是,他是问题规模的函数。为了便于比较同一问题的不同算法,通常的做法是,从算法中选取一种对于所研究的问题(或算法类型)来说是基本操作的原操作,以该基本操作重复执行的次数作为算法的时间量度。</p><p>一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>,算法的时间量度记为</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">T(n)=O(f(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></span></p><p>它表示随问题规模n增大,算法执行时间的增长率和<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>的增长率相同,称作算法的<strong>渐进时间复杂度</strong>,简称<strong>时间复杂度</strong>。式中,<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi></mrow><annotation encoding="application/x-tex">O</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span></span></span></span>的含义是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">T(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>的数量级。</p><p>算法的时间复杂度不仅仅依赖于问题的规模,还取决于待输入的数据。例如在数组A[0:n-1]中,查找定值K的算法如下:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">findK</span><span class="hljs-params">(<span class="hljs-type">int</span> A[], <span class="hljs-type">int</span> n, <span class="hljs-type">int</span> k)</span></span><br><span class="hljs-function"></span>{<br><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<n;i++){<br> <span class="hljs-keyword">if</span> (A[i]==k){<br> <span class="hljs-keyword">return</span> i;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>; <span class="hljs-comment">// 找不到返回-1</span><br>}<br></code></pre></td></tr></table></figure><blockquote><p>语句的频度是指语句重复执行的次数。</p></blockquote><p>对于这个程序来说,若A中没有与K相等的数据,则i++语句频度为n,循环执行n次;若第0个数据为k,则i++频度为0,循环仅执行1次。</p><p>最坏时间复杂度是指在最坏情况下,算法的时间复杂度,对应上述算法中最后一次循环找到k或数组中没有K的情况;最好时间复杂度是指在最好的情况下,算法的时间复杂度,对应上述算法第一次循环便找到了K;平均时间复杂度是指在所有可能输入实例在等概率出现的情况下,算法的期望运行时间。一般总是考虑在<strong>最坏的情况下</strong>的时间复杂度,以保证算法的运行时间不会比它更长。</p><p>对于上面的算法,它的时间复杂度为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>,即最坏情况下需要遍历整个数组才能找到目标元素,或者确认目标元素不存在。对于一个<strong>无序数组</strong>来说,这已经是最优的线性搜索算法了,因为在最坏情况下你必须检查每个元素才能确定k是否在数组中。但如果这个数组是<strong>有序数组</strong>,则二分查找的算法有着更高的效率。</p><p>以下是一个基于二分查找的优化算法(假设数组是有序的):</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">findK</span><span class="hljs-params">(<span class="hljs-type">int</span> A[], <span class="hljs-type">int</span> n, <span class="hljs-type">int</span> k)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-type">int</span> left = <span class="hljs-number">0</span>;<br> <span class="hljs-type">int</span> right = n - <span class="hljs-number">1</span>;<br> <br> <span class="hljs-keyword">while</span> (left <= right) {<br> <span class="hljs-type">int</span> mid = left + (right - left) / <span class="hljs-number">2</span>;<br> <span class="hljs-keyword">if</span> (A[mid] == k) {<br> <span class="hljs-keyword">return</span> mid;<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (A[mid] < k) {<br> left = mid + <span class="hljs-number">1</span>;<br> } <span class="hljs-keyword">else</span> {<br> right = mid - <span class="hljs-number">1</span>;<br> }<br> }<br> <br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br>}<br><br></code></pre></td></tr></table></figure><p>二分查找每次迭代将搜索区间减半,每次迭代缩小到原先二分之一的范围,经过<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log_2(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>次迭代后搜索区间缩小到1,因此时间复杂度是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo></mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>。</p><h4 id="规则">规则</h4><p>在分析一个程序的时间复杂性时,有两条规则:</p><ol><li>加法规则:<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>T</mi><mn>1</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>+</mo><msub><mi>T</mi><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>+</mo><mi>O</mi><mo stretchy="false">(</mo><mi>g</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>m</mi><mi>a</mi><mi>x</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo separator="true">,</mo><mi>g</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">T(n)=T_1(n)+T_2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n)))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">ma</span><span class="mord mathnormal">x</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)))</span></span></span></span></li><li>乘法规则:<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>T</mi><mn>1</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>×</mo><msub><mi>T</mi><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>×</mo><mi>O</mi><mo stretchy="false">(</mo><mi>g</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>×</mo><mi>g</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">T(n)=T_1(n) \times T_2(n)=O(f(n)) \times O(g(n))=O(f(n) \times g(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></li></ol><p>例如:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<n;i++){<br>程序段<span class="hljs-number">1</span>;<br>}<br><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j=<span class="hljs-number">0</span>;j<n;j++){<br>程序段<span class="hljs-number">2</span>;<br>}<br></code></pre></td></tr></table></figure><p>因此上述程序时间复杂度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>+</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n)+O(n)=O(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<n;i++){<br>程序段<span class="hljs-number">1</span>;<br><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j=<span class="hljs-number">0</span>;j<n;j++){<br>程序段<span class="hljs-number">2</span>;<br>}<br>}<br></code></pre></td></tr></table></figure><p>因此上述程序时间复杂度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mi>t</mi><mi>i</mi><mi>m</mi><mi>e</mi><mi>s</mi><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n) /times O(n)=O(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mord">/</span><span class="mord mathnormal">t</span><span class="mord mathnormal">im</span><span class="mord mathnormal">es</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<n;i++){<br>程序段<span class="hljs-number">1</span>;<br><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j=<span class="hljs-number">0</span>;j<n;j++){<br>程序段<span class="hljs-number">2</span>;<br>}<br>}<br><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j=<span class="hljs-number">0</span>;j<n;j++){<br>程序段<span class="hljs-number">2</span>;<br>}<br></code></pre></td></tr></table></figure><p>因此上述程序时间复杂度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo>+</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n^2) + O(n)=O(n^2)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>。</p><p>在进行加法运算时,若将高时间复杂度的算法与低时间复杂度的相加,则取较高的项。<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mi>n</mi><mn>3</mn></msup><mo>+</mo><msup><mi>n</mi><mn>2</mn></msup><mo>+</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">f(n)=n^3+n^2+n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8974em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8974em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>的时间复杂度取<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>3</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n^3)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>。</p><h4 id="常见的渐进时间复杂度">常见的渐进时间复杂度</h4><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><mi>l</mi><mi>o</mi><mi>g</mi><mi>n</mi><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mi>l</mi><mi>o</mi><mi>g</mi><mi>n</mi><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>3</mn></msup><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mn>2</mn><mi>n</mi></msup><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">!</mo><mo stretchy="false">)</mo><mo><</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mi>n</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(1)<O(log n)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.1141em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.1141em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">!)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><h3 id="(3)为什么时间复杂度是-log-n-而不是-log-2-n-呢?">(3)为什么时间复杂度是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>而不是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log_2(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>呢?</h3><p>在大 O 表示法中,常数因子和常数项通常被省略。这是因为大 O 表示法旨在描述算法复杂度的增长速率,而不是具体的计算步骤或常数倍数。因此, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log_2(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span> 被认为是等价的。</p><h4 id="对数的底数转换">对数的底数转换</h4><p>对数的底数转换公式为:</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mi>a</mi></msub><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mi>b</mi></msub><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mi>b</mi></msub><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">\log_a(x) = \frac{\log_b(x)}{\log_b(a)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>如果我们将对数的底数从 2 换成 10 或任何其他常数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi></mrow><annotation encoding="application/x-tex">c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">c</span></span></span></span>,可以看到:</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><mrow><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">\log_2(n) = \frac{\log(n)}{\log(2)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord">2</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>由于 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log(2)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord">2</span><span class="mclose">)</span></span></span></span> 是一个常数,所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log_2(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\log(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span> 之间仅仅相差一个常数倍。大 O 表示法忽略这些常数因子,因此:</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log_2(n)) = O(\log(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></span></p><h4 id="大-O-表示法的性质">大 O 表示法的性质</h4><blockquote></blockquote><p>大 O 表示法关心的是当 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> 变得非常大时,算法的增长趋势。因此,常数因子和低阶项都可以忽略。例如,以下所有时间复杂度都是等价的:</p><blockquote></blockquote><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>2</mn><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(2\log(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>3</mn><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>+</mo><mn>5</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(3\log(n) + 5)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord">3</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">5</span><span class="mclose">)</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msub><mrow><mi>log</mi><mo></mo></mrow><mn>2</mn></msub><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log_2(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop"><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></li></ul><p>它们都简化为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo></mo><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(\log(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right:0.01389em;">g</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span>。</p><h2 id="二、空间复杂度">二、空间复杂度</h2><p>类似于时间复杂度,我们用空间复杂度作为算法所需存储空间的量度,记作</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>S</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">S(n)=O(f(n))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">))</span></span></span></span></span></p><p>其中n为问题的规模(或大小)。一个上机执行的程序除了需要存储空间来寄存本身所用指令、常数、变量和输入数据外,也需要一些对数据进行操作的工作单元和存储一些为实现计算所需信息的辅助空间。若输人数据所占空间只取决于问题本身,和算法无关,则只需要分析除输人和程序之外的额外空间,否则应同时考虑输人本身所需空间(和输入数据的表示形式有关)。若额外空间相对于输人数据量来说是常数,则称此算法为原地工作,后面讨论的有些排序算法就属于这类。又如果所占空间量依赖于特定的输入,则除特别指明外,均按<strong>最坏情况</strong>来分析。</p>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>大O表示法</tag>
</tags>
</entry>
<entry>
<title>数据结构——线性表</title>
<link href="/2024/07/23/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%BA%BF%E6%80%A7%E8%A1%A8/"/>
<url>/2024/07/23/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%BA%BF%E6%80%A7%E8%A1%A8/</url>
<content type="html"><![CDATA[<h1>线性表</h1><blockquote><p>线性结构的特点是:在数据元素的非空有限集中,(1)存在唯一的一个被称做“第一个”的数据元素;(2)存在唯一的一个被称做“最后一个”的数据元素;(3)除第一个之外,集合中的每个数据元素均只有一个前驱;(4)除最后一个之外,集合中每个数据元素均只有一个后继。</p></blockquote><h2 id="一、线性表的基本概念">一、线性表的基本概念</h2><h3 id="(一)线性表的定义">(一)线性表的定义</h3><p>线性表是由n个具有相同数据类型的数据元素组成的有限序列。其中n>=0,n为表长,当n为0时线性表是一个空表,若用L命名线性表,则其一般表示为:</p><center>L=(a<sub>1</sub>, a<sub>2</sub>, a<sub>3</sub>, …, a<sub>i</sub>, …, a<sub>n</sub>)</center><p>式中,a<sub>1</sub>是唯一的“第一个”数据元素,又称表头元素;a<sub>n</sub>是唯一的“最后一个”数据元素,又称表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后继(“直接前驱”和“前驱”、“直接后继”和“后继”通常被视为同义词)。</p><p>在稍复杂的线性表中,一个数据元素可以由若干个<strong>数据项</strong>(item)组成。在这种情况下,常把数据元素称为<strong>记录</strong>(record),含有大量记录的线性表又称<strong>文件</strong>(file)。</p><p>以上就是线性表的逻辑特性,这种线性有序的逻辑结构正是线性表名字的由来。</p><p>由此,我们得出线性表的特点如下:</p><ul><li>表中元素的个数有限。</li><li>表中元素具有逻辑上的顺序性,表中元素有其先后次序。</li><li>表中元素都是数据元素,每个元素都是单个元素。</li><li>表中元素的数据类型都相同,这意味着每个元素占有相同大小的存储空间。</li><li>表中元素具有抽象性,即仅讨论元素间的逻辑关系,而不考虑元素究竟表示什么内容。</li></ul><h3 id="(二)线性表的基本操作">(二)线性表的基本操作</h3><p>抽象数据类型线性表的定义如下:</p><pre><code class="hljs"><figure class="highlight xquery"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><code class="hljs xquery">ADT List {<br> 数据对象:D = { a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span> | a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span> ∈ ElemSet, i = <span class="hljs-number">1</span>,<span class="hljs-number">2</span>,…,n, n>=<span class="hljs-number">0</span> }<br> 数据关系:R1 = ( <a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i-1<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span>, a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span>> | a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i-1<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span>,a<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">sub</span>></span>i<span class="hljs-tag"></<span class="hljs-name">sub</span>></span></span> ∈ D, i = <span class="hljs-number">2</span>,…,n)<br> 基本操作:<br> InitList( &L )<br> 操作结果:构造一个空的线性表L。<br> DestroyList( &L )<br> 初始条件:线性表L已存在。<br> 操作结果:销毁线性表L。<br> ClearList( &L )<br> 初始条件:线性表L已存在。<br> 操作结果:将L重置为空表。<br> PrintList( L )<br> 初始条件:线性表L已存在。<br> 操作结果:按前后顺序输出线性表L的所有元素。<br> ListEmpty( L )<br> 初始条件:线性表L已存在。<br> 操作结果:若L为空表,则返回True,否则返回False。<br> Listlength( L )<br> 初始条件:线性表L已存在。<br> 操作结果:返回L中数据元素个数。<br> GetElem( L, i, &e )<br> 初始条件:线性表L已存在,<span class="hljs-number">1</span><=i<=ListLength(L)。<br> 操作结果:用e返回L中第i个数据元素的值。<br> LocateElem( L, e,<span class="hljs-built_in"> compare</span>() )<br> 初始条件:线性表L已存在<span class="hljs-built_in">,compare</span>()是数据元素判定函数。<br> 操作结果:返回L中第<span class="hljs-number">1</span>个与e满足关<span class="hljs-built_in">系compare</span>()的数据元素的位序。若这样的数据元素不存在,则返回值为<span class="hljs-number">0</span>。<br> PriorElem( L, cur_e, &pre_e )<br> 初始条件:线性表L已存在。<br> 操作结果:若cur_e是L的数据元素,且不是第一个,则用则用pre_e来返回他的前驱,否则操作失败,pre_e无定义。<br> NextElem( L, cur_e, &pre_e )<br> 初始条件:线性表L已存在。<br> 操作结果:若cur_e是L的数据元素,且不是最后一个,则用则用next_e来返回他的后继,否则操作失败,next_e无定义。<br> ListInsert( &L, i, e )<br> 初始条件:线性表L已存在,<span class="hljs-number">1</span><=i<=ListLength(L)+<span class="hljs-number">1</span>。<br> 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加<span class="hljs-number">1</span>。<br> ListDelete( &L, i, &e )<br> 初始条件:线性表L已存在且非空,<span class="hljs-number">1</span><=i<=ListLength(L)。<br> 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减<span class="hljs-number">1</span>。<br> ListTraverse( L, visit() )<br> 初始条件:线性表L已存在。<br> 操作结果:依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败。<br>} ADT List<br></code></pre></td></tr></table></figure></code></pre><p>除了以上操作,还可以有一些更复杂的操作,例如拆分、合成与复制线性表。</p><h2 id="二、线性表的实现">二、线性表的实现</h2><h3 id="(一)顺序存储">(一)顺序存储</h3><h4 id="1-顺序表的定义">1.顺序表的定义</h4><p>线性表的顺序存储指的是用一组地址连续的存储单元依次存储线性表的数据元素,又称为顺序表,因此表中逻辑上相邻的两个元素在物理位置上也连续,正因为这一点,而且线性表中各元素属于同一类型,因此,顺序表中的任意一个数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的数据结构。通常用高级程序设计语言的数组来描述线性表的顺序存储结构。</p><h4 id="2-顺序表的实现">2.顺序表的实现</h4><p>在C++语言中,我们可以使用一维数组作为顺序表的存储结构,但是同样是数组我们也有两种不同的实现方式,分别是静态分配与动态分配。对数组进行静态分配时,由于数组的大小和空间已经固定,所以空间一旦被占满,再加入新数据就会发生溢出,进而导致程序崩溃。而进行动态分配则可以避免这一问题,存储数组的空间大小是在程序执行过程中可以自由调整的,通过内存分配语句来进行控制,因此一旦空间占满,就另外开辟一块更大的存储空间,将原表中的元素全部拷贝到新空间,从而达到扩充数组存储空间的目的,而不需要一次性地为数组划分所有空间。</p><blockquote><p>后续所有代码均采用C++实现,并为了保持跟课本上定义的抽象数据类型的基本操作一致,仅仅会使用部分C++特性。比如这一节我使用类来定义顺序表的数据结构,却将数据操作方法定义在类外,完全可以定义在类内进行,且更推荐将所有相关操作定义在同一类内而不是使用引用的方式。</p></blockquote><h5 id="1-静态分配">(1)静态分配</h5><blockquote><p><a href="https://blog.cxhap.top/2024/07/27/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%BA%90%E4%BB%A3%E7%A0%81%E5%90%88%E9%9B%86/#%E9%9D%99%E6%80%81%E5%88%86%E9%85%8D">完整代码</a></p></blockquote><h6 id="数据结构">数据结构</h6><p>首先来看一下静态分配顺序表的数据结构:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">define</span> MaxSize 10 <span class="hljs-comment">// 顺序表的最大长度</span></span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SqList</span> {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> data[MaxSize]; <span class="hljs-comment">// 实际的存储结构,采用数组存储</span><br> <span class="hljs-type">int</span> length; <span class="hljs-comment">// 记录顺序表的当前长度</span><br><br> <span class="hljs-built_in">SqList</span>() {<br> length = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < MaxSize; ++i) {<br> data[i] = <span class="hljs-number">0</span>; <span class="hljs-comment">// 将数组内的每个数值初始化为0,否则访问时为随机值,即脏数据</span><br> }<br> }<br>};<br></code></pre></td></tr></table></figure><p>可见,在创建<code>SqList</code>这个数据结构时已经完成了内存分配,顺序表长度不可改变,并且由于数组可以通过数组下标来访问每个位置的元素,实现了顺序表随机存取的特性。但需要注意C++数组下标从0开始。</p><h6 id="函数声明">函数声明</h6><p>下面是函数声明部分,定义了顺序表各个函数,这里不多做解释。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 函数声明</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 初始化</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroyList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 销毁</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SqList &L)</span></span>; <span class="hljs-comment">// 重置为空表</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintList</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 打印</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListEmpty</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 判空</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span></span>; <span class="hljs-comment">// 获取长度</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 按位查找</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 按值查找</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span></span>; <span class="hljs-comment">// 查找前驱</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span></span>; <span class="hljs-comment">// 查找后继</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 插入</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 删除</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span></span>; <span class="hljs-comment">// 遍历</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">LocateChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> e, <span class="hljs-type">int</span> em)</span></span>; <span class="hljs-comment">// 先按值查找后改值</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> em)</span></span>; <span class="hljs-comment">// 先按位序查找后改值</span><br></code></pre></td></tr></table></figure><h6 id="初始化,销毁与清空">初始化,销毁与清空</h6><p>下面是顺序表的初始化,销毁与清空。初始化在新建<code>SqList</code>时其实已经发生,而销毁操作会自动进行,因此无需手动销毁,清空操作是将长度置0然后将数组元素全部清空。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 实现模块</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> L.length = <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroyList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> <span class="hljs-comment">// 静态分配,无需显式销毁</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SqList &L)</span> </span>{<br> L.length = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < MaxSize; ++i) {<br> L.data[i] = <span class="hljs-number">0</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><h6 id="顺序表的打印">顺序表的打印</h6><p>下面是顺序表的打印,即数据表的元素存储在数组的前<code>length</code>位置上,只需循环访问即可。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintList</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> std::cout << <span class="hljs-string">"开始打印顺序表\n"</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> std::cout << <span class="hljs-string">"Data["</span> << i << <span class="hljs-string">"]=="</span> << L.data[i] << <span class="hljs-string">"\n"</span>;<br> }<br> std::cout << <span class="hljs-string">"打印结束!\n"</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="判空与获取长度">判空与获取长度</h6><p>下面是判空与获取长度函数,只需要获取顺序表<code>length</code>变量的值即可。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListEmpty</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length == <span class="hljs-number">0</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L)</span> </span>{<br> <span class="hljs-keyword">return</span> L.length;<br>}<br></code></pre></td></tr></table></figure><h6 id="按序号获取元素">按序号获取元素</h6><p><code>GetElem</code>函数获取顺序表中第i个元素,这里的i是从1开始的,因此需要首先检测要求获取的值是否在范围内,小于1以及大于顺序表长度的值都是不允许的。如果查找失败则返回<code>false</code>,查找成功则返回<code>true</code>并且将查找到的值用e返回。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> }<br> e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="查找元素位置">查找元素位置</h6><p><code>LocateList</code>函数获取表中第一次出现e元素的位置,返回值为元素e在表中的位序,如果没找到则返回<code>0</code>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == e)<br> <span class="hljs-keyword">return</span> i + <span class="hljs-number">1</span>; <span class="hljs-comment">// 返回位序</span><br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; <span class="hljs-comment">// 未找到返回0</span><br>}<br></code></pre></td></tr></table></figure><h6 id="获取某元素相邻元素">获取某元素相邻元素</h6><p><code>PriorElem</code>和<code>NextElem</code>函数在顺序表中查找元素e,若找到元素e且它有前一个或后一个元素,则用<code>pre_e</code>或<code>next_e</code>返回其相邻的上一个元素或下一个元素并且返回值为<code>true</code>,否则返回值为<code>false</code>并且<code>pre_e</code>和<code>next_e</code>不代表任何值。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">1</span>; i < L.length; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> pre_e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length - <span class="hljs-number">1</span>; ++i) {<br> <span class="hljs-keyword">if</span> (L.data[i] == cur_e) {<br> next_e = L.data[i + <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="插入和删除元素">插入和删除元素</h6><p><code>ListInsert</code>与<code>ListDelete</code>分别用于向顺序表插入元素和删除元素,需要注意的是,由于顺序表中元素的逻辑顺序和物理顺序保持一致,因此在进行插入操作时,需要将被插入位置后面的所有元素全部后移;在进行删除操作时,需要将被删除元素后面的的全部元素向前移动一位。移动操作的时间复杂度为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length + <span class="hljs-number">1</span> || L.length >= MaxSize)<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> <br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = L.length; j >= i; --j) {<br> L.data[j] = L.data[j - <span class="hljs-number">1</span>];<br> }<br> L.data[i - <span class="hljs-number">1</span>] = e;<br> L.length++;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> }<br> e = L.data[i - <span class="hljs-number">1</span>];<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = i; j < L.length; ++j) {<br> L.data[j - <span class="hljs-number">1</span>] = L.data[j];<br> }<br> L.length--;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="遍历顺序表">遍历顺序表</h6><p><code>ListTraverse</code>函数用于使用指定的函数访问顺序表的各元素。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span> </span>{<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) {<br> <span class="hljs-built_in">visit</span>(L.data[i]);<br> }<br>}<br></code></pre></td></tr></table></figure><p>例如有个简单的函数<code>visit</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">visit</span><span class="hljs-params">(<span class="hljs-type">int</span> a)</span></span>{<br> std::cout<<a<<std::endl;<br>}<br></code></pre></td></tr></table></figure><p>可通过下面的方式调用<code>visit</code>函数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-built_in">ListTraverse</span>(L,visit);<br></code></pre></td></tr></table></figure><h6 id="修改元素值">修改元素值</h6><p><code>LocateChangeElem</code>与<code>GetChangeElem</code>分别是两种改元素值的方式,代码比较简单,先定位后修改,代码如下。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">LocateChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> e, <span class="hljs-type">int</span> em)</span> </span>{<br> <span class="hljs-type">int</span> bitOrder = <span class="hljs-built_in">LocateElem</span>(L, e);<br> <span class="hljs-keyword">if</span> (bitOrder != <span class="hljs-number">0</span>) {<br> L.data[bitOrder - <span class="hljs-number">1</span>] = em;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>}<br><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetChangeElem</span><span class="hljs-params">(SqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> em)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">0</span> || i >= L.length) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> L.data[i] = em;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br></code></pre></td></tr></table></figure><h5 id="2-动态分配">(2)动态分配</h5><blockquote><p><a href="https://blog.cxhap.top/2024/07/27/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%BA%90%E4%BB%A3%E7%A0%81%E5%90%88%E9%9B%86/#%E5%8A%A8%E6%80%81%E5%88%86%E9%85%8D">完整代码</a></p></blockquote><h6 id="数据结构-2">数据结构</h6><p>相较于静态分配,动态分配顺序表的实现要稍显复杂,顺序表的数据结构如下:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">define</span> InitSize 10</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SeqList</span> {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> *data; <span class="hljs-comment">// 指示动态分配数组的指针</span><br> <span class="hljs-type">int</span> MaxSize; <span class="hljs-comment">// 顺序表的最大容量</span><br> <span class="hljs-type">int</span> length; <span class="hljs-comment">// 顺序表当前的长度</span><br><br> <span class="hljs-built_in">SeqList</span>() : <span class="hljs-built_in">data</span>(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[InitSize]), <span class="hljs-function">MaxSiz<span class="hljs-title">e</span><span class="hljs-params">(InitSize)</span>, <span class="hljs-title">length</span><span class="hljs-params">(<span class="hljs-number">0</span>)</span> </span>{}<br> ~<span class="hljs-built_in">SeqList</span>() {<br> <span class="hljs-keyword">delete</span>[] data;<br> }<br>};<br></code></pre></td></tr></table></figure><h6 id="函数声明-2">函数声明</h6><p>函数声明如下,由于<code>LocateChangeElem</code>与<code>GetChangeElem</code>实现方法没有什么不同,这里不再赘述。其中<code>IncreaseSize</code>函数起到扩展动态分配顺序表的空间的作用,下面我仅介绍与上述实现不同的地方。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 函数声明</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 初始化</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Empty</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 判空</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Full</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 判满</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">IncreaseSize</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> len)</span></span>; <span class="hljs-comment">// 动态扩展空间</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 插入</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">GetElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> i)</span></span>; <span class="hljs-comment">// 按位查找</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LocateElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> e)</span></span>; <span class="hljs-comment">// 按值查找</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListDelete</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> &e)</span></span>; <span class="hljs-comment">// 删除</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroySqList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 销毁</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ClearList</span><span class="hljs-params">(SeqList &L)</span></span>; <span class="hljs-comment">// 清空</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">ListLength</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 获取长度</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">PriorElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &pre_e)</span></span>; <span class="hljs-comment">// 查找前驱</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">NextElem</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">int</span> cur_e, <span class="hljs-type">int</span> &next_e)</span></span>; <span class="hljs-comment">// 查找后继</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ListTraverse</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L, <span class="hljs-type">void</span> (*visit)(<span class="hljs-type">int</span>))</span></span>; <span class="hljs-comment">// 遍历</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintSqList</span><span class="hljs-params">(<span class="hljs-type">const</span> SeqList &L)</span></span>; <span class="hljs-comment">// 打印顺序表</span><br></code></pre></td></tr></table></figure><h6 id="初始化">初始化</h6><p>初始化函数如下,由于采用动态分配内存的方式,顺序表必须手动销毁。在这里我采用的C++类的方式编写的数据结构,因此使用析构函数<code>~SeqList()</code>进行顺序表的销毁。当然,按照前文方法定义,如果非要进行自行销毁的话也是可以的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 初始化</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">InitList</span><span class="hljs-params">(SeqList &L)</span> </span>{<br> L.data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[InitSize]; <br> <span class="hljs-keyword">if</span> (L.data == <span class="hljs-literal">nullptr</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> L.length = <span class="hljs-number">0</span>;<br> L.MaxSize = InitSize;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br><span class="hljs-comment">// 销毁</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">DestroySqList</span><span class="hljs-params">(SeqList &L)</span> </span>{<br> <span class="hljs-keyword">delete</span>[] L.data;<br> L.data = <span class="hljs-literal">nullptr</span>;<br> L.length = <span class="hljs-number">0</span>;<br> L.MaxSize = <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="扩大顺序表内存">扩大顺序表内存</h6><p><code>IncreaseSize</code>是动态分配顺序表的核心函数,首先分配一个指针p指向原先顺序表的内存数据,其次分配增加之后的存储空间,然后将原内存数据复制进新空间,最后回收原先分配的内存,即完成了扩展空间操作。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 扩展空间</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">IncreaseSize</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> len)</span> </span>{<br> std::cout << <span class="hljs-string">"开始扩展表存储空间..."</span> << std::endl;<br> <span class="hljs-type">int</span> *p = L.data;<br> L.data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[L.MaxSize + len];<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i < L.length; ++i) { <span class="hljs-comment">// 复制数据</span><br> L.data[i] = p[i];<br> }<br> L.MaxSize += len;<br> <span class="hljs-keyword">delete</span>[] p;<br> std::cout << <span class="hljs-string">"扩展完成,当前最大容量: "</span> << L.MaxSize << std::endl;<br>}<br></code></pre></td></tr></table></figure><h6 id="插入元素">插入元素</h6><p><code>ListInsert</code>与静态分配的最大区别在于,当顺序表空间不足时会自动完成内存扩展,再进行插入操作。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-comment">// 插入</span><br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">ListInsert</span><span class="hljs-params">(SeqList &L, <span class="hljs-type">int</span> i, <span class="hljs-type">int</span> e)</span> </span>{<br> <span class="hljs-keyword">if</span> (i < <span class="hljs-number">1</span> || i > L.length + <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Full</span>(L)) <span class="hljs-built_in">IncreaseSize</span>(L, InitSize);<br> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j = L.length; j >= i; --j) {<br> L.data[j] = L.data[j - <span class="hljs-number">1</span>];<br> }<br> L.data[i - <span class="hljs-number">1</span>] = e;<br> L.length++;<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>}<br></code></pre></td></tr></table></figure><p>其余代码与上述静态分配顺序表相同,不进行列举。</p><h3 id="(二)链式存储">(二)链式存储</h3><p>顺序表中元素的物理地址相邻且连续,并且每个元素的长度和大小完全一致,因此可以随机存取存储表中的任意元素。但是这种顺序存储结构也具有一个严重的问题,那就是在插入或删除中间元素时需要移动大量的元素,这在顺序表很长时需要消耗大量的时间。链式存储线性表不需要使用的地址连续的物理单元,不要求元素间物理地址上相邻,而是通过指针的形式指向该元素的上一个或下一个结点,因此链式存储线性表在插入和删除内部元素时无需移动其他元素,但这也导致无法随机存取内部元素。</p><h4 id="1-线性链表的定义">1.线性链表的定义</h4><p>线性表的链式存储结构的特点是用一组<strong>任意</strong>的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>a</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">a_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>,与其直接后继数据元素<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>a</mi><mrow><mi>i</mi><mo>+</mo><mn>1</mn></mrow></msub></mrow><annotation encoding="application/x-tex">a_{i+1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6389em;vertical-align:-0.2083em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2083em;"><span></span></span></span></span></span></span></span></span></span>之间的逻辑关系,对数据元素<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>a</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">a_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>a</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">a_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>的存储映像,称为结点(node)。它包括两个域:其中存储数据元素信息的域称为<strong>数据域</strong>;存储直接后继存储位置的域称为<strong>指针域</strong>。指针域中存储的信息称做指针或链。n个结点(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>a</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">a_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>(1≤i≤n)的存储映像)链结成一个链表,即为线性表</p><p class="katex-block "><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mo stretchy="false">(</mo><msub><mi>a</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>a</mi><mn>2</mn></msub><mo separator="true">,</mo><mo>…</mo><mo separator="true">,</mo><msub><mi>a</mi><mi>n</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(a_1,a_2,…,a_n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">…</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><p>的链式存储结构。又由于此链表的每个结点中只包含一个指针域,故又称<strong>线性链表</strong>或<strong>单链表</strong>。</p><p>用线性链表表示线性表时,数据元素间的逻辑关系是由结点中的指针指示的,逻辑间相邻的元素不要求物理位置相邻,因此这种存储结构为非顺序映像或链式映像。</p><p>单链表的结点定义如下:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">LNode</span> {<br> <span class="hljs-type">int</span> data; <span class="hljs-comment">//数据域</span><br> LNode *next; <span class="hljs-comment">//指针域</span><br>};<br></code></pre></td></tr></table></figure><p>结点中的<code>data</code>用于存储数据,*next指向下个相邻节点,因此两个结点之间无需相邻,但是对于每个结点需要额外消耗内存来存储下个位置的指针。由于单链表的元素离散分布在内存中,因此不能进行随机存取,在查找某个元素时需要从表头开始遍历,依次查找。</p><p>通常用头指针L(或head)来标识一个单链表,指出链表的起始地址,头指针为空时表示单链表为空表。此外,为了操作上的方便,可以在单链表的第一个数据结点之前附加一个头结点,头结点可以不记录信息,也可以记录表长等信息。单链表带头结点时,头指针指向头结点,否则指向第一个数据结点。</p><p>引入头结点的优点:</p><ol><li>由于第一个数据结点的位置被存储在头结点的指针域中,因此在链表的第一个位置的操作跟在表的其他位置的操作一致,无须进行特殊处理。即修改第一个数据结点时不用修改头指针。</li><li>无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也得到了统一。</li></ol><h4 id="2-线性链表(单链表)的基本操作的实现">2.线性链表(单链表)的基本操作的实现</h4><p>根据单链表是否带头结点,部分实现代码会有所不同,不同的代码会单独标注出来,相同的省略。<a href="">完整代码</a></p><h5 id="1-带头结点的单链表">(1)带头结点的单链表</h5><h6 id="初始化-2">初始化</h6><p>单链表的初始化如下,新建一个结点,数据域不赋值,由于初始化的单链表为空表,因此指针域为<code>nullptr</code>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs C++">LinkList::<span class="hljs-built_in">LinkList</span>() {<br> head = <span class="hljs-keyword">new</span> LNode;<br> head->next = <span class="hljs-literal">nullptr</span>;<br>}<br></code></pre></td></tr></table></figure><h6 id="求表长">求表长</h6><p>求表长操作,设置一个计数变量,从头结点开始,若该节点的指针域不为空则计数变量+1,直到当前结点指针域为空,返回计数变量。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs C++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">LinkList::length</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>{<br> <span class="hljs-type">int</span> len=<span class="hljs-number">0</span>;<br> LNode *L = head;<br> <span class="hljs-keyword">while</span>(L->next!=<span class="hljs-literal">nullptr</span>){<br> L=L->next;<br> len++;<br> }<br> <span class="hljs-keyword">return</span> len;<br>}<br></code></pre></td></tr></table></figure><h6 id="按序号查找结点">按序号查找结点</h6><p>从单链表的第一个结点开始,沿着指针域依次向后搜索,直到找到第i个元素为止。如果给定序号不在链表范围内则查找失败。</p><h2 id="三、线性表的应用">三、线性表的应用</h2>]]></content>
<categories>
<category>数据结构</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>数据结构</tag>
<tag>线性表</tag>
</tags>
</entry>
<entry>
<title>计算机操作系统——操作系统的发展历程</title>
<link href="/2024/07/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%91%E5%B1%95%E5%8E%86%E7%A8%8B/"/>
<url>/2024/07/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%91%E5%B1%95%E5%8E%86%E7%A8%8B/</url>
<content type="html"><![CDATA[<h1>操作系统的发展历程</h1><blockquote><p>《计算机操作系统(慕课版)》(汤小丹)书中p5-p15</p></blockquote><h2 id="一、未配置操作系统的计算机系统">一、未配置操作系统的计算机系统</h2><p>从1945年诞生的第一台计算机,到50年代中期的计算机,都属于<strong>第一代计算机</strong>。这时还未出现OS,对计算机的全部操作都是由用户采取人工方式进行的。</p><h3 id="1-人工操作方式">1.人工操作方式</h3><p>早期的操作方式是由程序员将事先己穿孔的纸带(或卡片),装入纸带输入机(或卡片输入机)。再启动它们将纸带(或卡片)上的程序和数据输入计算机,然后启动计算机运行。仅当程序运行完毕并取走计算结果后,才允许下一个用户上机。这种人工操作方式有以下两方面的缺点:</p><ol><li>用户独占全机,即一台计算机的全部资源由上机用户所独占。</li><li>CPU 等待人工操作。当用户进行装带(卡)卸带(卡)等人工操作时,CPU 及内存等资源是空闲的。</li></ol><p>可见,人工操作方式严重降低了计算机资源的利用率,此即所谓的人机矛盾。虽然CPU的速度在迅速提高,但IO设备的速度却提高缓慢,这使CPU与IO设备之间速度不匹配的矛盾更加突出。为此,曾先后出现了通道技术,缓冲技术,然而都未能很好地解决上述矛盾,直至后来引入了脱机输入/输出技术,才获得了相对较为满意的结果。</p><h3 id="2-脱机输入-输出(Off-line-I-O)方式">2.脱机输入/输出(Off-line I/O)方式</h3><p>在输入时,事先将程序和数据装入纸带输入机,在一台外围机的控制下将纸带上的数据和程序输入磁带,当CPU需要这些数据时再将数据从磁带调入,输出时同理,先将数据输出到磁带上,再由外围机控制进行输出,从而提升了I/O速度。</p><h2 id="二、单道批处理系统(Single-Batch-Processing-System)">二、单道批处理系统(Single Batch Processing System)</h2><p>1950年代中期进入第二代晶体管计算机。单道批处理系统是一组监控程序,为了实现对作业的连续控制,需要把一批作业以脱机的方式输入到磁带上,并在监控程序的控制下,每当一项作业完成后,程序将控制权交给监控程序,监控程序自动调入磁带上下一个作业,直至磁带上的所有作业被全部完成,从而使这批作业能一个接一个的被处理,减少空闲等待时间。虽然作业是一批一批完成的,但是在内存中始终只保持一项作业。</p><h3 id="特征">特征</h3><ol><li>自动性。自动逐个运行一批作业。</li><li>顺序性。调入内存的先后顺序与程序在磁带中的顺序一致。</li><li>单道性。内存中只存在一个程序,在执行完成或出现异常后装入后继程序运行。</li></ol><h3 id="缺点">缺点</h3><p>在运行时如果遇到耗时的I/O操作,则CPU需要等待I/O完成之后才能完成继续的执行,这严重拖累了Cpu的运行,并且内存中仅装入一道程序必然会造成内存的浪费,因此便有了多道批处理系统。</p><h2 id="三、多道批处理系统(Multiprogrammed-Batch-Processing-System)">三、多道批处理系统(Multiprogrammed Batch Processing System)</h2><p>1960年代中期诞生的第一台小规模集成电路计算机IBM 360(第三代计算机系统)在体积、功耗、速度和可靠性上有了显著改善,取得了显著成功,同时计算机系统进入了更多工作领域。OS/360是第一个能运行多道程序的批处理系统。多道批处理系统相较于单道批处理系统改变在于在内存中同时装载多项作业,在该系统中,用户所提交的作业先存放在外存上,并排成“后备队列”,然后由作业调度程序按照一定的算法从后备队列中选择若干个作业调入内存,使他们共享CPU和其他资源。由于内存中装在多个程序,因此在程序运行过程中遇到I/O等需要等待的耗时操作时,可以调度另一程序执行,使多道程序轮流交替执行,从而使CPU保持忙碌状态,提高运行效率。由于需要完成CPU、内存与I/O设备等资源的分配调度等工作,因此多道程序的设计与实现复杂很多。</p><h3 id="特点">特点</h3><ol><li>多道。内存中存放多个程序。</li><li>宏观上并行。由于任务切换着执行,并且切换时间很短,因此在宏观上各程序并行执行。</li><li>微观上串行。由于CPU只有一个,因此只能同时运行一个程序,各程序间交替执行。</li></ol><h3 id="优点与缺点">优点与缺点</h3><ol><li>资源利用率高</li><li>系统吞吐量大</li><li>平均周转时间长</li><li>无交互能力</li></ol><h3 id="需要解决的问题">需要解决的问题</h3><ol><li>处理机争用问题</li><li>内存分配和保护的问题</li><li>I/O设备分配问题</li><li>文件的组织和管理问题</li><li>作业的组织和管理问题</li><li>用户与系统的接口问题</li></ol><p>若在计算机系统中增加处理以上问题的一组软件,这组软件应包括:能有效管理和组织四大资源的软件、合理地对各类作业进行调度和控制他们运行的软件以及方便用户使用计算机的软件。正是这样一组软件构成了操作系统。因此操作系统被定义为:操作系统是一组能有效地组织和管理计算机硬件和软件资源,合理地对各类作业进行调度,以及方便用户使用的程序的集合。</p><h2 id="四、分时系统-Time-Sharing-Operating-System,TOS">四、分时系统(Time-Sharing Operating System,TOS)</h2><p>所谓分时技术,是指把处理器的运行时间分成很短的时间片,按时间片轮流把处理器分配给各联机作业使用。若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时停止运行,把处理器让给其他作业使用,等待下一轮再继续运行。由于计算机速度很快,作业运行轮转得也很快,因此给每个用户的感觉就像是自己独占一台计算机。分时操作系统是指多个用户通过终端同时共享一台主机(共享主机),这些终端连接在主机上,用户可以同时与主机进行交互操作而互不干扰。因此,实现分时系统最关键的问题是如何使用户能与自己的作业进行交互,即当用户在自己的终端上键入命令时,系统应能及时接收并及时处理该命令,再将结果返回用户(人机交互)。分时系统也是支持多道程序设计的系统,但它不同于多道批处理系统。多道批处理是实现作业自动控制而无须人工干预的系统,而分时系统是实现人机交互的系统,这使得分时系统具有与批处理系统不同的特征。</p><h3 id="主要特征">主要特征</h3><ol><li>同时性。同时性也称多路性,指允许多个终端用户同时使用一台计算机,即一台计算机与若干台终端相连接,终端上的这些用户可以同时或基本同时使用计算机。</li><li>交互性。用户能够方便地与系统进行人机对话,即用户通过终端采用人机对话的方式直接控制程序运行,与同程序进行交互。</li><li>独立性。系统中多个用户可以彼此独立地进行操作,互不干扰,单个用户感觉不到别人也在使用这台计算机,好像只有自己单独使用这台计算机一样。</li><li>及时性。用户请求能在很短时间内获得响应。分时系统采用时间片轮转方式使一台计算机同时为多个终端服务。</li></ol><h2 id="五、实时系统">五、实时系统</h2><p>实时系统是指系统能及响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务协调一致地运行。</p><h3 id="实时系统的类型">实时系统的类型</h3><ol><li>工业(武器)控制系统</li><li>信息查询系统</li><li>多媒体系统</li><li>嵌入式系统</li></ol><h3 id="实时任务的类型">实时任务的类型</h3><h4 id="周期性实时任务和非周期性实时任务">周期性实时任务和非周期性实时任务</h4><p>周期性实时任务按指定周期循环执行,非周期性实时任务执行伴随着截止时间,截止时间分为:开始截至时间(收到请求后最迟开始执行时间)、完成截止时间(在指定时间内完成任务)</p><h4 id="硬实时任务和软实时任务">硬实时任务和软实时任务</h4><p>硬实时任务(HIrd Real-time Task,HRT)是指系统必须满足任务对截止时间的要求,否则可能出现难以预测的后果。用于工业和武器控制的实时系统,通常它所执行的是硬实时任务。软实时任务(Soft Real-time Task,SRT)也联系着一个截止时间,但并不严格,若偶尔错过了任务的截止时间,对系统产生的影响也不会太大。诸如用于信息查询系统和多媒体系统中的实时系统,通常是软实时任务。</p><h3 id="特征-2">特征</h3><ol><li>多路性</li><li>独立性</li><li>及时性</li><li>交互性(简单交互性)</li><li>可靠性</li></ol><h2 id="六、网络操作系统">六、网络操作系统</h2><p>网络OS是用于在计算机网络环境下对网络资源进行管理和控制,实现<strong>数据通信</strong>及对网络资源的<strong>共享</strong>,为用户提供网络资源接口的一组软件和规程的集合。网络OS建立在网络中的计算机各自不同的单处理机OS之上,为用户提供使用网络资源的桥梁。常见的局域网上的OS有UNIX、Linux、Windows NT/2000/Server等。</p><h3 id="网络操作系统的特征">网络操作系统的特征</h3><ol><li>硬件独立性:系统可以运行于各种硬件平台之上,例如,可以运行于Intel 80x86系统,也可以运行于面向精简指令集计算机(reduced instruction set computing,RISC)的系统,如DEC Alpha、MIPS R4000等。</li><li>接口一致性:系统为网络中的共享资源提供一致性的接口,即针对同一性质的资源,采用统一的访问方式和接口。</li><li>资源透明性:系统能对网络中的资源进行统一管理,能够根据用户的要求对资源进行自动选择和分配。</li><li>系统可靠性:系统利用资源在地理上分散的优点,通过统一的管理、分配和调度手段,确保了整个网络的安全可靠。如果一个节点和通信链路出现故障,则可屏蔽该节点或重新定义新的通信链路,以保证网络的正常运行。</li><li>执行并行性:系统不仅实现了在每个节点计算机中各道进程的并发执行,而且实现了网络中多个节点计算机上进程的并行执行。</li></ol><h3 id="网络-OS-的功能">网络 OS 的功能</h3><p>网络OS不仅涵盖了单处理机OS的全部功能,还具有支持数据通信、应用互操作、网络管理等功能。</p><p>为了实现网络中计算机之间的数据通信,网络OS应具有如下基本功能:①连接的建立与拆除;②报文的分解与组装;③传输控制;④流量控制;⑤差错的检测与纠正。为了实现多个网络之间的通信和资源共享,不仅需要将它们从物理上连接在一起,还需要使不同网络中的计算机系统之间能进行通信(信息互通)和实现资源共享(信息互用)。为此,在网络OS中必须提供应用互操作功能,以实现“信息互通性”及“信息互用性”。在网络中引入网络管理功能,可以确保最大限度地增加网络的可用时间、提高网络设备的利用率、改善网络的服务质量以及保障网络的安全性等。</p><h2 id="七、分布式操作系统">七、分布式操作系统</h2><h3 id="(一)分布式系统">(一)分布式系统</h3><p>分布式系统(distributed system),是基于软件实现的一种多处理机系统,是多个处理机通过通信线路互联而构成的松散耦合系统,系统的处理和控制功能分布在各个处理机上。换言之,分布式系统是利用软件系统方式构建在计算机网络上的一种多处理机系统。</p><p>与传统的多处理机系统(包括多处理机和多计算机等)相比,分布式系统的不同之处在于:①分布式系统中的每个节点都是一台独立的计算机,并配置有完整的外部设备;②分布式系统中节点的耦合程度更低,地理分布区域更加广阔;③分布式系统中的每个节点均可以运行不同的OS,每个节点均拥有自己的文件系统,除了本节点的管理外,还有其他多个机构会对其实施管理。</p><p>针对分布式系统,已有很多不同的定义。例如:分布式系统是一些独立的计算机的集合,但是对这个系统的用户来说,系统就像一台计算机一样。再如:分布式系统是能为用户自动管理资源的网络OS,它能调用用于完成用户任务所需要的资源,而整个网络就像一个大的计算机系统一样对用户是透明的。归纳起来,分布式系统应具有以下几个主要特征。</p><ol><li>分布性:分布式系统由多台计算机组成,从位置和地域范围来看,它们是分散的和广阔的,此即地理位置的分布性。从系统的功能来看,功能分散在系统的各个节点计算机上,此即功能的分布性。从系统的资源来看,资源也分散配置在各节点计算机上,此即资源的分布性。从系统的控制来看,在一般的分布式系统中,计算机没有主从之分,此即控制的分布性。其中,资源和控制的分布性也称为自治性。</li><li>透明性:分布式系统的系统资源被所有计算机共享。每台计算机的用户不仅可以使用本机的资源,还可以使用分布式系统中其他计算机的资源,包括CPU、文件、打印机等。</li><li>同一性:分布式系统中的若干台计算机可以通过互相协作来完成同一任务,或者说一个程序可以分布在几台计算机上并行地运行。</li><li>全局性:系统具备一个全局性的进程通信机制,系统中的任意两台计算机都可以通过该机制实现信息交换。</li></ol><h3 id="(二)分布式-OS">(二)分布式 OS</h3><p>分布式OS是配置在分布式系统上的公用OS,其以全局的方式对分布式系统中的所有资源进行统一管理,可以直接对系统中地理位置分散的各种物理和逻辑资源进行动态分配和调度,有效地协调和控制各个任务的并行执行,协调和保持系统内的各个计算机间的信息传输与协作运行,并向用户提供一个统一的、方便的、透明的使用系统界面和标准接口。一个典型的例子是万维网(world wide web,WWW),在万维网中,所有的操作只通过一种界面(即网页)进行。目前,华为所研发的鸿蒙系统(HarmonyOS)就是一个“面向未来”、面向全场景(包括移动办公、运动健康、社交通信、媒体娱乐等)的分布式OS。它在传统的单一设备系统能力的基础上,增加了支持多种终端设备的功能。</p><p>与网络OS不同,分布式OS的用户在使用系统资源时,不需要了解诸如网络中各个计算机的功能与配置、OS的差异、软件资源、网络文件的结构、网络设备的地址、远程访问的方式等情况,即系统对用户屏蔽了其内部实现的细节。分布式OS保持了网络OS所拥有的全部功能,同时又具有透明性、内聚性、可靠性和高性能等特点。</p><p>分布式OS除了涵盖单处理机OS的主要功能外,还应该包括以下功能。</p><ol><li>通信管理功能。分布式OS应提供某种通信机制和方法,使不同节点上的用户或进程能方便地进行信息交换。一般地,分布式OS通过提供一些通信原语的方式,实现了系统内的进程通信,但由于系统中没有共享内存,这些原语需要按照通信协议的约定和规则来实现。</li><li>资源管理功能。分布式OS对系统中的所有资源实施统一管理、统一分配和统一调度,以提高资源利用率,方便用户共享和使用。例如,提供不同节点用户均可共享的分布式文件系统、分布式数据库系统、分布式程序设计语言及编译系统、分布式邮件系统等。</li><li>进程管理功能。针对系统的分布性特征,为了平衡各节点负载,加速计算速度,分布式OS应提供进程或计算迁移功能;为了协调进程对资源的共享与竞争,提高进程的并行程度,分布式OS还应提供分布式的同步和互斥机制以及应对死锁的措施等。</li></ol><h2 id="八、微机操作系统">八、微机操作系统</h2><p>随着计算机技术与超大规模集成电路(VLSI)的发展,计算机系统同时朝着大型化与小型化发展,8080与Z80等芯片的发布,更为廉价的微型机逐渐走向大众视野中,最早诞生的微机操作系统是配置在8位微机上的CP/M。后来逐渐出现字长16位、32位、64位的微机和微机操作系统。</p><h3 id="(1)单用户单任务操作系统">(1)单用户单任务操作系统</h3><p>单用户单任务操作系统是指只允许一个用户上机,且只允许用户程序作为一个任务运行,这是最简单的微机操作系统,主要配置在8位和16位微机上,最有代表性的单用户单任务微机操作系统是CP/M和MS-DOS。</p><h4 id="CP-M">CP/M</h4><p>1974年第一代通用8位微处理机芯片Intel 8080出现后的第二年,Digital Research公司就开发出带有软盘系统的8位微机操作系统。1977年Digital Research公司对CP/M进行了重写,使其可配置在以Intel 8080、8085、Z80等8位芯片为基础的多种微机上。1979年又推出带有硬盘管理功能的CP/M 2.2版本。由于CP/M具有较好的体系结构,可适应性强,可移植性以及易学易用等优点,使之在8位微机中占据了统治地位。</p><h4 id="MS-DOS">MS-DOS</h4><p>1981年IBM公司首次推出了IBM-PC个人计算机(16位微机),在微机中采用了微软公司开发的MS-DOS(Disk Operating System)操作系统,该操作系统在CP/M的基础上进行了较大的扩充,使其在功能上有很大的提高。1983年IBM推出 PC/AT(配有Intel 80286芯片),相应地微软又开发出 MS-DOS 2.0版本,它不仅能支持硬盘设备,还采用了树形目录结构的文件系统。1987年又宣布了MS-DoS 3.3版本。从MS-DoS 1.0到3.3为止的版本都属于单用户单任务操作系统,内存被限制在640KB。从1989到1993年又先后推出了多个MS-DOS版本,它们都可以配置在Intel80386、80486等32位微机上。从80年代到90年代初,由于MS-DOS性能优越受到当时用户的广泛欢迎,成为事实上的16位单用户单任务操作系统标准。</p><h3 id="(2)单用户多任务操作系统">(2)单用户多任务操作系统</h3><p>单用户多任务操作系统的含义是,只允许一个用户上机,但允许用户把程序分为若干个任务,使它们并发执行,从而有效地改善了系统的性能。目前在32位微机上配置的操作系统,基本上都是单用户多任务操作系统。其中最有代表性的是由微软公司推出了Windows。1985年和1987年微软公司先后推出了Windows 1.0和Windows 2.0版本操作系统,由于当时的硬件平台还只是16位微机,对10和2.0版本不能很好地支持。1990年微软公司又发布了Windows 3.0版本,随后又宣布了Windows 3.1版本,它们主要是针对386和486等32位微机开发的,它较之以前的操作系统有着重大的改进,引入了友善的图形用户界面,支持多任务和扩展内存的功能。使计算机更好使用,从而成为386和486等微机的主流操作系统。</p><p>1995年微软公司推出了Windows 95,它较之以前的Windows 3.1有许多重大改进,采用了全32位的处理技术,并兼容以前的16位应用程序,在该系统中还集成了支持Internet的网络功能。1998年微软公司又推出了Windows 95的改进版Windows 98,它已是最后一个仍然兼容以前的16位应用程序的Windows。其最主要的改进是把微软公司自己开发的Internet浏览器整合到系统中,大大方便了用户上网浏览:另一个改进是增加了对多媒体的支持。2001年微软又发布了Windows XP,同时提供了家用和商业工作站两种版本,在此后相当长的一段时间,成为使用最广泛的个人操作系统之一。在开发上述 Windows操作系统的同时,微软公司又开始对网络操作系统 Windows NT进行开发,它是针对网络开发的操作系统,在系统中融入许多面向网络的功能,从2006年后推出的一系列内核版本号为NT6.X的桌面及服务器操作系统,包括Windows Vista,Windows Server 2008、Windows 7、Windows Server 2008 R2、Windows 8和Windows Server 2012等,这里就不对它们进行介绍。</p><h3 id="(3)多用户多任务操作系统">(3)多用户多任务操作系统</h3><p>多用户多任务操作系统的含义是,允许多个用户通过各自的终端,使用同一台机器,共享主机系统中的各种资源,而每个用户程序又可进一步分为几个任务,使它们能并发执行,从而可进一步提高资源利用率和系统吞吐量。在大、中和小型机中所配置的大多是多用户多任务操作系统,而在32位微机上,也有不少配置的是多用户多任务操作系统,其中最有代表性的是UNIX OS。UNIX OS是美国电报电话公司的Bell实验室在1969~1970年期间开发的,1979年推出来的UNIX V.7已被广泛应用于多种中小型机上。随着微机性能的提高,人们又将UNIX移植到微机上。在1980年前后,将UNIX第7版本移植到Motorola公司的MC 680xx微机上,后来又将UNIX V7.0版本进行简化后,移植到Intel 8080上,把它称为Xenix。现在最有影响的两个能运行在微机上的UNIX 操作系统变形是Solaris OS 和Linux OS。</p><ol><li>Solaris OS:SUN公司于1982年推出的SUN OS 1.0,是一个运行在MOTOROLA 680x0平台上的UNIX OS,在1988年宣布的SUN OS 4.0,把运行平台从早期的MOTOROLA 680x0平台迁移到SPARC平台,并开始支持Intel公司的Intel 80x86;1992年SUN发布了Solaris 2.0。从1998年开始,Sun公司推出64位操作系统Solaris 2.7和2.8,这几款操作系统在网络特性、互操作性、兼容性以及易于配置和管理方面均有很大的提高。</li><li>Linux OS:Linux是UNIX的一个重要变种,最初是由芬兰学生Linus Torvalds针对Intel 80386开发的,1991年,在Internet网上发布第一个Linux版本,由于源代码公开,因此有很多人通过Internet 与之合作,使Linux 的性能迅速提高,其应用范围也日益扩大,相应地,源代码也急剧膨胀,此时它已是具有全面功能的UNIX系统,大量在UNIX上运行的软件(包括1000多种实用工具软件和大量网络软件),被移植到Linux 上,而且可以在主要的微机上运行,如Inel 80X86 Pentium等。</li></ol><h2 id="九、嵌入式操作系统">九、嵌入式操作系统</h2><h3 id="(一)嵌入式系统">(一)嵌入式系统</h3><p>与通用的计算机(如便携式计算机或桌面系统等)不同,嵌入式系统(embedded system)是为了完成某个特定功能而设计的系统,或是具有附加机制的系统,或是其他部分的计算机硬件与软件的结合体。在许多情况下,嵌入式系统都是一个大系统或产品中的一部分,如汽车中的防抱死系统。</p><h3 id="(二)嵌入式-OS">(二)嵌入式 OS</h3><p>嵌入式OS是指应用于嵌入式系统的OS。嵌入式OS是一种用途广泛的系统软件,通常包括与硬件相关的低层驱动软件、系统内核、设备驱动接口、通信协议、图形用户界面、标准化浏览器等。嵌入式OS负责嵌入式系统的全部软硬件资源的分配、任务的调度以及并发活动的协调等。它必须体现其所在系统的特征,必须能够通过装卸某些模块来实现系统所要求的功能。</p><p>目前在嵌入式领域广泛使用的OS有嵌入式(实时)µC/OS-II、嵌入式Linux、Windows Embedded、VxWorks,以及应用在智能手机和平板电脑上的Android、iOS等。</p><h3 id="(三)嵌入式-OS-的特点">(三)嵌入式 OS 的特点</h3><p>由于嵌入式系统对存储空间、功耗和实时性等有特定的要求,因此嵌入式OS也具有独特的<br>特性。</p><ol><li>系统内核小。由于嵌入式OS一般应用于小型电子装置,系统资源相对有限,因此其内核较传统OS要小得多。</li><li>系统精简。嵌入式OS一般没有系统软件和应用软件的明显区分,不要求功能设计与实现过于复杂。这样既可以控制系统成本,也有利于系统安全。</li><li>实时性高。实时性高是嵌入式软件的基本要求,此外,软件还要求固态存储以提高速度,软件代码要求高质量和高可靠性。</li><li>具有可配置性。由于嵌入式系统的多样性,一个嵌入式OS若想应用在不同的嵌入式系统中,它就必须可以灵活配置,以便为特定的应用和硬件系统提供所需的功能。</li></ol><h2 id="按时间排序">按时间排序</h2><h3 id="大型机操作系统的发展历程">大型机操作系统的发展历程</h3><h4 id="1950s-1960s">1950s-1960s</h4><ul><li><strong>GM-NAA I/O</strong>: 1956年,通用汽车为IBM 701计算机开发的操作系统,是最早的商用操作系统之一。</li><li><strong>SHARE Operating System (SOS)</strong>: 由IBM用户组织SHARE在1960年开发,用于IBM 7090计算机。</li><li><strong>BESYS</strong>: 由贝尔实验室开发,用于科学计算,使用于1950年代末到1960年代中期。</li><li><strong>IBSYS</strong>: IBM在1960年代初为其7090和7094大型计算机开发的操作系统,支持批处理和多道程序设计。</li></ul><h4 id="1960s-1970s">1960s-1970s</h4><ul><li><strong>OS/360</strong>: 1964年推出,专为IBM System/360计算机系列设计。支持批处理、多编程和分时系统,成为商业领域的重要操作系统。</li><li><strong>CP/CMS</strong>: 1967年推出,是第一个成功的虚拟机操作系统,支持在单台物理机器上运行多个操作系统实例。</li><li><strong>TSS/360</strong>: 为System/360开发的时间共享系统,但由于可靠性问题未能广泛应用。</li></ul><h4 id="1970s-1980s">1970s-1980s</h4><ul><li><strong>VM/370</strong>: CP/CMS的后继者,1972年推出,为System/370系列提供虚拟机支持。</li><li><strong>MVS (Multiple Virtual Storage)</strong>: 1974年推出,是OS/360的演进版本,增加了对虚拟内存的支持,成为IBM大型机的主要操作系统之一。</li><li><strong>DOS/360</strong>: 为中小型System/360计算机设计,1966年推出,适用于磁盘驱动器有限的环境。</li></ul><h4 id="1980s-2000s">1980s-2000s</h4><ul><li><strong>MVS/XA (Extended Architecture)</strong>: 1981年推出,扩展了MVS的体系结构,支持更多的物理和虚拟内存。</li><li><strong>MVS/ESA (Enterprise Systems Architecture)</strong>: 1985年推出,进一步增强了MVS的功能。</li><li><strong>OS/390</strong>: 1996年推出,将MVS与其它系统软件整合,提供更全面的企业级解决方案。</li><li><strong>z/OS</strong>: 2000年推出,现代化的64位操作系统,兼容以前的MVS和OS/390应用程序。</li><li><strong>Linux on IBM Z</strong>: 1999年开始,IBM在大型机上支持Linux操作系统,使大型机能够运行开源软件,满足新的市场需求。</li></ul><h3 id="小型机操作系统的发展历程">小型机操作系统的发展历程</h3><h4 id="1960s-1970s-2">1960s-1970s</h4><ul><li><strong>RT-11</strong>: 由Digital Equipment Corporation (DEC)在1970年推出,用于PDP-11小型计算机,是早期的实时操作系统。</li><li><strong>UNIX</strong>: 1969年在贝尔实验室开发的分时操作系统,1970年代早期在PDP-7和PDP-11计算机上运行,奠定了现代操作系统的基础。</li></ul><h4 id="1980s">1980s</h4><ul><li><strong>VAX/VMS</strong>: DEC在1977年推出,用于VAX系列小型计算机,支持虚拟内存和分时操作。</li><li><strong>Xenix</strong>: 1980年代初,由微软开发的UNIX版本,运行于多种小型计算机上。</li><li><strong>BSD UNIX</strong>: 1980年代,由加州大学伯克利分校开发的UNIX版本,增加了许多创新功能。</li></ul><h4 id="1990s-2000s">1990s-2000s</h4><ul><li><strong>Windows NT</strong>: 微软在1993年推出的操作系统,支持多处理器和企业级应用,运行在多种硬件平台上。</li><li><strong>Linux</strong>: 1991年由Linus Torvalds发布的开源操作系统,迅速发展成为服务器和桌面应用的重要操作系统。</li></ul><h4 id="2000s至今">2000s至今</h4><ul><li><strong>Windows Server</strong>: 微软为企业服务器市场开发的操作系统,从2000年开始发布多个版本。</li><li><strong>FreeBSD</strong>: 继承自BSD UNIX的开源操作系统,持续发展并广泛应用于服务器和嵌入式系统。</li></ul>]]></content>
<categories>
<category>计算机操作系统</category>
</categories>
<tags>
<tag>计算机操作系统</tag>
<tag>笔记</tag>
<tag>发展历程</tag>
</tags>
</entry>
<entry>
<title>计算机科学与技术(081200)考试指南:科目、时间与备考全攻略</title>
<link href="/2024/07/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E4%B8%8E%E6%8A%80%E6%9C%AF-081200-%E8%80%83%E8%AF%95%E6%8C%87%E5%8D%97-%E7%A7%91%E7%9B%AE%E3%80%81%E6%97%B6%E9%97%B4%E4%B8%8E%E5%A4%87%E8%80%83%E5%85%A8%E6%94%BB%E7%95%A5/"/>
<url>/2024/07/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E4%B8%8E%E6%8A%80%E6%9C%AF-081200-%E8%80%83%E8%AF%95%E6%8C%87%E5%8D%97-%E7%A7%91%E7%9B%AE%E3%80%81%E6%97%B6%E9%97%B4%E4%B8%8E%E5%A4%87%E8%80%83%E5%85%A8%E6%94%BB%E7%95%A5/</url>
<content type="html"><![CDATA[<h1>专业介绍与院校信息</h1><p>见研招网<a href="https://yz.chsi.com.cn/zyk/specialityDetail.do?zymc=%e8%ae%a1%e7%ae%97%e6%9c%ba%e7%a7%91%e5%ad%a6%e4%b8%8e%e6%8a%80%e6%9c%af&zydm=081200&cckey=10&ssdm=&method=distribution">计算机科学与技术专业知识库</a>。</p><h1>二级学科</h1><p>不同的学校开设不同的二级学科,但是主要有计算机系统结构、计算机软件与理论、计算机应用技术以及信息安全这四个二级学科。</p><ol><li>计算机系统结构(081201):先进计算机体系结构、先进微处理器结构、智能计算系统、大数据存储系统、量子计算系统、智能物联网系统、系统软件、高性能计算、云计算、嵌入式计算、边缘计算。</li><li>计算机软件与理论(081202):计算复杂性理论、算法设计与分析、大数据与智能软件、编译和操作系统、移动计算和智能物联网、新型数据库、图计算、大数据计算、并行与分布式计算、形式化方法和验证技术、程序设计与软件工程学、软件测试、密码学。</li><li>计算机应用技术(081203):人工智能、大数据分析与管理、机器学习与数据挖掘、知识工程、信息检索与推荐系统、社交网络、生物信息学、数据库技术、多媒体信息处理、区块链技术、多智能体技术、机器人、图形学、计算机视觉、虚拟现实与人机交互、新一代通信技术、智能物联网与应用、智能系统与应用、智慧教育、智慧医疗、计算机辅助设计与制造。</li><li>信息安全(081204):计算机系统安全、网络安全、信息内容与数据安全、软件安全与验证、区块链技术、隐私保护、信息隐藏与检测、密码理论与应用技术、量子密码学与量子信息安全、计算机病毒与免疫系统、网络管理与风险评估。</li></ol><blockquote><p>以上介绍来自<a href="https://yz1.ustc.edu.cn/sszs_2024/index_8.shtml">ustc硕士研究生计算机与信息学院招生简章</a>。</p></blockquote><h1>初试</h1><h2 id="初试时间">初试时间</h2><p>一般在每年12月末。</p><h2 id="初试科目">初试科目</h2><ol><li>101思想政治理论</li><li>201英语(一)</li><li>301数学(一)</li><li>408计算机学科专业基础<br><a href="https://blog.cxhap.top/2024/07/11/2024-7-11-2024%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AD%A6%E7%A7%91%E4%B8%93%E4%B8%9A%E5%9F%BA%E7%A1%80-408-%E8%80%83%E8%AF%95%E5%A4%A7%E7%BA%B2/">大纲</a></li></ol><h1>复试</h1><h2 id="复试时间">复试时间</h2><p>各大高校自行确定时间,一般从三月份开始,四月底结束。</p><h2 id="复试科目">复试科目</h2><ol><li>面试</li><li>上机</li></ol>]]></content>
<categories>
<category>0812计算机考研408</category>
</categories>
<tags>
<tag>计算机科学与技术</tag>
<tag>812</tag>
<tag>硕士研究生考试指南</tag>
</tags>
</entry>
<entry>
<title>2024计算机学科专业基础(408)考试大纲</title>
<link href="/2024/07/11/2024-7-11-2024%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AD%A6%E7%A7%91%E4%B8%93%E4%B8%9A%E5%9F%BA%E7%A1%80-408-%E8%80%83%E8%AF%95%E5%A4%A7%E7%BA%B2/"/>
<url>/2024/07/11/2024-7-11-2024%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AD%A6%E7%A7%91%E4%B8%93%E4%B8%9A%E5%9F%BA%E7%A1%80-408-%E8%80%83%E8%AF%95%E5%A4%A7%E7%BA%B2/</url>
<content type="html"><![CDATA[<h1>2024计算机学科专业基础(408)考试大纲</h1><blockquote><p>2024年408考纲为2023年9月公布,是2023年12月参加硕士研究室考试的考纲。2025与2026年考纲将分别于2024年9月以及2025年9月发布。信息收集自互联网。</p></blockquote> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-2c313594" role="button" aria-expanded="false" aria-controls="collapse-2c313594"> <div class="fold-arrow">▶</div>考试信息 </div> <div class="fold-collapse collapse" id="collapse-2c313594"> <div class="fold-content"> <h2 id="考试性质">考试性质</h2><p> 计算机学科专业基础考试是为高等院校和科研院所招收计算机科学与技术学科的硕士研究生而设置的具有选拔性质的全国统一入学考试科目。其目的是科学、公正、有效地测试考生掌握计算机科学与技术学科大学本科阶段专业基础知识、基本理论、基本方法的水平和分析问题、解决问题的能力,评价的标准是高等院校计算机科学与技术学科优秀本科毕业生所能达到的及格或及格以上的水平,以利于各高等院校和科研院所择优选拔,确保硕士研究生的招生质量。</p><h2 id="考察目标">考察目标</h2><p> 计算机学科专业基础考试涵盖数据结构、计算机组成原理、操作系统和计算机网络等学科专业基础课程。要求考生系统地掌握上述专业基础课程的基本概念、基本原理和基本方法,能够综合运用所学的基本原理和基本方法分析、判断和解决有关理论问题和实际问题。</p><h2 id="考试形式和试卷结构">考试形式和试卷结构</h2><h3 id="一、试卷满分及考试时间">一、试卷满分及考试时间</h3><p>本试卷满分为150分,考试时间为180分钟。</p><h3 id="二、答题方式">二、答题方式</h3><p>闭卷、笔试。</p><h3 id="三、试卷内容结构">三、试卷内容结构</h3><table><thead><tr><th style="text-align:center">内容</th><th style="text-align:center">分值</th></tr></thead><tbody><tr><td style="text-align:center">数据结构</td><td style="text-align:center">45分</td></tr><tr><td style="text-align:center">计算机组成原理</td><td style="text-align:center">45分</td></tr><tr><td style="text-align:center">操作系统</td><td style="text-align:center">35分</td></tr><tr><td style="text-align:center">计算机网络</td><td style="text-align:center">25分</td></tr></tbody></table><h3 id="四、试卷题型结构">四、试卷题型结构</h3><table><thead><tr><th style="text-align:center">题型</th><th style="text-align:center">分值</th></tr></thead><tbody><tr><td style="text-align:center">单项选择题</td><td style="text-align:center">80分(40题*2分)</td></tr><tr><td style="text-align:center">综合应用题</td><td style="text-align:center">70分(共7题)</td></tr></tbody></table><table><thead><tr><th style="text-align:center">题号</th><th style="text-align:center">描述</th></tr></thead><tbody><tr><td style="text-align:center">41</td><td style="text-align:center">数据结构算法题</td></tr><tr><td style="text-align:center">42</td><td style="text-align:center">数据结构分析题</td></tr><tr><td style="text-align:center">43</td><td style="text-align:center">计算机组成原理</td></tr><tr><td style="text-align:center">44</td><td style="text-align:center">计算机组成原理</td></tr><tr><td style="text-align:center">45</td><td style="text-align:center">操作系统</td></tr><tr><td style="text-align:center">46</td><td style="text-align:center">操作系统</td></tr><tr><td style="text-align:center">47</td><td style="text-align:center">计算机网络</td></tr></tbody></table> </div> </div> </div><h2 id="考查内容">考查内容</h2><h3 id="数据结构">数据结构</h3> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-a16e476e" role="button" aria-expanded="false" aria-controls="collapse-a16e476e"> <div class="fold-arrow">▶</div>数据结构大纲 </div> <div class="fold-collapse collapse" id="collapse-a16e476e"> <div class="fold-content"> <blockquote><p>参考教材:《数据结构C语言》(严蔚敏版)</p></blockquote><h4 id="考查目标">[考查目标]</h4><ol><li>掌握数据结构的基本概念、基本原理和基本方法。</li><li>掌握数据的逻辑结构、存储结构及基本操作的实现,能够对算法进行基本的时间复杂度和空间复杂度的分析。<a href="https://blog.cxhap.top/2024/07/25/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%AE%97%E6%B3%95%E6%95%88%E7%8E%87%E7%9A%84%E5%BA%A6%E9%87%8F/">算法效率的度量</a></li><li>能够运用数据结构的基本原理和方法进行问题的分析与求解,具备采用C或C++语言设计和实现算法的能力。</li></ol><h4 id="一、线性表">一、线性表</h4><p><a href="https://blog.cxhap.top/2024/07/23/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E7%BA%BF%E6%80%A7%E8%A1%A8/">笔记</a></p><h5 id="(一)线性表的基本概念">(一)线性表的基本概念</h5><h5 id="(二)线性表的实现">(二)线性表的实现</h5><ol><li>顺序存储</li><li>链式存储</li></ol><h5 id="(三)线性表的应用">(三)线性表的应用</h5><h4 id="二、栈、队列和数组">二、栈、队列和数组</h4><p><a href="https://blog.cxhap.top/2024/08/18/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%88%E3%80%81%E9%98%9F%E5%88%97%E5%92%8C%E6%95%B0%E7%BB%84/">笔记</a></p><h5 id="(一)栈和队列的基本概念">(一)栈和队列的基本概念</h5><h5 id="(二)栈和队列的顺序存储结构">(二)栈和队列的顺序存储结构</h5><h5 id="(三)栈和队列的链式存储结构">(三)栈和队列的链式存储结构</h5><h5 id="(四)多维数组的存储">(四)多维数组的存储</h5><h5 id="(五)特殊矩阵的压缩存储">(五)特殊矩阵的压缩存储</h5><h5 id="(六)栈、队列和数组的应用">(六)栈、队列和数组的应用</h5><h4 id="三、树与二叉树">三、树与二叉树</h4><p><a href="https://blog.cxhap.top/2024/08/19/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%A0%91%E4%B8%8E%E4%BA%8C%E5%8F%89%E6%A0%91/">笔记</a></p><h5 id="(一)树的基本概念">(一)树的基本概念</h5><h5 id="(二)二叉树">(二)二叉树</h5><ol><li>二叉树的定义及其主要特征</li><li>二叉树的顺序存储结构和链式存储结构</li><li>二叉树的遍历</li><li>线索二叉树的基本概念和构造</li></ol><h5 id="(三)树、森林">(三)树、森林</h5><ol><li>树的存储结构</li><li>森林与二叉树的转换</li><li>树和森林的遍历</li></ol><h5 id="(四)树与二叉树的应用">(四)树与二叉树的应用</h5><ol><li>哈夫曼(Huffman)树和哈夫曼编码</li><li>并查集及其应用</li></ol><h4 id="四、图">四、图</h4><p><a href="https://blog.cxhap.top/2024/08/20/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E5%9B%BE/">笔记</a></p><h5 id="(一)图的基本概念">(一)图的基本概念</h5><h5 id="(二)图的存储及基本操作">(二)图的存储及基本操作</h5><ol><li>邻接矩阵</li><li>邻接表法</li><li>邻接多重表,十字链表</li></ol><h5 id="(三)图的遍历">(三)图的遍历</h5><ol><li>深度优先搜索</li><li>广度优先搜索</li></ol><h5 id="(四)图的基本应用">(四)图的基本应用</h5><ol><li>最小(代价)生成树</li><li>最短路径</li><li>拓扑排序</li><li>关键路径</li></ol><h4 id="五、查找">五、查找</h4><p><a href="https://blog.cxhap.top/2024/08/21/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%9F%A5%E6%89%BE/">笔记</a></p><h5 id="(一)查找的基本概念">(一)查找的基本概念</h5><h5 id="(二)顺序查找法">(二)顺序查找法</h5><h5 id="(三)分块查找法">(三)分块查找法</h5><h5 id="(四)折半查找法">(四)折半查找法</h5><h5 id="(五)树形查找">(五)树形查找</h5><ol><li>二叉搜索树</li><li>平衡二叉树</li><li>红黑树</li></ol><h5 id="(六)B-树及其基本操作、B-树的基本概念">(六)B 树及其基本操作、B+ 树的基本概念</h5><h5 id="(七)散列-hash-表">(七)散列(hash)表</h5><h5 id="(八)字符串模式匹配">(八)字符串模式匹配</h5><h5 id="(九)查找算法的分析及其应用">(九)查找算法的分析及其应用</h5><h4 id="六、排序">六、排序</h4><p><a href="https://blog.cxhap.top/2024/08/22/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E2%80%94%E2%80%94%E6%8E%92%E5%BA%8F/">排序</a></p><h5 id="(一)排序的基本概念">(一)排序的基本概念</h5><h5 id="(二)直接插入排序">(二)直接插入排序</h5><h5 id="(三)折半插入排序">(三)折半插入排序</h5><h5 id="(四)起泡排序-bubble-sort">(四)起泡排序(bubble sort)</h5><h5 id="(五)简单选择排序">(五)简单选择排序</h5><h5 id="(六)希尔排序-shell-sort">(六)希尔排序(shell sort)</h5><h5 id="(七)快速排序">(七)快速排序</h5><h5 id="(八)堆排序">(八)堆排序</h5><h5 id="(九)二路归并排序-merge-sort">(九)二路归并排序(merge sort)</h5><h5 id="(十)基数排序">(十)基数排序</h5><h5 id="(十一)外部排序">(十一)外部排序</h5><h5 id="(十二)排序算法的分析和应用">(十二)排序算法的分析和应用</h5> </div> </div> </div><h3 id="计算机组成原理">计算机组成原理</h3> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-0e68dd17" role="button" aria-expanded="false" aria-controls="collapse-0e68dd17"> <div class="fold-arrow">▶</div>计算机组成原理大纲 </div> <div class="fold-collapse collapse" id="collapse-0e68dd17"> <div class="fold-content"> <blockquote><p>参考教材:《计算机组成原理》(唐朔飞)</p></blockquote><h4 id="考查目标">[考查目标]</h4><ol><li>掌握单处理器计算机系统中主要部件的工作原理、组成结构以及相互连接方式。</li><li>掌握指令集体系结构的基本知识和基本实现方法,对计算机硬件相关问题进行分析,并能够对相关部件进行设计。</li><li>能够综合运用计算机组成的基本原理和基本方法,对有关计算机硬件系统中的理论和实际问题进行计算、分析,对一些基本部件进行简单设计;并能对高级程序设计语言(如 C语言)中的相关问题进行分析。</li></ol><h4 id="一、计算机系统概述">一、计算机系统概述</h4><p><a href="https://blog.cxhap.top/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%BF%B0/">笔记</a></p><h5 id="(一)计算机系统层次结构">(一)计算机系统层次结构</h5><ol><li>计算机系统的基本组成</li><li>计算机硬件的基本结构</li><li>计算机软件和硬件的关系</li><li>计算机系统的工作原理</li></ol><p>“存储程序”工作方式,高级语言程序与机器语言程序之间的转换,程序和指令的执行过程。</p><h5 id="(二)计算机的性能指标">(二)计算机的性能指标</h5><p>吞吐量、响应时间;CPU 时钟周期、主频、CPI、CPU 执行时间;MIPS、 MFLOPS 、GFLOPS、TFLOPS、PFLOPS、EFLOPS、ZFLOPS。</p><h4 id="二、数据的表示和运算">二、数据的表示和运算</h4><p><a href="https://blog.cxhap.top/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E7%9A%84%E8%A1%A8%E7%A4%BA%E5%92%8C%E8%BF%90%E7%AE%97/">笔记</a></p><h5 id="(一)数制与编码">(一)数制与编码</h5><ol><li>定点计数制及其数据之间的相互转换</li><li>定点数的编码表示</li></ol><h5 id="(二)运算方法和运算电路">(二)运算方法和运算电路</h5><ol><li>基本运算部件</li></ol><p>加法器,算数逻辑单元(ALU)。</p><ol start="2"><li>加/减运算</li></ol><p>补码加/减运算器,标志位的生成。</p><ol start="3"><li>乘/除运算</li></ol><p>乘/除法运算的的基本原理,乘法电路和除法电路的基本结构。</p><h5 id="(三)整数的表示和运算">(三)整数的表示和运算</h5><ol><li>无符号整数的表示和运算</li><li>带符号整数的表示和运算</li></ol><h5 id="(四)浮点数的表示和运算">(四)浮点数的表示和运算</h5><ol><li>浮点数的表示</li></ol><p>IEEE 754标准。</p><ol start="2"><li>浮点数的加/减运算</li></ol><h4 id="三、存储器层次结构">三、存储器层次结构</h4><p><a href="https://blog.cxhap.top/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E5%AD%98%E5%82%A8%E5%99%A8%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84/">笔记</a></p><h5 id="(一)存储器的分类">(一)存储器的分类</h5><h5 id="(二)层次化存储器的基本结构">(二)层次化存储器的基本结构</h5><h5 id="(三)半导体随机存取存储器">(三)半导体随机存取存储器</h5><ol><li>SRAM 存储器</li><li>DRAM 存储器</li><li>Flash 存储器</li></ol><h5 id="(四)主存储器">(四)主存储器</h5><ol><li>DRAM 芯片和内存条</li><li>多模块存储器</li><li>主存和CPU之间的连接</li></ol><h5 id="(五)外部存储器">(五)外部存储器</h5><ol><li>磁盘存储器</li><li>固态硬盘(SSD)</li></ol><h5 id="(六)高速缓存存储器(Cache)">(六)高速缓存存储器(Cache)</h5><ol><li>Cache 的基本原理</li><li>Cache 和主存之间的映射方式</li><li>Cache 中主存块的替换算法</li><li>Cache 写策略</li></ol><h5 id="(七)虚拟存储器">(七)虚拟存储器</h5><ol><li>虚拟存储器的基本概念</li><li>页式虚拟存储器</li></ol><p>基本原理,页表,地址转换,TLB(快表)。</p><ol start="3"><li>段式虚拟存储器的基本原理</li><li>段页式虚拟存储器的基本原理</li></ol><h4 id="四、指令系统">四、指令系统</h4><p><a href="https://blog.cxhap.top/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%8C%87%E4%BB%A4%E7%B3%BB%E7%BB%9F/">笔记</a></p><h5 id="(一)指令系统的基本概念">(一)指令系统的基本概念</h5><h5 id="(二)指令格式">(二)指令格式</h5><h5 id="(三)寻址方式">(三)寻址方式</h5><h5 id="(四)数据的对齐和大-小端存放方式">(四)数据的对齐和大/小端存放方式</h5><h5 id="(五)CISC和RISC的基本概念">(五)CISC和RISC的基本概念</h5><h5 id="(六)高级语言程序与与机器级代码之间的对应">(六)高级语言程序与与机器级代码之间的对应</h5><ol><li>编译器、汇编器和链接器的基本概念</li><li>选择结构语句的机器级表示</li><li>循环结构语句的机器级表示</li><li>过程(函数)调用对应的机器级表示</li></ol><h4 id="五、中央处理器(CPU)">五、中央处理器(CPU)</h4><p><a href="https://blog.cxhap.top/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E4%B8%AD%E5%A4%AE%E5%A4%84%E7%90%86%E5%99%A8%EF%BC%88CPU%EF%BC%89/">笔记</a></p><h5 id="(一)CPU的功能和基本结构">(一)CPU的功能和基本结构</h5><h5 id="(二)指令执行过程">(二)指令执行过程</h5><h5 id="(三)数据通路的功能和基本结构">(三)数据通路的功能和基本结构</h5><h5 id="(四)控制器的功能和工作原理">(四)控制器的功能和工作原理</h5><h5 id="(五)异常和中断机制">(五)异常和中断机制</h5><ol><li>异常和中断的基本概念</li><li>异常和中断的分类</li><li>异常和中断的检测与响应</li></ol><h6 id="(六)指令流水线">(六)指令流水线</h6><ol><li>指令流水线的基本概念</li><li>指令流水线的基本实现</li><li>结构冒险、数据冒险和控制冒险的处理</li><li>超标量和动态流水线的基本概念</li></ol><h5 id="(七)多处理器基本概念">(七)多处理器基本概念</h5><ol><li>SISD、SIMD、MIMD、向量处理器的基本概念</li><li>硬件多线程的基本概念</li><li>多核(multi-core)处理器的基本概念</li><li>共享内存多处理器(SMP)的基本概念</li></ol><h4 id="六、总线和输入-输出系统">六、总线和输入/输出系统</h4><p><a href="https://blog.cxhap.top/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86%E2%80%94%E2%80%94%E6%80%BB%E7%BA%BF%E5%92%8C%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA%E7%B3%BB%E7%BB%9F/">笔记</a></p><h5 id="(一)总线">(一)总线</h5><ol><li>总线的基本概念</li><li>总线的组成及性能指标</li><li>总线事务和定时</li></ol><h5 id="(二)I-O接口(I-O控制器)">(二)I/O接口(I/O控制器)</h5><ol><li>I/O接口的功能和基本结构</li><li>I/O接口及其编址</li></ol><h5 id="(三)I-O方式">(三)I/O方式</h5><ol><li>程序查询方式</li><li>程序中断方式<br>中断的基本概念,中断响应过程,中断处理过程,多重中断和中断屏蔽的概念。</li><li>DMA方式<br>DMA控制器的组成,DMA传送过程。</li></ol> </div> </div> </div><h3 id="操作系统">操作系统</h3> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-cd921afa" role="button" aria-expanded="false" aria-controls="collapse-cd921afa"> <div class="fold-arrow">▶</div>操作系统大纲 </div> <div class="fold-collapse collapse" id="collapse-cd921afa"> <div class="fold-content"> <blockquote><p>参考教材:《计算机操作系统第四版》(汤子瀛版)</p></blockquote><h4 id="考查目标">[考查目标]</h4><ol><li>掌握操作系统的基本概念、方法和原理,了解操作系统的结构、功能和服务,理解操作系统所采用的策略算法和机制。</li><li>能够从计算机系统的角度理解并描述应用程序、操作系统内核和计算机硬件协同完成任务的过程。</li><li>能够运用操作系统的原理,分析并解决计算机系统中与操作系统相关的问题。</li></ol><h4 id="一、操作系统基础">一、操作系统基础</h4><p><a href="https://blog.cxhap.top/2024/08/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80/">笔记</a></p><h5 id="(一)操作系统的基本概念">(一)操作系统的基本概念</h5><h5 id="(二)操作系统的发展历程">(二)操作系统的发展历程</h5><p><a href="https://blog.cxhap.top/2024/07/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%91%E5%B1%95%E5%8E%86%E7%A8%8B/">笔记</a></p><h5 id="(三)程序的运行环境">(三)程序的运行环境</h5><ol><li>CPU 运行环境</li></ol><p>内核模式,用户模式。</p><ol start="2"><li>中断和异常的处理</li><li>系统调用</li><li>程序的链接与装入</li><li>程序运行时的内存映像与地址空间</li></ol><h5 id="(四)操作系统结构">(四)操作系统结构</h5><p>分层,模块化,宏内核,微内核,外核。</p><h5 id="(五)操作系统引导">(五)操作系统引导</h5><h5 id="(六)虚拟机">(六)虚拟机</h5><h4 id="二、进程管理">二、进程管理</h4><p><a href="https://blog.cxhap.top/2024/08/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/">笔记</a></p><h5 id="(一)进程与线程">(一)进程与线程</h5><ol><li>进程与线程的基本概念</li><li>进程的状态与转换</li><li>线程的实现</li></ol><p>内核支持的线程,线程库支持的线程。</p><ol start="4"><li>进程与线程的组织与控制</li><li>进程间通信</li></ol><p>共享内存,消息传递,管道。</p><h5 id="(二)CPU-调度与上下文切换">(二)CPU 调度与上下文切换</h5><ol><li>调度的基本概念</li><li>调度的目标</li><li>调度的实现</li></ol><p>调度器/调度程序(scheduler),调度的时机与调度方式(抢占式/非抢占式),闲逛进程,内核级线程与用户级线程调度。</p><ol start="4"><li>典型调度算法</li></ol><p>先来先服务调度算法,短作业(短进程、短线程)优先调度算法,时间片轮转调度算法,优先级调度算法,高响应比优先调度算法,多级队列调度算法,多级反馈队列调度算法。</p><ol start="5"><li>上下文及其切换机制</li></ol><h5 id="(三)同步与互斥">(三)同步与互斥</h5><ol><li>同步与互斥的基本概念</li><li>基本的实现方法</li></ol><p>软件方法,硬件方法。</p><ol start="3"><li>锁</li><li>信号量</li><li>条件变量</li><li>经典同步问题</li></ol><p>生产者-消费者问题,读者-写者问题,哲学家进餐问题等。</p><h5 id="(四)死锁">(四)死锁</h5><ol><li>死锁的基本概念</li><li>死锁预防</li><li>死锁避免</li><li>死锁检测和解除</li></ol><h4 id="三、内存管理">三、内存管理</h4><p><a href="https://blog.cxhap.top/2024/08/20/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">笔记</a></p><h5 id="(一)内存管理基础">(一)内存管理基础</h5><ol><li>内存管理的基本概念</li></ol><p>逻辑地址空间与物理地址空间,地址变换,内存共享,内存保护,内存分配与回收。</p><ol start="2"><li>连续分配管理方式</li><li>页式管理</li><li>段式管理</li><li>段页式管理</li></ol><h5 id="(二)虚拟内存管理">(二)虚拟内存管理</h5><ol><li>虚拟内存的基本概念</li><li>请求页式管理</li><li>页框分配</li><li>页面置换算法</li></ol><p>最佳置换算法(OPT);先进先出置换算法(FIFO);最近最少使用置换算法(LRU);时钟置换算法(CLOCK)。</p><ol start="5"><li>内存映射文件(Memory-Mapped Flies)</li><li>虚拟存储器性能的影响因素及改进方法</li></ol><h4 id="四、文件管理">四、文件管理</h4><p><a href="https://blog.cxhap.top/2024/08/21/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86/">笔记</a></p><h5 id="(一)文件">(一)文件</h5><ol><li>文件的基本概念</li><li>文件元数据和索引结点(inode)</li><li>文件的操作</li></ol><p>建立,删除,打开,关闭,读,写。</p><ol start="4"><li>文件的保护</li><li>文件的逻辑结构</li><li>文件的物理结构</li></ol><h5 id="(二)目录">(二)目录</h5><ol><li>目录的基本概念</li><li>树形目录</li><li>目录的操作</li><li>硬链接和软链接</li></ol><h5 id="(三)文件系统">(三)文件系统</h5><ol><li>文件系统的全局结构(layout)</li></ol><p>文件系统在外存中的结构,文件系统在内存中的结构。</p><ol start="2"><li>外存空闲空间管理方法</li><li>虚拟文件系统</li><li>文件系统挂载(mounting)</li></ol><h4 id="五、输入-输出-I-O-管理">五、输入/输出(I/O)管理</h4><p><a href="https://blog.cxhap.top/2024/08/22/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BE%93%E5%85%A5-%E8%BE%93%E5%87%BA-I-O-%E7%AE%A1%E7%90%86/">笔记</a></p><h5 id="(一)I-O-管理基础">(一)I/O 管理基础</h5><ol><li>设备</li></ol><p>设备的基本概念,设备的分类,I/O 接口,I/O 端口。</p><ol start="2"><li>I/O 控制方式</li></ol><p>轮询方式,中断方式,DMA 方式。</p><ol start="3"><li>I/O 软件层次结构</li></ol><p>中断处理程序,驱动程序,设备独立软件,用户层I/O软件。</p><ol start="4"><li>输入/输出应用程序接口</li></ol><p>字符设备接口,块设备接口,网络设备接口,阻塞/非阻塞I/O。</p><h5 id="(二)设备独立文件">(二)设备独立文件</h5><ol><li>缓存区管理</li><li>设备分配和回收</li><li>假脱机技术(SPOOLing)</li><li>设备驱动程序接口</li></ol><h5 id="(三)外存管理">(三)外存管理</h5><ol><li>磁盘</li></ol><p>磁盘结构,格式化,分区,磁盘调度方法。</p><ol start="2"><li>固态硬盘</li></ol><p>读写性能特性,磨损均衡。</p> </div> </div> </div><h3 id="计算机网络">计算机网络</h3> <div class="fold"> <div class="fold-title fold-info collapsed" data-toggle="collapse" href="#collapse-2c9f2df9" role="button" aria-expanded="false" aria-controls="collapse-2c9f2df9"> <div class="fold-arrow">▶</div>计算机网络大纲 </div> <div class="fold-collapse collapse" id="collapse-2c9f2df9"> <div class="fold-content"> <blockquote><p>参考教材:《计算机网络第8版》(谢希仁版)</p></blockquote><h4 id="考查目标">[考查目标]</h4><ol><li>掌握计算机网络的基本概念、基本原理和基本方法。</li><li>掌握计算机网络的体系结构和典型网络协议,了解典型网络设备的组成和特点,理解典型网络设备的工作原理。</li><li>能够运用计算机网络的基本概念、基本原理和基本方法进行网络系统的分析、设计和应用。</li></ol><h4 id="一、计算机网络概述">一、计算机网络概述</h4><p><a href="https://blog.cxhap.top/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/">笔记</a></p><h5 id="(一)计算机网络基本概念">(一)计算机网络基本概念</h5><p><a href="https://blog.cxhap.top/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/#%E4%B8%80%E3%80%81%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">笔记</a></p><ol><li>计算机网络的定义、组成与功能</li><li>计算机网络的分类</li><li>计算机网络的主要性能指标</li></ol><h5 id="(二)计算机网络体系结构">(二)计算机网络体系结构</h5><p><a href="https://blog.cxhap.top/2024/08/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/#%E4%BA%8C%E3%80%81%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84">笔记</a></p><ol><li>计算机网络分层结构</li><li>计算机网络协议、接口、服务等概念</li><li>ISO / OSI参考模型和TCP / IP模型</li></ol><h4 id="二、物理层">二、物理层</h4><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/">笔记</a></p><h5 id="(一)通信基础">(一)通信基础</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/#%E4%B8%80%E3%80%81%E9%80%9A%E4%BF%A1%E5%9F%BA%E7%A1%80">笔记</a></p><ol><li>信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念</li><li>奈奎斯特定理与香农定理</li><li>编码与调制</li><li>电路交换、报文交换与分组交换</li><li>数据报与虚电报</li></ol><h5 id="(二)传输介质">(二)传输介质</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/#%E4%BA%8C%E3%80%81%E4%BC%A0%E8%BE%93%E4%BB%8B%E8%B4%A8">笔记</a></p><ol><li>双绞线、同轴电缆、光纤与无线传输介质</li><li>物理层接口的特性</li></ol><h5 id="(三)物理层设备">(三)物理层设备</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%89%A9%E7%90%86%E5%B1%82/#%E4%B8%89%E3%80%81%E7%89%A9%E7%90%86%E5%B1%82%E8%AE%BE%E5%A4%87">笔记</a></p><ol><li>中继器</li><li>集线器</li></ol><h4 id="三、数据链路层">三、数据链路层</h4><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/">笔记</a></p><h5 id="(一)数据链路层的功能">(一)数据链路层的功能</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E4%B8%80%E3%80%81%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82%E7%9A%84%E5%8A%9F%E8%83%BD">笔记</a></p><h5 id="(二)组帧">(二)组帧</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E4%BA%8C%E3%80%81%E7%BB%84%E5%B8%A7">笔记</a></p><h5 id="(三)差错控制">(三)差错控制</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E4%B8%89%E3%80%81%E5%B7%AE%E9%94%99%E6%8E%A7%E5%88%B6">笔记</a></p><ol><li>检错编码</li><li>纠错编码</li></ol><h5 id="(四)流量控制与可靠传输机制">(四)流量控制与可靠传输机制</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E5%9B%9B%E3%80%81%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6%E4%B8%8E%E5%8F%AF%E9%9D%A0%E4%BC%A0%E8%BE%93%E6%9C%BA%E5%88%B6">笔记</a></p><ol><li>流量控制、可靠传输与滑动窗口机制</li><li>停止 - 等待协议</li><li>后退N帧协议( GBN )</li><li>选择重传协议( SR )</li></ol><h5 id="(五)介质访问控制">(五)介质访问控制</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E4%BA%94%E3%80%81%E4%BB%8B%E8%B4%A8%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6">笔记</a></p><ol><li>信道划分</li></ol><p>频分多路复用、时分多路复用、波分多路复用、码分多路复用的概念和基本原理。</p><ol start="2"><li>随机访问</li></ol><p>ALOHA 协议;CSMA 协议;CSMA/CD 协议;CSMA/CA 协议。</p><ol start="3"><li>轮询访问</li></ol><p>令牌传递协议。</p><h5 id="(六)局域网">(六)局域网</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E5%85%AD%E3%80%81%E5%B1%80%E5%9F%9F%E7%BD%91">笔记</a></p><ol><li>局域网的基本概念与体系结构</li><li>以太网与IEEE 802.3</li><li>IEEE 802.11无线局域网</li><li>VLAN 基本概念与基本原理</li></ol><h5 id="(七)广域网">(七)广域网</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E4%B8%83%E3%80%81%E5%B9%BF%E5%9F%9F%E7%BD%91">笔记</a></p><ol><li>广域网的基本概念</li><li>PPP 协议</li></ol><h5 id="(八)数据链路层设备">(八)数据链路层设备</h5><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/#%E5%85%AB%E3%80%81%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82%E8%AE%BE%E5%A4%87">笔记</a></p><p>以太网交换机及其工作原理</p><h4 id="四、网络层">四、网络层</h4><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E7%BD%91%E7%BB%9C%E5%B1%82/">笔记</a></p><h5 id="(一)网络层的功能">(一)网络层的功能</h5><ol><li>异构网络互连</li><li>路由和转发</li><li>SDN 基本概念</li><li>阻塞控制</li></ol><h5 id="(二)路由算法">(二)路由算法</h5><ol><li>静态路由与动态路由</li><li>距离-向量路由算法</li><li>链路状态路由算法</li><li>层次路由</li></ol><h5 id="(三)IPv4">(三)IPv4</h5><ol><li>IPv4 分组</li><li>IPv4 地址与 NAT</li><li>子网划分、路由聚集、子网掩码与 CIDR</li><li>ARP 协议、DHCP 协议与 ICMP 协议</li></ol><h5 id="(四)IPv6">(四)IPv6</h5><ol><li>Ipv6 的主要特点</li><li>IPv6 地址</li></ol><h5 id="(五)路由协议">(五)路由协议</h5><ol><li>自治系统</li><li>域内路由与域间路由</li><li>RIP 路由协议</li><li>OSPF 路由协议</li><li>BGP 路由协议</li></ol><h5 id="(六)IP组播">(六)IP组播</h5><ol><li>组播的概念</li><li>IP 组播地址</li></ol><h5 id="(七)移动-IP">(七)移动 IP</h5><ol><li>移动 IP 的概念</li><li>移动 IP 的通信过程</li></ol><h5 id="(八)网络层设备">(八)网络层设备</h5><ol><li>路由器的组成和功能</li><li>路由表与分组转发</li></ol><h4 id="五、传输层">五、传输层</h4><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E4%BC%A0%E8%BE%93%E5%B1%82/">笔记</a></p><h5 id="(一)传输层提供的服务">(一)传输层提供的服务</h5><ol><li>传输层的功能</li><li>传输层寻址与端口</li><li>无连接服务与面向连接服务</li></ol><h5 id="(二)UDP-协议">(二)UDP 协议</h5><ol><li>UDP 数据报</li><li>UDP 校验</li></ol><h5 id="(三)TCP-协议">(三)TCP 协议</h5><ol><li>TCP 段</li><li>TCP 连接管理</li><li>TCP 可靠传输</li><li>TCP 流量控制</li><li>TCP 拥塞控制</li></ol><h4 id="六、应用层">六、应用层</h4><p><a href="https://blog.cxhap.top/2024/08/16/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%80%94%E2%80%94%E5%BA%94%E7%94%A8%E5%B1%82/">笔记</a></p><h5 id="(一)网络应用模型">(一)网络应用模型</h5><ol><li>客户/服务端(C/S)模型</li><li>对等(P2P)模型</li></ol><h5 id="(二)DNS-系统">(二)DNS 系统</h5><ol><li>层次域名空间</li><li>域名服务器</li><li>域名解析过程</li></ol><h5 id="(三)FTP">(三)FTP</h5><ol><li>FTP 协议的工作原理</li><li>控制连接与数据连接</li></ol><h5 id="(四)电子邮件">(四)电子邮件</h5><ol><li>电子邮件系统的组成结构</li><li>电子邮件的结构与 MIME</li><li>SMTP 协议与POP3 协议</li></ol><h5 id="(五)WWW">(五)WWW</h5><ol><li>WWW 的概念与组成结构</li><li>HTTP 协议</li></ol> </div> </div> </div>]]></content>
<categories>
<category>0812计算机考研408</category>
</categories>
<tags>
<tag>计算机科学与技术</tag>
<tag>812</tag>
<tag>考试大纲</tag>
</tags>
</entry>
<entry>
<title>使用Github Pages与Actions搭建个人Hexo博客</title>
<link href="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/"/>
<url>/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/</url>
<content type="html"><![CDATA[<h1>使用Github Pages与Actions搭建个人Hexo博客</h1><h2 id="引言">引言</h2><p>作为一名计算机专业的学生,拥有一个自己的博客网站无疑是一件非常酷的事情。然而,搭建一个网站不仅需要完成大量的工作,还需要支付一定的费用来购买或租用服务器并进行维护。那么,有没有一种更简单的方法来搭建博客呢?答案是肯定的。正如标题所示,我们可以利用 GitHub Pages 来搭建一个全前端的网站,轻松实现我们的博客需求。</p><h2 id="Hexo-介绍">Hexo 介绍</h2><p>Hexo 是一个快速、简洁且高效的静态博客框架。它使用 Markdown 或其他渲染引擎生成静态文件,并且支持丰富的插件和主题,方便用户自定义博客的外观和功能。</p><blockquote><p>以下内容部分由ChatGPT生成。</p></blockquote><h3 id="为什么选择-Hexo?">为什么选择 Hexo?</h3><ol><li><strong>性能优越</strong>:Hexo 生成的静态页面加载速度非常快,这得益于它生成的文件不需要服务器端的动态处理。</li><li><strong>易于使用</strong>:Hexo 提供了简单易用的命令行工具,方便用户快速创建、发布和管理博客内容。</li><li><strong>灵活的插件系统</strong>:Hexo 拥有丰富的插件库,用户可以根据需要安装插件来扩展博客的功能,如评论系统、搜索功能等。</li><li><strong>强大的主题支持</strong>:Hexo 社区有大量精美的主题可供选择,用户可以轻松更换博客的外观,使其更具个性化。</li><li><strong>活跃的社区</strong>:Hexo 拥有一个活跃的社区,用户可以通过社区获得帮助,分享经验和资源。</li></ol><h3 id="Hexo-的基本架构">Hexo 的基本架构</h3><p>Hexo 的架构主要包括以下几个部分:</p><ol><li><strong>Hexo 核心</strong>:负责博客的基本功能,如文章管理、静态文件生成等。</li><li><strong>Hexo 插件</strong>:用于扩展 Hexo 功能的模块,例如 SEO 优化、RSS 生成等。</li><li><strong>Hexo 主题</strong>:决定博客外观和布局的模板文件,用户可以根据喜好选择和更换主题。</li><li><strong>Hexo 渲染引擎</strong>:负责将 Markdown 等格式的源文件渲染为 HTML 静态文件。</li></ol><h3 id="post和page的区别">post和page的区别</h3><p>在 Hexo 中,<code>page</code>(页面)和 <code>post</code>(文章)是两种常用的不同类型的内容:</p><ol><li><p><strong>Post(文章)</strong>:</p><ul><li><strong>定义</strong>:Post 是指博客中的文章或日志,通常是按时间顺序排列的内容,例如博客文章、新闻稿等。</li><li><strong>存放位置</strong>:通常存放在 <code>source/_posts</code> 目录下(可以在配置文件中指定其他目录)。</li><li><strong>命名规则</strong>:通常以 Markdown 或其他支持的格式书写,并以日期和标题命名,例如 <code>2024-07-10-my-first-post.md</code>。</li><li><strong>生成</strong>:生成时会被自动排序和归档,可以通过配置自动生成目录、标签、分类等信息。</li></ul></li><li><p><strong>Page(页面)</strong>:</p><ul><li><strong>定义</strong>:Page 是指博客中的静态页面,通常不按时间顺序排列,而是作为独立的页面存在,如关于页面、联系页面等。</li><li><strong>存放位置</strong>:通常存放在 <code>source</code> 目录下或 <code>source</code> 下的其他子目录中,如 <code>source/about/index.md</code>。</li><li><strong>命名规则</strong>:可以是 Markdown 格式,也可以是其他支持的格式,文件名通常就是页面的路径。</li><li><strong>生成</strong>:生成时作为站点的固定页面存在,可以通过导航链接访问。</li></ul></li></ol><h3 id="如何开始使用-Hexo?">如何开始使用 Hexo?</h3><blockquote><p>跳转到<a href="#%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2Hexo%E5%8D%9A%E5%AE%A2">本地部署Hexo博客</a>?</p></blockquote><ol><li><strong>安装 Node.js 和 Git</strong>:Hexo 依赖于 Node.js 和 Git,首先需要在系统中安装这两个工具。</li><li><strong>安装 Hexo</strong>:使用 npm(Node.js 包管理工具)安装 Hexo:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">npm install -g hexo-cli<br></code></pre></td></tr></table></figure></li><li><strong>初始化博客</strong>:在目标目录下初始化一个新的 Hexo 博客:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo init my-blog<br><span class="hljs-built_in">cd</span> my-blog<br>npm install<br></code></pre></td></tr></table></figure></li><li><strong>创建文章</strong>:使用 Hexo 提供的命令创建新文章:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo new <span class="hljs-string">"My First Post"</span><br></code></pre></td></tr></table></figure></li><li><strong>生成和预览</strong>:生成静态文件并在本地服务器中预览博客:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo generate<br>hexo server<br></code></pre></td></tr></table></figure>在浏览器中访问 <code>http://localhost:4000</code> 查看博客效果。</li></ol><h3 id="部署到-GitHub-Pages">部署到 GitHub Pages</h3><p>Hexo 提供了简便的部署命令,可以将生成的静态文件直接部署到 GitHub Pages:</p><ol><li><strong>配置部署信息</strong>:在博客根目录的 <code>_config.yml</code> 文件中配置 GitHub Pages 的仓库信息:<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">deploy:</span><br> <span class="hljs-attr">type:</span> <span class="hljs-string">git</span><br> <span class="hljs-attr">repo:</span> <span class="hljs-string">https://github.com/username/username.github.io.git</span><br> <span class="hljs-attr">branch:</span> <span class="hljs-string">main</span><br></code></pre></td></tr></table></figure></li><li><strong>安装部署插件</strong>:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">npm install hexo-deployer-git --save<br></code></pre></td></tr></table></figure></li><li><strong>执行部署命令</strong>:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo deploy<br></code></pre></td></tr></table></figure></li></ol><p>通过以上步骤,你就可以轻松地将 Hexo 博客部署到 GitHub Pages 上,拥有一个免费的个人博客网站。</p><h2 id="本地部署Hexo博客">本地部署Hexo博客</h2><p>基本步骤可参考GPT生成部分<a href="#%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-Hexo%EF%BC%9F">如何开始使用 Hexo?</a>。node.js与git的安装与配置可根据不同的操作系统在网上查找安装方法,下面将对基础的安装步骤进行补充。</p><h3 id="切换主题">切换主题</h3><p>Hexo提供了许多免费的主题可供直接使用,用户可以个性化选择主题以达到自己想要的结果,可以去<a href="https://hexo.io/themes/">Hexo官方主题仓库</a>挑选自己喜欢的主题。但需要注意的是,每款主题的配置文件可能各不相同,我使用的是<strong>Fluid</strong>主题,下面的配置以该主题为准,大家可自行根据配置文件注释进行配置。</p><h4 id="下载主题">下载主题</h4><p>前往Fluid主题官方<a href="https://github.com/fluid-dev/hexo-theme-fluid">Github仓库</a>下载zip压缩包即可,直接解压至my_blog/theme目录,并将<strong>hexo-theme-fluid</strong>更名为<strong>fluid</strong>。</p><blockquote><p>顺便在这里解释一下Hexo项目的目录结构,<code>node_modules</code>是nodejs自动生成的模块目录,<code>public</code>是编译出的静态页面地址,<code>scaffolds</code>是自动新建的页面或博客模板文件,<code>source</code>中存放页面和post的源文件(.md形式)以及部分图片,其中页面单独成一个目录,博客文件则存放在<code>_posts</code>中,关于post和页面的区别请见<a href="#post%E5%92%8Cpage%E7%9A%84%E5%8C%BA%E5%88%AB">post和page的区别</a>,<code>theme</code>中存放主题。</p></blockquote><h4 id="应用主题">应用主题</h4><p>寻找my_blog根目录下配置文件**_config.yml**,找到<strong>theme</strong>这一行,修改为<code>theme: fluid</code>,别忘了:后面有一个空格。修改完配置文件后自己去看看效果吧:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo generate<br>hexo server<br></code></pre></td></tr></table></figure><h3 id="更多配置内容">更多配置内容</h3><p>为了节约篇幅和更直观形象,下面将用表格呈现一些有用的配置内容。需要注意的是,一个Hexo项目有一个自己的配置文件<code>_config.yml</code>,此外每个主题还有一个自己的配置文件<code>themes/fluid/_config.yml</code>。</p><p>表1:_config.yml</p><table><thead><tr><th>键(Key)</th><th>值(Val)</th><th>描述(Description)</th></tr></thead><tbody><tr><td>title</td><td>Your Blog Title</td><td>浏览器tab页名称</td></tr><tr><td>subtitle</td><td>Your Subtitle</td><td>title的副标题</td></tr><tr><td>description</td><td>Your description</td><td>网站的描述</td></tr><tr><td>author</td><td>Your Name</td><td>文章作者名</td></tr><tr><td>language</td><td>“zh-CN”</td><td>网站语言</td></tr><tr><td>timezone</td><td>‘’</td><td>时区设置,可置空</td></tr><tr><td>url</td><td>Your Blog url</td><td>可设置成Github Page的地址</td></tr><tr><td>new_post_name</td><td>:year-:month-:day-:title.md</td><td>post的模板标题</td></tr><tr><td>post_asset_folder</td><td>true</td><td>为每个post自动建立资源文件夹</td></tr><tr><td>theme</td><td>fluid</td><td>所使用的主题名称</td></tr></tbody></table><p>表2:themes/fluid/_config.yml</p><table><thead><tr><th>键(Key)</th><th>值(Val)</th><th>描述(Description)</th></tr></thead><tbody><tr><td>favicon</td><td>/img/fluid.png</td><td>浏览器标签的图标</td></tr><tr><td>apple_touch_icon</td><td>/img/fluid.png</td><td>苹果设备的图标</td></tr><tr><td>blog_title</td><td>Your blog_title</td><td>导航栏左侧的标题</td></tr><tr><td>menu</td><td>…</td><td>导航栏菜单,可自行添加页面</td></tr><tr><td>index/slogan/text</td><td>…</td><td>显示在主页的文字</td></tr><tr><td>about/*</td><td>…</td><td>自定义关于页面的个人信息</td></tr></tbody></table><p>以上只是我建议修改的配置内容,如查找进阶内容请参考<a href="https://fluid-dev.github.io/hexo-fluid-docs/guide/#%E5%85%B3%E4%BA%8E%E6%8C%87%E5%8D%97">Hexo Fluid 用户手册</a>与<a href="https://hexo.io/zh-cn/docs/">Hexo手册</a>自行研究。</p><h3 id="增加阅读量统计">增加阅读量统计</h3><p>参考文章<a href="http://minghuijia.cn/2022/03/14/Hexo-fluid%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE%E7%BB%9F%E8%AE%A1%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB%E9%87%8F/">Hexo-fluid主题设置统计博客阅读量</a></p><h3 id="增加评论功能">增加评论功能</h3><p>参考文章<a href="http://minghuijia.cn/2022/03/14/Hexo-fluid%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE%E7%BB%9F%E8%AE%A1%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB%E9%87%8F/">Hexo-fluid主题设置统计博客阅读量</a></p><h3 id="显示数学公式">显示数学公式</h3><blockquote><p>参考官方配置指南<a href="https://fluid-dev.github.io/hexo-fluid-docs/guide/#latex-%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F">latex-数学公式</a>,基本配置和官方类似,但需要注意安装pandoc工具(使用mathjax),否则会报错。</p></blockquote><h4 id="1-设置主题配置">1. 设置主题配置</h4><p>编辑主题配置文件themes/fluid/_config.yml</p> <figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">post:</span><br><span class="hljs-attr">math:</span><br> <span class="hljs-attr">enable:</span> <span class="hljs-literal">true</span><br> <span class="hljs-attr">specific:</span> <span class="hljs-literal">false</span><br> <span class="hljs-attr">engine:</span> <span class="hljs-string">mathjax</span><br></code></pre></td></tr></table></figure><p><code>specific</code>: 建议开启。当为 true 时,只有在文章 front-matter (opens new window)里指定 <code>math: true</code> 才会在文章页启动公式转换,以便在页面不包含公式时提高加载速度。</p><p><code>engine</code>: 公式引擎,目前支持 <code>mathjax</code> 或 <code>katex</code>。</p><h4 id="2-更换-Markdown-渲染器">2. 更换 Markdown 渲染器</h4><p>由于 Hexo 默认的 Markdown 渲染器不支持复杂公式,所以需要更换渲染器(mathjax 可选择性更换)。</p><p>然后根据上方配置不同的 <code>engine</code>,推荐更换如下渲染器:</p><ol><li>mathjax</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">npm uninstall hexo-renderer-marked --save<br>npm install hexo-renderer-pandoc --save<br></code></pre></td></tr></table></figure><p>并且还需安装pandoc</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install pandoc -y<br></code></pre></td></tr></table></figure><ol start="2"><li>katex</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">npm uninstall hexo-renderer-marked --save<br>npm install hexo-renderer-markdown-it --save<br>npm install @traptitech/markdown-it-katex --save<br></code></pre></td></tr></table></figure><p>然后在站点配置中添加:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">markdown:</span><br> <span class="hljs-attr">plugins:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">"@traptitech/markdown-it-katex"</span><br></code></pre></td></tr></table></figure><h4 id="清理环境">清理环境</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo clean<br></code></pre></td></tr></table></figure><h2 id="添加博客页面与文章">添加博客页面与文章</h2><h3 id="添加About页面">添加About页面</h3><p>使用<code>hexo new page about</code>即可新建一个about页面,页面默认存放在<strong>source</strong>文件夹中,一个页面就是一个文件夹。</p><h3 id="从模板新建文章">从模板新建文章</h3><p>同理,使用<code>hexo new post newpost</code>即可新建一篇文章,文章默认存放在<strong>source/_posts</strong>文件夹中,所有的文章都存储在**_posts**文件夹中,但可在文章同级目录建立同名文件夹以存放图片等资源文件,如下图。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/1.png" class="" title="post目录结构"><h2 id="配置Github-Action自动发布到Github-Page">配置Github Action自动发布到Github Page</h2><p>经过上面的配置操作,相信你已经成功在本地运行起来了自己的博客,但仅仅运行在本地肯定不够,我们需要将博客推送到github page中,通过username.github.io或是通过自己的域名进行访问。</p><h3 id="原理">原理</h3><p>github page支持的是静态页面,而hexo编译后生成的<code>public</code>文件夹内存放的便是静态页面,因此我们只需要将<code>public</code>文件夹内的内容推送至个人github page仓库即可。</p><h3 id="准备工作">准备工作</h3><p>首先你需要注册一个自己的github账号,并且进行了一系列的安全配置工作。</p><h4 id="创建Github仓库">创建Github仓库</h4><p>我们需要创建两个仓库来完成操作,其中一个仓库名随意,我使用的名称是hexo-blog,另一个仓库名必须以<code>yourusername.github.io</code>为名字,在创建时会提示你这个仓库是特殊仓库,如下图(因为我预先创建过了,显示仓库已存在)。其中<code>yourusername.github.io</code>仓库必须设为<strong>public</strong>。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/2.png" class="" title="创建仓库"><h4 id="配置git">配置git</h4><p>我们需要使用git工具来将本地代码推送至github仓库,git工具在第一次使用前必须进行相关配置。参考<a href="https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%88%9D%E6%AC%A1%E8%BF%90%E8%A1%8C-Git-%E5%89%8D%E7%9A%84%E9%85%8D%E7%BD%AE">官方文档</a>。</p><h4 id="同步代码">同步代码</h4><p>为了便于操作,我使用vscode来完成git推送工作,我们首先使用git工具克隆一份空仓库,仓库地址可从Github获取,如下图。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/3.png" class="" title="仓库URL"><p>在终端使用命令<code>git clone your-repository-url</code>克隆到本地,并且将之前创建的hexo项目复制到文件夹下(要将my_blog下的所有文件以及文件夹复制到hexo-blog文件夹下,而不是复制整个my_blog文件夹),接着使用vscode打开文件夹,保持目录结构如下图。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/4.png" class="" title="目录结构"><p>然后试试vscode的源代码管理功能吧。这里第一次点击提交是提交更改,第二次则是同步到仓库,第一次提交时必须填写消息。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/5.png" class="" title="源代码管理"><p>同步完成后,去Github仓库看下是否同步成功吧。</p><h4 id="拷贝主题配置文件">拷贝主题配置文件</h4><p>由于我的github action脚本会自动拉取最新版本主题,因此主题的配置文件必须保存在其他地方,在部署时复制进去即可,因此我们提前将主题配置文件<code>themes/fluid/_config.yml</code>复制到<code>_config_theme.yml</code>。</p><h4 id="配置github-action">配置github action</h4><h5 id="配置SSH密钥对">配置SSH密钥对</h5><p>使用命令<code>ssh-keygen -f github-deploy-key</code>在当前工作目录下可生成文件<code>github-deploy-key</code>和<code>github-deploy-key.pub</code>。</p><p>复制 github-deploy-key 文件内容,在 hexo-blog 仓库 <code>Settings -> Secrets and variables -> Actions -> New repository secret</code> 页面上添加。</p><ol><li>在 Name 输入框填写 HEXO_DEPLOY_PRI。</li><li>在 Value 输入框填写 github-deploy-key 文件内容。</li></ol><p>复制 github-deploy-key.pub 文件内容,在 <a href="http://your.github.io">your.github.io</a> 仓库 Settings -> Deploy keys -> Add deploy key 页面上添加。</p><ol><li>在 Title 输入框填写 HEXO_DEPLOY_PUB。</li><li>在 Key 输入框填写 github-deploy-key.pub 文件内容。</li><li>勾选 Allow write access 选项。</li></ol><h5 id="配置GH-Token">配置GH_Token</h5><p>使用hexo-deployer-git工具部署时需要github personal access token,而且这个token是不能写在配置文件中的,因此只能写在仓库环境变量中,在action部署时自动获取。点击你的GitHub头像 -> 设置 -> 开发者设置 -> Personal access tokens -> Generate new token来获取这个token,设置权限时只需要设置有关repository的读写权限即可。<br>复制 personal access token 内容,在 hexo-blog 仓库 <code>Settings -> Secrets and variables -> Actions -> New repository secret</code> 页面上添加。</p><ol><li>在 Name 输入框填写 GH_TOKEN。</li><li>在 Value 输入框填写 personal access token 内容。</li></ol><h5 id="添加github-action">添加github action</h5><p>新建文件<code>.github/workflows/deploy.yml</code>,将下面的模板内容粘贴进去,然后根据自己的需要进行修改,需要修改的地方已标出。</p> <figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">CI</span><br><br><span class="hljs-attr">on:</span><br><span class="hljs-attr">push:</span><br> <span class="hljs-attr">branches:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">master</span><br><br><span class="hljs-attr">env:</span><br><span class="hljs-attr">GIT_USER:</span> <span class="hljs-string">DingWH03</span> <span class="hljs-comment"># 这里更改为自己的Github用户名</span><br><span class="hljs-attr">GIT_EMAIL:</span> <span class="hljs-number">2521248869</span><span class="hljs-string">@qq.com</span> <span class="hljs-comment"># 这里更改为自己的Github绑定的邮箱</span><br><span class="hljs-attr">THEME_REPO:</span> <span class="hljs-string">fluid-dev/hexo-theme-fluid</span> <span class="hljs-comment"># 这里更改为你使用的主题的git仓库,省略github.com</span><br><span class="hljs-attr">THEME_BRANCH:</span> <span class="hljs-string">master</span> <span class="hljs-comment"># 这里更改为你使用的主题的git分支</span><br><span class="hljs-attr">DEPLOY_REPO:</span> <span class="hljs-string">DingWH03/dingwh03.github.io</span> <span class="hljs-comment"># 这里更改为你自己的仓库地址,省略github.com</span><br><span class="hljs-attr">DEPLOY_BRANCH:</span> <span class="hljs-string">main</span> <span class="hljs-comment"># 这里更改为你自己的仓库分支,一般都是main</span><br><br><span class="hljs-attr">jobs:</span><br><span class="hljs-attr">build:</span><br> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">on</span> <span class="hljs-string">node</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node_version</span> <span class="hljs-string">}}</span> <span class="hljs-string">and</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.os</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span><br> <span class="hljs-attr">strategy:</span><br> <span class="hljs-attr">matrix:</span><br> <span class="hljs-attr">os:</span> [<span class="hljs-string">ubuntu-latest</span>]<br> <span class="hljs-attr">node_version:</span> [<span class="hljs-number">16.</span><span class="hljs-string">x</span>]<br><br> <span class="hljs-attr">steps:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span><br> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span><br><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">theme</span> <span class="hljs-string">repo</span><br> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span><br> <span class="hljs-attr">with:</span><br> <span class="hljs-attr">repository:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.THEME_REPO</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">ref:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.THEME_BRANCH</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">path:</span> <span class="hljs-string">themes/fluid</span> <span class="hljs-comment"># 这里更换成你的主题所在路径</span><br><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">deploy</span> <span class="hljs-string">repo</span><br> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span><br> <span class="hljs-attr">with:</span><br> <span class="hljs-attr">repository:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.DEPLOY_REPO</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">ref:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.DEPLOY_BRANCH</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">path:</span> <span class="hljs-string">.deploy_git</span><br><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node_version</span> <span class="hljs-string">}}</span><br> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span><br> <span class="hljs-attr">with:</span><br> <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node_version</span> <span class="hljs-string">}}</span><br><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configuration</span> <span class="hljs-string">environment</span><br> <span class="hljs-attr">env:</span><br> <span class="hljs-attr">HEXO_DEPLOY_PRI:</span> <span class="hljs-string">${{secrets.HEXO_DEPLOY_PRI}}</span><br> <span class="hljs-attr">GH_TOKEN:</span> <span class="hljs-string">${{secrets.GH_TOKEN}}</span><br> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span><br><span class="hljs-string"> sudo apt-get install pandoc -y # pandoc是为了启用数学公式渲染</span><br><span class="hljs-string"> sudo timedatectl set-timezone "Asia/Shanghai"</span><br><span class="hljs-string"> mkdir -p ~/.ssh/</span><br><span class="hljs-string"> echo "$HEXO_DEPLOY_PRI" > ~/.ssh/id_rsa</span><br><span class="hljs-string"> chmod 600 ~/.ssh/id_rsa</span><br><span class="hljs-string"> ssh-keyscan github.com >> ~/.ssh/known_hosts</span><br><span class="hljs-string"> git config --global user.name $GIT_USER</span><br><span class="hljs-string"> git config --global user.email $GIT_EMAIL</span><br><span class="hljs-string"> cp _config_theme.yml themes/fluid/_config.yml # 拷贝主题的配置文件</span><br><span class="hljs-string"> sed -i "s|token:.*|token: ${GH_TOKEN}|" _config.yml </span><br><span class="hljs-string"></span><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span><br> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span><br><span class="hljs-string"> npm install</span><br><span class="hljs-string"></span><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">hexo</span><br> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span><br><span class="hljs-string"> npm run deploy</span><br><span class="hljs-string"></span> <br> <span class="hljs-comment">#- name: Add CNAME file # 这部分用来为github page添加自己的域名,后面会讲</span><br> <span class="hljs-comment">#run: |</span><br> <span class="hljs-comment"># echo "blog.cxhap.top" > .deploy_git/CNAME # 改成你的域名地址</span><br> <span class="hljs-comment"># cd .deploy_git</span><br> <span class="hljs-comment"># git config user.name "$GIT_USER"</span><br> <span class="hljs-comment"># git config user.email "$GIT_EMAIL"</span><br> <span class="hljs-comment"># git add CNAME</span><br> <span class="hljs-comment"># git commit -m "Add CNAME file for custom domain"</span><br> <span class="hljs-comment"># git remote set-url origin git@github.com:DingWH03/dingwh03.github.io.git</span><br> <span class="hljs-comment"># git push origin HEAD:main</span><br></code></pre></td></tr></table></figure><h5 id="为github-page添加自己的域名">为github page添加自己的域名</h5><blockquote><p>最新更正,现在有更简单的方法,编写一个文件名为CNAME存放在<code>source/CNAME</code>,文件内容为你的域名,在部署时会直接放置到github page根目录,这样做或避免相邻两次重复部署github page。<br>参考<a href="https://github.com/hexojs/hexo-deployer-git/issues/87">hexo-deployer-git_issues#87</a>。</p></blockquote><p>步骤和原理都很简单,在你的域名DNS解析中添加一条CNAME解析指向你的github.io地址,然后在github.io仓库中添加一个CNAME文件,里面内容即是你的域名,在上面的脚本中已经体现出来了。</p><img src="/2024/07/06/2024-7-6-%E4%BD%BF%E7%94%A8Github-Pages%E4%B8%8EActions%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BAHexo%E5%8D%9A%E5%AE%A2/6.png" class="" title="cloudfare"><p>同步一下仓库吧,不出意外的话Github action会自动执行,并且上传到github.io中。如遇到问题欢迎与我联系。</p>]]></content>
<categories>
<category>简单记录</category>