文章目录
前言
- 本人已通过25年中级软件设计师考试,以下内容为个人学习复习考点总结
- 考试形式:现在都是机考,选择题75分,简答题75分,总时长240分钟,选择题最长120分钟,考完提交立刻进行简答题
- 由于教材内容太多,耗时太长,对于上班族来说可能时间不够,建议还是抓大放小,对高频考点理解和记忆,毕竟有30分容错空间,不需要面面俱到,
- 零基础建议先补充java基础(或者C++这种面向对象的高级语言),这对重点内容如
数据结构、设计模式、面向对象等学习有极大帮助,并且简答题最后两题可选为c++和java就是送分的。
一、计算机组成原理
1、CPU
1.1 CPU的基本组件
| 分类 | 组件 | 作用 | 类比 |
|---|---|---|---|
| 运算器 | 算术逻辑单元(ALU) | 执行算术和逻辑运算 | 工厂核心加工机器 |
| 累加器(ACC) | 暂存运算结果 | 车间临时仓库 | |
| 数据缓冲寄存器(DR) | 暂存数据,协调与内存的数据传输 | 运输中转站 | |
| 状态条件寄存器(PSW) | 记录运算结果状态信息 | 质量检测员 | |
| 控制器 | 程序计数器(PC) | 存放下一条指令地址 | 任务清单 |
| 指令寄存器(IR) | 存放当前执行指令 | 任务详情单 | |
| 指令译码器(ID) | 译码指令 | 翻译官 | |
| 时序产生器 | 产生时序信号 | 车间时钟 | |
| 操作控制器 | 产生控制信号,协调各部件工作 | 团队指挥官 | |
| 高频考点 |
1.1.1 PC和IR
- 如搭配指令执行周期(取址-译码-执行)考察当前指令存在哪
指令执行实例:加法指令(ADD R1, R2, R3)
指令含义:将寄存器 R2 和 R3 的值相加,结果存入 R1。
- 取指:PC→MAR(cpu内部地址暂存寄存器),内存读指令→IR,PC+4(假设 32 位指令占 4 字节);
- 译码:控制单元解析操作码为 ADD,从寄存器堆读取 R2 和 R3 的值;
- 执行:R2+R3 送 ALU 计算,结果暂存;
- 访存:无(非访存指令);
- 写回:ALU 结果写入 R1。
1.1.2 操作数寻址
根据操作数位置
指令
- 立即寻址:操作数在指令中直接获取
寄存器 - 寄存器寻址:指令存在寄存器中直接获取
内存 - 直接寻址:获取指令时直接拿到内存地址
- 寄存器间接寻址:寄存器存储内存的地址
- 计算寻址(了解即可)
- 基址寻址:用一个 “固定基址” + 偏移量,定位数据(基址固定,偏移量可变)
- 变址寻址:用一个 “可变索引” + 固定基址,定位数据(索引可变,基址固定)(如数组遍历)
- 相对寻址:以 “当前指令地址” 为基准,加上偏移量,定位数据或跳转目标(相对当前位置寻址) 如分支跳转循环等
1.1.3 计算机体系结构(flynn分类)
S(single) I(instruction) M(multiple) D(data) 理解概念
- SISD(单指令流单数据流)
- SIMD(单指令流多数据流)
- MISD(多指令流单数据流,指令性能太低)
- MIMD(多指令流多数据流)
2、指令
2.1 RISC(简单指令集)和 CISC(复杂指令集)的特点
- RISC
- 大量通用寄存器【常考】
- 控制单元布线:硬布线控制(布线短、路径固定)【常考】
- 寻址方式简单(如直接寻址、寄存器寻址)
- 指令格式统一,天然支持深度流水线【常考】
- 译码简单,硬件设计难度低并且功耗低适合资源受限的场景
- 追求高性能、低功耗、需要编译器优化的场景(如移动设备、云计算)
- CISC
- 寄存器数量较少,依赖内存操作
- 控制单元布线:微程序控制 + 硬布线混合(布线长、分支多)【常考】
- 寻址方式复杂(如基址 + 变址 + 偏移量)
- 指令长度和复杂度不一,流水线效率受限
- 指令功能强大,方便与高级语言的复杂操作映射【常考】
- 码效率低,硬件设计难度高功耗大
- 追求兼容性、代码密度、依赖复杂指令简化编程的场景(如桌面电脑、传统服务器)
2.2 流水线周期的计算
- 流水线周期的概念及周期时间
- 一条指令执行过程(取指-译码-执行)并行进行
- 某个阶段最长执行时间即为周期时间
- 流水线指令执行时间计算公式
- 一条指令执行时间+(n-1)* 指令执行周期时间
3、存储
3.1 Cache
cache特点
- 高速缓存
- 连通CPU与内存,解决两者执行速度不匹配的问题
- 由硬件自动完成主存到cache的数据同步【常考】
cache与内存地址映射表
- 直接映像
- 内存地址 = [区号(Tag)] + [Cache块索引(Index)] + [块内偏移(Offset)]
- 内存地址与cache存储块取模决定存储位置
- 优:实现简单高效
- 缺:空间利用率低,冲突率高:不同内存块若模运算结果相同,会竞争同一 Cache 位置
- 全联映像
- 内存地址 = [完整Tag(块号)] + [块内偏移(Offset)]
- 内存块可映射到 Cache 的任意位置,无固定限制
- 优:提高了空间利用率
- 缺:每次命中比对需要全遍历,硬件复杂度高:需 CAM 实现并行查找
- 组相连映像
- 内存地址 = [Tag(区号)] + [组索引(Set Index)] + [块内偏移(Offset)]
- 将 Cache 分为若干组(Set),每组包含
N个块(称为N路组相联) - 内存块映射到固定组,可放入该组的任意块中。 公式:
组索引 = 内存块号 mod 组数 - 优:平衡性能与成本:比全相联更简单,比直接映射冲突率低
- 缺:硬件复杂度介于前两者之间,组内仍可能出现冲突(如组内所有块被占用时,新数据需替换旧块)
拓展:现代处理器中的应用
- 一级 Cache(L1):常采用 4 路或 8 路组相联,平衡速度与冲突率;
- 二级 / 三级 Cache(L2/L3):通常采用更高路数(如 16 路、32 路)或全相联,提升大容量 Cache 的利用率;
- 映射表优化:通过硬件预取、伪相联(结合直接映射与组相联)等技术减少冲突,例如:
- 伪相联 Cache:当直接映射查找失败时,尝试访问对应组的另一块,模拟二路组相联的效果。
3.2 内存
SRAM DRAM的概念和特点
| 特性 | SRAM(静态存储器) | DRAM(动态存储器) |
|---|---|---|
| 存储原理 | 触发器(晶体管电路) | 电容存储电荷 |
| 刷新需求 | 无需刷新 | 需要定期刷新(约 64ms) |
| 速度 | 快(纳秒级,1-10ns) | 较慢(几十到几百纳秒) |
| 容量 | 小(几 MB 到几十 MB) | 大(几 GB 到几十 GB) |
| 成本 | 高(晶体管数量多) | 低(1T1C 结构简单) |
| 功耗 | 持续功耗较高 | 非刷新时功耗低,刷新时功耗高 |
| 典型应用 | CPU 缓存(Cache)、高速缓冲 | 系统内存、显存 |
3.3 外存
磁盘的组成
- 盘片(表面涂覆磁性材料(如氧化铁),用于存储数据)
- 磁道
- 盘片表面划分为同心圆磁道
- 扇区
- 每个磁道再分为若干扇区(典型为 512 字节或 4KB),扇区是磁盘读写的最小单位
- 磁道
- 磁头
- 每个盘片的上下表面各有一个磁头,用于读取或写入磁信号
- 磁头臂
- 连接所有磁头的机械臂,通过移动磁头定位到目标磁道(寻道操作)
磁盘的存取时间
存取时间=寻道时间+旋转延迟+数据传输时间
- 寻道时间
- 磁头臂移动磁头从当前磁道到目标磁道的时间
- 旋转延迟
- 盘片旋转使目标扇区到达磁头下方的时间
- 数据传输时间
- 从磁盘读取或写入数据的时间,与数据量和传输速率相关
这里会涉及影响数据存取时间的因素考察、计算存储时间
拓展计算
涉及转速 如 转速 7200rpm rpm(转 / 分钟,revolutions per minute),即磁盘每分钟旋转 N 圈
例:硬盘平均寻道时间为 8ms,转速 7200rpm,数据传输速率为 200MB/s(200×10²⁴ KB/s),读取一个 4KB 的扇区。
计算:
- 寻道时间:8ms
- 旋转延迟: ( 30000 7200 ≈ 4.17 ) (\frac{30000}{7200} \approx 4.17) (720030000≈4.17) ms
- 传输时间: ( 4 200 × 1024 秒 = 4 × 1000 200 × 1024 ≈ 0.0195 ) (\frac{4}{200×1024} \, \text{秒} = \frac{4×1000}{200×1024} \approx 0.0195) (200×10244秒=200×10244×1000≈0.0195) ms
- 总存取时间: ( 8 + 4.17 + 0.0195 ≈ 12.19 ) (8 + 4.17 + 0.0195 \approx 12.19) (8+4.17+0.0195≈12.19) ms
FLASH与EEPROM区别
FLASH 存储器和 EEPROM(电可擦可编程只读存储器)均属于非易失性存储技术,断电后数据不丢失
EEPROM(Electrically Erasable Programmable Read-Only Memory)
ROM -> PROM -> EPROM -> EEPROM
- ROM/PROM 的淘汰:因无法更新或仅能一次编程,仅存于极少数低成本、固定功能的场景(如简单传感器的固件)。
- EEPROM 的主流场景:
- 需要频繁小数据修改的场景(如设备配置参数);
- 需高可靠性的场景(如医疗设备的校准数据,避免 Flash 块擦除导致的磨损)。
- Flash 的统治地位:现代计算机中,大容量非易失存储几乎全由 Flash 实现(如 SSD、U 盘),而 EEPROM 专注于小容量、高可靠性的字节级更新场景。
4、总线
计算机总线是计算机系统中传输数据、地址和控制信号的公共通道
4.1 总线的分类
按功能 / 传输信号类型分类
- 数据总线
- 传输数据信息,宽度决定一次能传输的数据位数(如 32 位、64 位)
- 地址总线
- 传输内存地址或外设地址,宽度决定系统可寻址的最大内存空间(如 32 位地址总线可寻址 4GB)
- 控制总线
- 传输控制信号(如读写命令、中断请求、时钟信号等),协调各部件操作
按层次结构 / 应用场景分类
- 片内总线
- 芯片内部各功能单元间的通信总线(如 CPU 内部寄存器与 ALU 之间的总线)
- 系统总线
- 计算机主板上连接 CPU、内存、外设接口的总线(如 ISA、PCI、PCI-E),是软考重点
- 外部总线
- 用于计算机与外部设备通信的总线(如 USB、IEEE 1394、RS-232),又称 “通信总线”
4.2 常见总线
常考PCI PCI-E
| 总线类型 | 特点 | 应用场景 |
|---|---|---|
| ISA(工业标准架构) | 早期并行总线,16 位 / 32 位,低速(最高 8MB/s),兼容性强但带宽低。 | 早期 PC(已淘汰,被 PCI 取代)。 |
| PCI(外设组件互连) | 并行总线,32 位 / 64 位,时钟频率 33MHz,带宽最高 133MB/s,支持即插即用。 | 声卡、网卡、旧显卡等。 |
| PCI-E(PCI Express) | 串行总线,采用差分信号,支持 x1/x4/x8/x16 通道(如 x16 通道带宽约 16GB/s),高速低功耗,取代 PCI。 | 现代显卡、NVMe 硬盘、高速接口卡。 |
| AGP(加速图形接口) | 专为显卡设计的并行总线,带宽最高 2.1GB/s,已被 PCI-E 取代。 | 旧代 PC 显卡(如 AGP 8X)。 |
| USB(通用串行总线) | 外部总线,支持热插拔,多版本迭代: USB 2.0(480Mbps)、USB 3.0(5Gbps)、USB 4(40Gbps)。 | 外设连接(鼠标、键盘、U 盘等)。 |
| IEEE 1394(火线) | 高速外部总线,支持实时数据传输(如 400Mbps/800Mbps),用于音视频设备。 | 摄像机、高端外设(被 USB 3.0 取代)。 |
4.3 串行总线和并行总线的特点
- 串行
- 按位传输每次传输一位,结构简单线路简单成本低,传输高速率,抗干扰能力强,适合远距离传输
- 应用场景:如USB外设连接
- 并行
- 并行线路传输可多位传输,结构复杂布线困难,相邻数据线会产生电磁干扰,因高频下的信号问题和复杂性
- 应用场景:仅存于极少数低频率短距离场景(如嵌入式系统),已被串形总线大规模取代
4.4 总线周期
- 时钟周期是 “心跳”,决定系统最小时序粒度。
- 总线周期是 “单次总线对话”,用于 CPU 与外部设备的交互。
- 指令周期是 “完整任务”,包含取指、译码、执行等阶段,可能涉及多次总线操作或纯内部操作。
4.5总线带宽的计算
总线带宽=总线宽度(bit) * 时钟频率(HZ) / 8(转换为Byte)
例:32 位总线,时钟频率 100MHz,则带宽为 ( 32 × 100 × 1 0 6 / 8 = 400 M B / s ) (32 \times 100 \times 10^6 / 8 = 400MB/s) (32×100×106/8=400MB/s)。
注意单位换算
- Hz(赫兹):表示每秒一次的周期性事件(如时钟脉冲、信号振荡)。 例如:1Hz = 1 次 / 秒。
- kHz(千赫兹):1kHz = ( 1 0 3 ) (10^3) (103) Hz = 1,000 Hz。
- MHz(兆赫兹):1MHz = ( 1 0 6 ) (10^6) (106) Hz = 1,000,000 Hz。
- GHz(吉赫兹):1GHz = ( 1 0 9 ) (10^9) (109) Hz = 1,000,000,000 Hz
4.6 总线仲裁特点
当多个设备同时请求使用总线时,需通过仲裁确定优先级。考点(链式查询、独立请求的优缺点,集中式与分布式的区别)
- 集中式仲裁:由中央仲裁器统一管理,常见方式:
- 链式查询(菊花链):仲裁信号按设备顺序传递,离仲裁器近的设备优先级高,硬件简单但可靠性低。
- 计数器定时查询:仲裁器通过计数器计数确定优先级,可动态调整优先级。
- 独立请求:每个设备独立向仲裁器发送请求,仲裁器按优先级响应,速度快但硬件复杂。
- 分布式仲裁:无中央仲裁器,设备自行协商优先级(如通过硬件逻辑竞争),常用于高端系统(如多处理器系统)。
5、IO
cpu与外部设备进行交互主要通过io接口如(USB 网卡等),主要解决两者在速度、数据格式、时序上的差异
5.1 CPU与外部设备交互方式
CPU 通过 IO 系统与外部设备交互的异步处理方式主要包括以下四种 DMA是常考点
- 中断方式
- 外设完成数据准备后,通过硬件中断信号通知 CPU,CPU 暂停当前任务,执行中断服务程序(ISR)处理数据
- 直接内存访问(DMA)
- DMA 控制器(硬件)接管总线控制权,直接在外设与内存间传输数据,无需 CPU 干预
- 通道方式(channel)与 io处理器(iop)
- channel
- 专用硬件通道控制器独立管理多个外设的复杂 I/O 操作,CPU 只需发送指令
- iop
- 独立于主 CPU 的专用处理器,完全接管 I/O 系统的控制与数据传输
- channel
现代计算机通过总线架构(如 PCIe)+ DMA + MMIO(内存io地址映射)的组合,实现了高效的外设与内存交互,CPU 仅需处理逻辑控制,大幅释放计算资源
5.2 异步处理 / CPU是否参与处理
| 方式 | CPU 参与程度 | 适用场景 | 典型设备 | 软考高频考点 |
|---|---|---|---|---|
| 中断方式 | 全程参与(ISR 执行) | 少量数据、实时响应 | 键盘、鼠标 | 中断优先级、上下文切换 |
| DMA 方式 | 仅初始化与收尾 | 大批量数据块传输 | 硬盘、显卡 | DMA 控制器结构、总线仲裁 |
| 通道方式 | 低参与(启动后托管) | 多外设并发复杂 I/O | 大型机存储系统 | 通道类型、通道程序设计 |
| IO 处理机方式 | 几乎不参与 | 高复杂度协议处理 | 智能网卡、RAID 控制器 | IOP 与主 CPU 的分工、IOP 指令集 |
6、计算机可靠性
6.1 串、并联可靠性计算
R为可靠度
- 串联部件的可靠度
- R1 * R2 * Rn
- 并联部件的可靠度
- (1- (1-R1) * (1-R2) * (1-Rn))
**6.2 软件 可靠性、可维护性、可用性 计算
相关概念
- MTTF(平均无故障时间)
- MTTR(平均修复时间)
- MTBF(平均故障间隔时间)
MTBF = MTTF + MTTR
- 可靠性
- MTTF 1 + MTTF \frac{\text{MTTF}}{1 + \text{MTTF}} 1+MTTFMTTF
- MTTF越大,可靠性越高,+1是防止溢出
- 可维护性
- 1 1 + MTTR \frac{1}{1 + \text{MTTR}} 1+MTTR1
- MTTR越小,则可维护性越高,+1是防止溢出
- 可用性
- M T B F M T B F + M T T R \frac{MTBF}{MTBF + MTTR} MTBF+MTTRMTBF
- 正常运行时间 / (正常运行时间+修复时间)
7、二进制数
7.1 原码、饭码、补码概念
CPU通过补码进行计算,补码计算不用考虑符号位,优化减法为加法便于硬件设计和性能优化
二进制码最高位为符号位(0-正/1-负),其余为数值位
正数的原、反、补码一致;负数的补码为反码+1,反码为原码取反。
十进制 -9
- 原码
- 1000 1001
- 反码
- 1111 0110
- 补码
- 1111 0111
7.2 二进制单位换算
1
GB
=
2
30
B
1 \, \text{GB} = 2^{30} \, \text{B}
1GB=230B
1
MB
=
2
20
B
1 \, \text{MB} = 2^{20} \, \text{B}
1MB=220B
1
KB
=
2
10
B
1 \, \text{KB} = 2^{10} \, \text{B}
1KB=210B
1
B
=
2
8
bit
1 \, \text{B} = 2^{8} \, \text{bit}
1B=28bit
7.3 进制数之间的转换
(2(B)、8(O)、10(D)、16(Ox / H)进制)
| 进制 | 基数 | 基本符号(示例) |
|---|---|---|
| 二进制 | 2 | 0, 1 |
| 八进制 | 8 | 0-7 |
| 十进制 | 10 | 0-9 |
| 十六进制 | 16 | 0-9, A(10), B(11), C(12), D(13), E(14), F(15) |
非十进制数转十进制数(按权展开法)
每一位数字乘以基数的幂次,再求和
例: ( 1011.01 ) 2 (1011.01)_2 (1011.01)2
KaTeX parse error: {align*} can be used only in display mode.
KaTeX parse error: {align*} can be used only in display mode.
KaTeX parse error: {align*} can be used only in display mode.
十进制数转非十进制数(除基取余法 / 乘基取整法)
10 -> 2
( 25.625 ) 10 (25.625)_{10} (25.625)10
整数部分 25
25
÷
2
25÷2
25÷2 12 余 1
12
÷
2
12÷2
12÷2 6 余 0
6
÷
2
6÷2
6÷2 3 余 0
3
÷
2
3÷2
3÷2 1 余 1
1
÷
2
1÷2
1÷2 0 余 1
逆序余数得:
(
11001
)
2
(11001)_2
(11001)2
小数部分 0.625
0.625
×
2
0.625×2
0.625×2 1.25 取整 1
0.25
×
2
0.25×2
0.25×2 0.5 取整 0
0.5
×
2
0.5×2
0.5×2 1.0 取整 1
顺序整数得
(
0.101
)
2
(0.101)_2
(0.101)2
结果 ( ( 25.625 ) 10 = ( 11001.101 ) 2 ) ((25.625)_{10} = (11001.101)_2) ((25.625)10=(11001.101)2)
二进制与八进制 / 十六进制的快速转换(分组法)
二进制与八进制互转(3 位二进制 = 1 位八进制)
例: ( ( 10110.01 ) 2 ) ((10110.01)_2) ((10110.01)2)
- 分组(整数从右往左,小数从左往右,不足补 0): ( 010 110 . 010 ( 补零后 ) ) (010 \, 110 \, . \, 010 \quad (\text{补零后})) (010110.010(补零后))
- 每组转八进制: ( 01 0 2 = 2 , 11 0 2 = 6 , 01 0 2 = 2 ⇒ ( 26.2 ) 8 ) (010_2=2, \, 110_2=6, \, 010_2=2 \quad \Rightarrow \quad (26.2)_8) (0102=2,1102=6,0102=2⇒(26.2)8)
例: ( ( 73.5 ) 8 ) ((73.5)_8) ((73.5)8)
- 每位转 3 位二进制: ( 7 8 = 111 , 3 8 = 011 , 5 8 = 101 ⇒ ( 111011.101 ) 2 ) (7_8=111, \, 3_8=011, \, 5_8=101 \quad \Rightarrow \quad (111011.101)_2) (78=111,38=011,58=101⇒(111011.101)2)
二进制与十六进制互转(4 位二进制 = 1 位十六进制)
例: ( ( 1101101.101 ) 2 ) ((1101101.101)_2) ((1101101.101)2)
- 分组: ( 0110 1101 . 1010 ( 补零后 ) ) (0110 \, 1101 \, . \, 1010 \quad (\text{补零后})) (01101101.1010(补零后))
- ( 011 0 2 = 6 , 110 1 2 = D , 101 0 2 = A ⇒ ( 6 D . A ) 16 ) (0110_2=6, \, 1101_2=D, \, 1010_2=A \quad \Rightarrow \quad (6D.A)_{16}) (01102=6,11012=D,10102=A⇒(6D.A)16)
例: ( ( A 2 F . 4 ) 16 ) ((A2F.4)_{16}) ((A2F.4)16)
- 每位转 4 位二进制:A=1010,2=0010,F=1111,4=0100⇒(101000101111.01)2
8、浮点数
浮点数有点复杂分值也就一两分,过度深入容易影响心态,主记规范化、对阶这两个高频考点
8.1 基本概念
浮点数的二进制值可表示为: ( Value = ( − 1 ) S × ( 1 + M ) × 2 E − 偏移量 (\text{Value} = (-1)^S \times (1 + M) \times 2^{E - \text{偏移量}} (Value=(−1)S×(1+M)×2E−偏移量)
- 符号位(S):0 表示正数,1 表示负数。
- 阶码(E):存储时加上偏移量(如单精度 + 127),用于表示指数部分,决定数值的大小范围。
- 尾数(M):规格化后隐含整数部分 “1”(如二进制数 (1.xxxx_2)),因此 M 实际表示小数部分,决定数值的精度。
8.2 浮点数的规范化和非规范化表示
类似与科学计数法的表示
- 左规格化(尾数≥2):尾数左移,指数减 1(如尾数为 10.01,则左移 1 位变为 1.001,指数 + 1);
- 右规格化(尾数 < 1):尾数右移,指数加 1(极少出现,对阶已处理)。
- 例中结果: ( 1.001 × 2 3 ) (1.001 \times 2^3) (1.001×23) 已规格化(最高位为 1)。
8.3 浮点数对阶
原则:小指数向大指数对齐,尾数右移(右移导致低位丢失,可能引入误差)
- 例:计算 10.0_2 + 1.0_2(即 10.0 + 2.0 = 12.0)
- 两数二进制浮点数表示:
- ( 10. 0 2 = 1.0 × 2 3 ) (10.0_2 = 1.0 \times 2^3) (10.02=1.0×23),存储为:S=0, E=3+127=130=10000010, M=000…0;
- ( 1. 0 2 = 1.0 × 2 0 ) (1.0_2 = 1.0 \times 2^0) (1.02=1.0×20),存储为:S=0, E=0+127=127=01111111, M=000…0;
- 对阶:小指数 0 向大指数 3 对齐,后者尾数右移 3 位:
- ( 1.0 × 2 0 → 0.001 × 2 3 ) (1.0 \times 2^0 \to 0.001 \times 2^3) (1.0×20→0.001×23),尾数变为 001000…0(原 M=000…0 右移 3 位补 0)。
- 两数二进制浮点数表示:
8.4 浮点数加法步骤
浮点数加法需遵循 对阶→尾数相加→规格化→舍入→溢出判断 五步,以单精度为例
例:计算 0.5_10 + 0.25_10 的单精度浮点数加法
- 转换为二进制浮点数
- 0. 5 10 = 0. 1 2 = 1.0 × 2 − 1 0.5_{10} = 0.1_2 = 1.0 \times 2^{-1} 0.510=0.12=1.0×2−1
- 0.2 5 10 = 0.0 1 2 = 1.0 × 2 − 2 0.25_{10} = 0.01_2 = 1.0 \times 2^{-2} 0.2510=0.012=1.0×2−2
- 按 IEEE 754 存储
- ( 0.5 ) (0.5) (0.5):S=0, E=-1+127=126=01111110, M=000…0;
- ( 0.25 ) (0.25) (0.25):S=0, E=-2+127=125=01111101, M=000…0;
- 对阶
- 小指数 - 2 向大指数 - 1 对齐, ( 0.25 ) (0.25) (0.25)的尾数右移 1 位: ( 1.0 × 2 − 2 → 0.1 × 2 − 1 (1.0 \times 2^{-2} \to 0.1 \times 2^{-1} (1.0×2−2→0.1×2−1,尾数变为 100…0(原 M=000…0 右移 1 位补 0)。
- 尾数相加
- 1.000…0 ( 0.5 0.5 0.5的尾数)+0.100…0 ( 0.25 0.25 0.25的尾数) = 1.100…0
- 规格化
- 结果为(1.1 \times 2^{-1}),已规格化。
- 舍入(无超出)
- 尾数为 1.100…0,长度足够,无需舍入
- 最终结果
- 指数 E=-1+127=126=01111110,尾数 M=100…0,符号位 0;
- 二进制存储:
0 01111110 1000000000000000000000000,对应十进制为 0.75,正
9、海明码
9.1 校验码的分类
- 奇偶校验码
- 在原始数据位后面添加一位奇偶校验位,实现简单但检测准确度不高
- 循环冗余校验码
- 预先约定的生成多项式,计算出一个校验码。实现复杂,有很强的纠错能力,也是在数据位后添加校验位
- 海明码(汉明码)
- 在数据位之间插入校验位,不仅可以检测还可以纠错。校验位与数据位之间需要满足一定关系
9.2 海明码校验位的计算
重点公式: ( 2 k ≥ n + k + 1 ) (2^k \geq n+k+1) (2k≥n+k+1)
- k是校验位
- n是数据位
二、数据结构和算法
1、栈
特点先进先出
结合后缀表达式(逆波兰式)考察
主要考查表达式转换、计算过程及栈的操作逻辑
1.1 后缀表达式的定义与优势
- 形式:运算符位于操作数之后,如中缀表达式
3+4*2的后缀表达式为3 4 2 * +。 - 优势:无需考虑运算符优先级和括号,仅通过栈即可完成计算,适合计算机高效处理。
1.2 栈的作用
- 转换阶段:存储运算符,根据优先级决定弹出时机(如 Shunting Yard 算法)。
- 操作数直接加入表达式
- 运算符与栈顶运算符相比较,优先级高则压栈,优先级低则弹出栈顶符号再入栈
- 若为左括号,直接压栈;若为右括号,则弹出栈中运算符直至遇到左括号(左括号出栈但不加入表达式)
- 计算阶段:存储操作数,遇到运算符时弹出操作数计算,结果压栈
- 操作数直接入栈
- 遇到操作符,直接弹出栈内两个元素进行运算,将结果压入栈中
- 所有操作数弹出,运算结果为栈顶的值
1.3 后缀表达式的计算
给出后缀表达式,计算其值,或分析计算过程中栈的状态(如某一步骤后栈内元素)
示例:后缀表达式 3 4 2 * + 的计算过程:
- 扫描
3→ 压栈 → 栈:[3] - 扫描
4→ 压栈 → 栈:[3, 4] - 扫描
2→ 压栈 → 栈:[3, 4, 2] - 扫描
*→ 弹出2和4,计算4×2=8,压栈 → 栈:[3, 8] - 扫描
+→ 弹出8和3,计算3+8=11,压栈 → 栈:[11] - 结果为
11。
中缀表达式 a*(b+c)-d 的后缀表达式是
a
b
c
+
∗
d
−
abc+*d-
abc+∗d−
- 转换步骤:
a→ 加入后缀表达式 →a*→ 压栈(→ 压栈b→ 加入 →a b+→ 栈顶为(,压栈c→ 加入 →a b c)→ 弹出+加入 →a b c +,弹出((不加入)*→ 弹出栈顶*加入 →a b c + *-→ 压栈d→ 加入 →a b c + * d- 扫描结束,弹出
-加入 →a b c + * d -
2、队列
2.1 字符串进出双端队列
队列双端都可以进入,但只有一端可以出,根据给出的选项进行模拟测试即可
循环队列的考察
- 掌握核心公式:循环队列的队满 / 队空条件、队列长度计算。
- 理解双端队列操作逻辑:区分两端插入 / 删除的指针变化,熟记单调队列优化滑动窗口的步骤。
- 练习真题:重点关注队列操作序列合法性判断、算法应用题(如滑动窗口最大值)。
- 对比数据结构:明确循环队列与双端队列的区别,在不同场景下选择最优结构(如缓冲区用循环队列,窗口问题用双端队列)。
2.2 循环队列
是一种用数组实现的队列,通过头尾指针的循环移动(取模运算)存储和删除元素;重点掌握在入队和 出队时的指针运动
特点
- 单端循环队列
- 队头出,队尾入 ,严格遵循FIFO(先进先出)
- 双端循环队列
- 队头队尾都可以入队,出队
- 出队在只是逻辑层级上的删除,而在物理存储上并未删除,当下一次入队元素占据该索引位置时原值被覆盖。
指针定义
指针位置的计算取模操作是实现循环队列的关键以及防止索引溢出
单端循环队列
front:指向队头元素的当前位置。rear:指向下一个入队元素的位置(即队尾元素的下一个位置)
双端循环队列front指向队头元素rear指向队尾元素
2.2.1 核心公式
单端/双端通用
- 队空
front == rear(头尾指针重合)
- 队满
(rear + 1) % capacity == front- 牺牲一个单元法(因为front == rear可为队空或队满,故将rear的循环下一个移动地址 = front为队满)
- 计数器法
- 每入队一个单元计算器++,每出队一个单元计数器–,无需依赖指针移动
- 队列长度
(rear - front + capacity) % capacity
公式记忆技巧
- 单端队列:入队出队都朝一个方向(
rear和front后移),类似 “传送带”。 - 双端队列:
- 入队:队头 “左移”(
front-1),队尾 “右移”(rear+1); - 出队:队头 “右移”(
front+1),队尾 “左移”(rear-1),类似 “双向门”。
- 入队:队头 “左移”(
2.2.2 队列指针的操作
需掌握循环队列的出入队操作时的指针运动(左移右移),队列中的元素顺序始终是从对头指向队尾(front -> rear)即逻辑顺序(顺时针)
2.2.2.1 单端循环队列(容量 5,数组索引 0-4)
初始状态:front = 0, rear = 0,队空。
队尾入队与队头出队操作
| 操作步骤 | 操作描述 | front 值 | rear 值 | 队列元素(方括号表示数组,箭头为指针) |
|---|---|---|---|---|
| 初始状态 | 队空 | 0 | 0 | [ ][ ][ ][ ][ ] → front/rear |
| 入队元素 1 | rear = (0+1)%5=1 | 0 | 1 | [1][ ][ ][ ][ ] → rear |
| 入队元素 2 | rear=(1+1)%5=2 | 0 | 2 | [1][2][ ][ ][ ] → rear |
| 入队元素 3 | rear=(2+1)%5=3 | 0 | 3 | [1][2][3][ ][ ] → rear |
| 队头出队(1) | front=(0+1)%5=1 | 1 | 3 | [ ][2][3][ ][ ] → front |
| 入队元素 4 | rear=(3+1)%5=4 | 1 | 4 | [ ][2][3][4][ ] → rear |
| 队头出队(2) | front=(1+1)%5=2 | 2 | 4 | [ ][ ][3][4][ ] → front |
| 入队元素 5 | rear=(4+1)%5=0(循环) | 2 | 0 | [ ][ ][3][4][5] → rear(此时队满?) |
队满判断
- 此时
(rear+1)%5=(0+1)%5=1 == front=2? 否,未队满(实际有 3 个元素:3,4,5)。 - 若继续入队元素 6:
rear=(0+1)%5=1,此时(1+1)%5=2 == front=2,队满。
2.2.2.2 双端循环队列(容量 5,数组索引 0-4)
初始状态:front = -1, rear = 1,队空。
队头入队、队尾入队、队头出队、队尾出队操作
| 操作步骤 | 操作描述 | front 值 | rear 值 | 队列元素(逻辑顺序:队头→队尾) |
|---|---|---|---|---|
| 初始状态 | 队空 | -1 | -1 | [ ][ ][ ][ ][ ] |
| 队尾入队 A | rear=(-1+1)%5=0 | 0 | 0 | [A][ ][ ][ ][ ](队尾 A) |
| 队头入队 B | front=(0-1+5)%5=4(左移取模) | 4 | 0 | [A][ ][ ][ ][B](队头 B->队尾 A) |
| 队尾入队 C | rear=(0+1)%5=1 | 4 | 1 | [A][C][][ ][B](B-A-C) |
| 队尾出队(C) | rear=(1-1+5)%5=0(左移取模) | 4 | 0 | [A][C][ ][ ][B](逻辑上B-A) |
| 队头出队(B) | front=(4+1)%5=0(右移取模) | 0 | 0 | [A][C][ ][ ][B](逻辑上A) |
| 队头入队 D | front=(0-1+5)%5=4 | 4 | 0 | [A][C][ ][ ][D](逻辑上D-A ) |
双向操作的指针变化核心
- 队头入队:
front = (front - 1 + capacity) % capacity(指针左移,新元素存于 front 位置)。 - 队尾出队:
rear = (rear - 1 + capacity) % capacity(指针左移,指向队尾前一个元素)。
关键指针运算总结
- 右移(队尾操作):
pos = (pos + 1) % capacity(入队 / 出队均可能使用)。 - 左移(队头操作):
pos = (pos - 1 + capacity) % capacity(仅双端队列队头入队 / 队尾出队使用)。 - 循环本质:通过取模运算实现指针 “绕圈”,避免数组越界,如
rear=4时 + 1 变为 0。
2.2.3 队列操作的时间复杂度
| 操作类型 | 时间复杂度 | 说明 |
|---|---|---|
| 插入(入队) | O(1) | 修改front 活 rear 指针(移动)并存储元素,仅涉及指针算术运算和取模操作。 |
| 删除(出队) | O(1) | 修改front 或 rear 指针(移动),无需数据移动。 |
| 查询队头元素 | O(1) | 直接通过front指针访问,无需遍历。 |
| 查询队尾元素 | O(1) | 直接通过rear指针(或计算)访问,无需遍历。 |
| 查询任意位置元素 | O(n) | 需从front或rear开始遍历,最坏情况下遍历整个队列。 |
2.2.4 应用场景
了解拓展
- 单端循环队列
- I/O 缓冲区管理
- 磁盘读写、串口通信等 I/O 操作中,缓冲区暂存数据
- 循环队列可实现 “生产者 - 消费者” 模型,生产者(如读取数据)从队尾入队,消费者(如处理数据)从队头出队,避免数据覆盖
- 空间利用率高,无需频繁申请 / 释放内存
- I/O 缓冲区管理
- 双端循环队列
- 滑动窗口
- 如 “求数组中每个滑动窗口的最大值”,双端队列可优化为双端循环队列(减少空间开销)
- 队头删除过期元素,队尾添加新元素,同时维护窗口内元素的有序性
- 循环结构避免窗口滑动时数组的整体移动,提升效率
- 任务调度中的优先级动态调整
- 系统需处理不同优先级的任务,高优先级任务可插队,普通任务按顺序入队
- 队头入队支持高优先级任务插队(直接插入队首)
- 队尾入队处理普通任务,队头 / 队尾均可出队(根据优先级选择处理顺序)
- 滑动窗口
3、二叉树
其每个节点最多有两个子节点,分别称为左子节点和右子节点
相关概念
- 根节点:树的顶层节点,没有父节点。
- 叶子节点:没有子节点的节点。
- 节点的度:节点拥有的子节点数量,树的度为其节点的最大度。
- 树的高度:从根节点到最远叶子节点的最长路径上的节点数。
3.1 二叉树的分类
二叉排序树
每个节点满足 左子树所有节点值 < 根节点值 < 右子树所有节点值
plaintext
5(根)
/ \
3 7
/ \ / \
2 4 6 8
平衡二叉树
任意节点的左右子树高度差不超过 1,通过旋转操作(左旋、右旋)维持平衡
plaintext
4(根)
/ \
2 6
/ \ / \
1 3 5 7
完全二叉树
除最后一层外,其他层节点数全满;最后一层节点从左到右连续排列,不允许有空缺。
plaintext
A(根)
/ \
B C
/ \ /
D E F
满二叉树
所有非叶子节点都有两个子节点,且所有叶子节点在同一层
plaintext
A(根)
/ \
B C
/ \ / \
D E F G
哈夫曼树
带权路径长度(WPL)最短的二叉树,常用于构建数据压缩的霍夫曼编码
plaintext
10(根,1+2+3+4)
/ \
4 6(2+4)
/ \ / \
1 3 2 4
3.2 树转换成二叉树
转换规则(左孩子右兄弟法[兄弟节点变为右孩子节点])
- 左子节点:原树中节点的第一个孩子变为二叉树的左子节点。
- 右子节点:原树中节点的下一个兄弟(右侧相邻兄弟)变为二叉树的右子节点。
- 递归处理所有子树
普通树结构
plaintext
A(根)
/ | \
B C D
/ \ /
E F G
旋转后形成的二叉树
plaintext
A
/ \
B C
/ \ \
E F D
\ /
G
题型
森林转换成二叉树的约定
- 森林中所有树各自转换成二叉树,第一棵树为合成二叉树的根和左子节点,后面的树都在二叉树的右子节点
3.3 构建哈夫曼树
哈夫曼树(最优二叉树)是带权路径长度(WPL)最短的二叉树(各节点的权重 * 树的高度之和),核心思想是通过贪心算法,每次选择权值最小的两个节点合并,直到形成一棵树
构建步骤
- 按权值排序给出的节点
- 自底向上构建,每次选取权值最小的节点构建父节点,将父节点的值放入队列中排序
- 重复步骤 选取两个最小权值点继续构建
示例:构建权值为 [5, 9, 12, 13, 16, 45] 的哈夫曼树
最终哈夫曼树的字符图
plaintext
100
/ \
45 55
/ \
25 30
/ \ / \
12 13 14 16
/ \
5 9
带权路径长度(WPL)计算
| 叶子节点 | 路径长度(边数) | 权值 × 路径长度 |
|---|---|---|
| 5 | 4(100→55→30→14→5) | 5×4 = 20 |
| 9 | 4(100→55→30→14→9) | 9×4 = 36 |
| 12 | 3(100→55→25→12) | 12×3 = 36 |
| 13 | 3(100→55→25→13) | 13×3 = 39 |
| 16 | 3(100→55→30→16) | 16×3 = 48 |
| 45 | 1(100→45) | 45×1 = 45 |
WPL 总和:20 + 36 + 36 + 39 + 48 + 45 = 224
构建哈夫曼树生成哈夫曼编码
哈夫曼编码特点
- 前缀编码:任一编码不是其他编码的前缀(如
000不是001的前缀)。 - 频率与编码长度关系:频率越高的字符(如 e, c, d)编码越短,符合哈夫曼编码的最优性。
例: 给出一组字符 及 字符使用频率 来构建哈夫曼树 生成哈夫曼编码
如 a(5), b(9), c(12), d(13), e(16)
构建步骤
1. 排序
1. 将字符跟据使用频率排序 正序(因为最终的哈夫曼编码越短说明使用频率越高,起到一个数字压缩的作用)
2. 合并
1. 弹出数组中前两个元素生成父节点,将父节点加入数组
3. 递归
1. 重复进行排序、弹出、加入,直到所有节点构建完成
4. 编码
1. 自顶向下,左0右1,写出各节点的编码即为哈夫曼编码
哈夫曼树结构
plaintext
55(Root)
/ \
25 30
/ \ / \
12(c) 13(d)14 16(e)
/ \
5(a) 9(b)
plaintext
55(Root)
/ \
0/ \1
25 30
/ \ / \
0/ \1 0/ \1
12(c) 13(d)14 16(e)
/ \
0/ \1
5(a) 9(b)
各字符的编码路径详解
- Root → 30 → 14 → a = 100
- Root → 30 → 14 → b = 101
- Root → 25 → c = 00
- Root → 25 → d = 01
- Root → 30 → e = 11
3.4 二叉树的遍历
前中后序遍历,想象成三角形来记忆遍历的顺序
- 前序遍历:根左右
- 中序遍历:左根右
- 后序遍历:左右根
自顶向下,每次将树看成根-左-右三个节点,在递归根据规则来遍历。
plaintext
1(根)
/ \
2 3
/ \
4 5
- 前序:1 → 2 → 4 → 5 → 3
- 中序:4 → 2 → 5 → 1 → 3
- 后序:4 → 5 → 2 → 3 → 1
3.5 平衡二叉树的旋转原理
平衡二叉树首先是排序树,满足中缀表达式,在新增or删除节点影响平衡时,通过左旋右旋节点使之达到左右子树差的绝对值不超过1的平衡点
**旋转的触发条件:AVL 树的平衡因子BF **
BF = 左子树高度 - 右子树高度 要求左右子树差的绝对值不超过1
失衡类型
- LL 型失衡:左子树 高于 右子树,其左孩子的左子树高于该孩子右子树(平衡因子为 (2, 1))
- 失衡节点右旋保持平衡
- RR 型失衡:左子树 低于 右子树,其右孩子的左子树 低于 该孩子右子树(平衡因子为 (-2, -1))
- 失衡节点左旋转保持平衡
- LR 型失衡:左子树 高于 右子树,其左孩子的左子树 低于 该孩子右子树(平衡因子为 (2, -1))
- 先左孩子节点 左旋转
- 节点右旋转
- 旋转过程中冲突的节点拆开拼接到子节点
- RL 型失衡:左子树 低于 右子树,其右孩子的左子树 高于 该孩子右子树(平衡因子为 (-2, 1))
- 先右孩子节点右旋转
- 节点左旋转
- 旋转过程中冲突的节点拆开拼接到子节点
特殊:当树中节点及其子节点同时失衡即(2, 2),只需调整子节点旋转使其平衡即可
构建平衡二叉树时也是,按照中缀表达式 左根右构建,当失衡时旋转节点,继续构建平衡。
删除节点时,若发生失衡状态,在旋转达到平衡时需检查其他节点是否失衡。
4、图
4.1图的基本概念
定义
图是由顶点集合(Vertex)和边集合(Edge)组成的数据结构,记为
G=(V, E)。其中:
- 顶点(V):表示数据元素,如节点、对象等。
- 边(E):表示顶点之间的关系,边可以带权值(如距离、成本等)
- 顶点度数
- 无向图中顶点的度数为其连接的边数
- 有向图中分为入度(指向该顶点的边数)和出度(该顶点发出的边数)
- 路径与环
- 顶点序列构成的通路,若起点和终点相同且路径长度≥1,则为环
- 连通性
- 无向图中顶点间存在路径则连通(连起来)
- 有向图中若任意两顶点互相可达则为强连通(连起来且看方向是否互相可达)
- 连通分量
- 在无向图中,连通分量是指图的一个极大(无法再拓展)连通子图
- 子图内的任意两个节点之间都有路径相连;
- 强连通分量
- 强连通分量是有向图中 “极大(无法再拓展)的双向可达子图”
- 若图本身是强连通的(如单环),则其强连通分量只有一个;否则划分为多个分量
plaintext
(A)——(B)
| |
| |
(D)——(C)
4.2 图的分类
无向图有向图都可以成环(A-B-C-D-A)或不成环(A-B-C-D)
| 图类型 | 边方向 | 边数特点 | 连通性特点 | 示例节点数 |
|---|---|---|---|---|
| 无向图 | 无 | 任意边无箭头 | 可能不连通 | 4 |
| 有向图 | 有 | 边带箭头 | 可能单向可达 | 3 |
| 强连通图 | 有 | 必须存在双向路径 | 任意两顶点互相可达 | 3 |
| 无向完全图 | 无 | 边数 = n (n-1)/2(n 为顶点数) | 一定连通 | 4 |
| 有向完全图 | 有 | 边数 = n (n-1) | 若 n≥2 则为强连通 | 3 |
无向图
A-B-C-D
无环无向图,节点连通为树,不连通则为森林(多棵树)
有向图
A->B->C->D
完全图
- 无向完全图:每个顶点都有一条边相连
- 有向完全图:每个顶点之间都有两条有向边互连
- 边数的计算(常考)
无向完全图
(A)
/ | \
(B)—(C)
\ | /
(D)
有向完全图
A
<|> # <|> 表示A与B和A与C之间的双向边(A<->B 和 A<->C)
B<->C # B<->C 表示B与C之间的双向边
连通图
- 强连通图:每个顶点可达 字符图(A→B→C→A环)
- 弱连通图:无向图
4.3 图的邻接表和邻接矩阵
4.3.1 邻接矩阵
定义:用二维数组 matrix[n][n] 表示图,其中 n 为顶点数,matrix[i][j] 表示顶点 i 到 j 的连接关系(1表示连通,0表示未连通)。
图结构:
(A)—(B)
| /
(C)
邻接矩阵表示:
A B C
A [0, 1, 1]
B [1, 0, 1]
C [1, 1, 0]
- 无向图:矩阵对称,
matrix[i][j] = matrix[j][i]。 - 带权图:非 0 值表示权值,如
matrix[i][j] = 5表示边权为 5,无穷大表示不连通。
核心特点
- 空间复杂度:O (n²),无论边数多少,均需 n×n 的存储空间,适合稠密图(边数接近 n²)。
- 时间复杂度:
- 查找边:O (1)(直接访问 matrix [i][j])。
- 遍历顶点 i 的所有邻接顶点:O (n)(扫描第 i 行)。
- 优缺点:
- 优点:实现简单,适合矩阵运算(如 Floyd 算法),判断两顶点是否相连高效。
- 缺点:稀疏图中浪费大量空间(如 n=1000,边数 = 1000 时,空间利用率仅 0.1%)。
4.3.2 邻接表
定义:为每个顶点维护一个链表,链表中存储其邻接顶点及边权,由数组 + 链表构成。
图结构:
(A)—(B)
| /
(C)
邻接表表示:
A: -> B -> C
B: -> A -> C
C: -> A -> B
- 链表节点结构:
[邻接顶点, 权值],无向图中每条边在两个顶点的链表中各出现一次。
核心特点
- 空间复杂度:O (n+m),n 为顶点数,m 为边数,适合稀疏图(m << n²)。
- 时间复杂度:
- 查找边:O (deg (i)),deg (i) 为顶点 i 的度数,最坏 O (n)。
- 遍历顶点 i 的所有邻接顶点:O (deg (i)),平均 O (m/n)。
- 优缺点:
- 优点:节省空间,适合边数少的图(如社交网络、互联网拓扑)。
- 缺点:判断两顶点是否相连需遍历链表,效率低;实现稍复杂(需处理指针或链表)。
对比表
O (deg (i))
deg(i)是 顶点 i 的度数(Degree)
| 特性 | 邻接矩阵 | 邻接表 |
|---|---|---|
| 存储结构 | 二维数组 | 数组 + 链表 |
| 空间复杂度 | O (n²)(稠密图友好) | O (n+m)(稀疏图友好) |
| 边存在性查询 | O (1)(直接访问) | O (deg (i))(遍历链表) |
| 遍历所有邻接顶点 | O (n)(扫描整行) | O (deg (i))(遍历链表) |
| 适合场景 | 稠密图(如完全图、网格图) | 稀疏图(如社交网络、树) |
| 典型算法 | Floyd(多源最短路径) | Dijkstra(邻接表优化版)、Kruskal |
4.4 图的算法
理解算法的思想,解题时画图+观察+枚举路径即可
算法应用
- 看到 “最短路径” 想 Dijkstra/Floyd,“最小成本连通” 想 Prim/Kruskal,“任务顺序” 想拓扑排序,“项目工期” 想关键路径
4.4.1 图的遍历
从起点 A 出发遍历图:
A -- B -- C
| |
D -- E
- BFS(广度遍历)
- A → B → D → C → E
- 按层次遍历,从起点出发逐层访问邻接节点
- 参考树层级遍历 从上到下 从左到右
- 应用:找单源最短路径(无权图)、层序遍历、判断二分图
- DFS(深度遍历)
- A → B → C → E → D
- 递归或栈实现,沿一条路径走到底再回溯
- 参考树的深度遍历 从根到叶子再回溯
- 应用:拓扑排序、生成树
两者的时间复杂度一致
- 邻接表:O (V+E)(V 为顶点数,E 为边数)
- 邻接矩阵:O (V²)
4.4.2 最短路径算法
自顶点开始到其他顶点的最短距离
Dijkstra 算法(单源最短路径,无负权边)
- 适用条件:图中所有边权非负。
- 核心思想:贪心策略,每次选择当前距离起点最近的顶点,更新其邻居的最短距离。
解题步骤示例(以图 1 为例):
图1:顶点A到其他顶点的边权如下
A→B(2), A→C(5)
B→D(3), B→E(4)
C→D(1), C→E(6)
D→E(2)
-
初始化:
- 距离数组
dist = [∞, ∞, ∞, ∞, ∞],起点 A 的距离为 0。 - 访问标记数组
visited = [False, False, False, False, False]。
- 距离数组
-
迭代过程:
- 第 1 轮:选择 A(未访问),更新 B(2)、C(5)。
- 第 2 轮:选择 B(距离 2),更新 D(2+3=5)、E(2+4=6)。
- 第 3 轮:选择 C(距离 5),更新 D(5+1=6)、E(5+6=11)。
- 第 4 轮:选择 D(距离 5),更新 E(5+2=7)。
- 第 5 轮:选择 E(距离 7),无更新。
-
结果:
- A 到 B=2,A 到 C=5,A 到 D=5,A 到 E=7。
Floyd-Warshall 算法(多源最短路径,允许负权边,无负权环)
推导 Floyd-Warshall 算法的核心是逐次枚举中间节点,拆解路径 i→k→j 并比较长度,无需矩阵即可直观理解最短路径的优化过程
- 适用条件:图中允许存在负权边,但不能有负权环。
- 核心思想:动态规划,通过中间顶点逐步优化路径。
解题步骤示例(以图 2 为例):
图2:邻接矩阵(初始值为直接边权,无穷大表示无直接边)
A B C D
A 0 2 5 ∞
B ∞ 0 ∞ 3
C ∞ ∞ 0 1
D ∞ ∞ ∞ 0
核心思想
- 若 i→k→j 的距离 < i→j 的当前距离,则更新 i→j 的最短距离
- 每次选取单个节点作为中间节点
- 比对所有矩阵中的节点是否需要优化
- 实际解答选择题时直接枚举比较即可
真题实战示例
题目:某有向图邻接矩阵如下,求 B 到 C 的最短路径:
A B C D
A 0 1 3 ∞
B 2 0 ∞ 2
C ∞ 4 0 1
D ∞ ∞ 5 0
快速解:
- 直接边:B→C=∞(无效)。
- 中间节点 A:B→A→C=2+3=5。
- 中间节点 D:B→D→C=2+5=7。
- 中间节点 C:B→C→C=∞+0=∞(无效)。
- 最短路径为 5。
通过这种 “目标导向” 的枚举法,软考中 90% 的最短路径题可在 1 分钟内解决,无需完整展开 Floyd 的三重循环。关键是抓住 “路径枚举 + 中间节点分层” 的核心逻辑,避免无效计算
SSTF(磁盘磁头-最短寻道时间优先)
贪心算法策略,每次选取离磁头最近位置的请求,减少磁头移动距离
题目:磁盘当前磁头位于 20 号柱面,请求序列为 {2,6,10,20,22,38},使用最短寻道时间优先(SSTF)算法,求访问顺序
解析:
- SSTF 算法逻辑:每次选择距离当前磁头最近的柱面。
- 步骤:
- 当前 20 → 最近 22(距离 2)→ 38(距离 16)→ 10(距离 28)→ 6(距离 4)→ 2(距离 4)。
- 答案:20 → 22 → 38 → 10 → 6 → 2。
4.4.3 最小生成树算法
不管是prim算法还是kruskal算法最终结果都是一致的可以彼此校验
Prim 算法
每次选取最小边权的顶点加入集合,连通所有顶点但无环
- 特点:
从任意顶点开始,每次选当前树外连接树的最小权边,扩展树直到包含所有顶点(按点扩展)。 - 时间复杂度:
- 邻接矩阵:O (n²)
- 优先队列优化:O (m log n)
- 适用场景:
边稠密图(邻接矩阵更优),如局域网布线最小成本。 - 解题技巧:
- 根据题意画出图并标出权重值,任选一顶点,选取权值最小的顶点并加入该树,继续循环寻找下一个顶点,直到连通所有顶点,注意不要生成环。
- 软考中常考构造过程,需按顺序选择边,注意边权最小且不形成环,画图时用不同颜色标记树内节点。
题目:开始用 Prim 算法构造最小生成树,边权如下
边:(A-B,2), (A-C,3), (B-C,1), (B-D,4), (C-D,5), (D-E,2), (C-E,3)
解题步骤:
1. 初始化:集合 S={A},未选节点 {T=B,C,D,E},选与 A 相连的最小边 (A-B,2),S={A,B},总权 + 2。
2. 迭代选边:
- 从 S 中节点找连向 T 的最小边:B-C (1),选边,S={A,B,C},总权 + 1;
- 从 S 中找连向 T (D,E) 的最小边:D-E (2) 或 C-E (3),选 (D-E,2),S={A,B,C,D,E},总权 + 2;
- 最后补边 C-E (3),总权 + 3,完成生成树(总权 8)。
Kruskal 算法
先按边权排序,贪心算法每次选最小边,连通所有顶点但不能成环
- 特点:
按边权从小到大排序,依次选边,若不形成环则加入生成树(按边扩展,用并查集判环)。 - 时间复杂度:O (m log m)(排序边的时间)
- 适用场景:
边稀疏图(邻接表更优),如跨区域管道铺设。 - 解题技巧:
- 并查集(Union-Find)判断边的两端是否已连通,避免环。
- 软考中常考边的选择顺序和最终 MST 的权值和,需按边权排序后逐个检查,跳过成环的边。
- 例:给定带权无向图,求 Kruskal 构造的 MST,需先排序边,再依次选边(如权值 1,2,3…),直到选 n-1 条边。
例题: 同上题,对下图用 Kruskal 算法求最小生成树
解题步骤:
1. 按边权排序:(B-C,1), (A-B,2), (D-E,2), (A-C,3), (C-E,3), (B-D,4), (C-D,5)。
2. 用并查集选边,避免环:
- 选 (B-C,1):连接 B 和 C;
- 选 (A-B,2):连接 A 和 B(A 与 C 连通);
- 选 (D-E,2):连接 D 和 E;
- 选 (A-C,3):A 与 C 已连通,跳过;
- 选 (C-E,3):连接 C 和 E(C 与 A、B 连通,E 与 D 连通,合并两个集合);
- 此时 5 个节点已连通,停止。
3. 最小生成树边:(B-C,1), (A-B,2), (D-E,2), (C-E,3),总权值 1+2+2+3=8。
4.4.4 拓扑排序(有向无环图 DAG)
拓扑排序必须是无环的,找入度为0的顶点集合(结果可能有多种)
- 特点:
将 DAG 的顶点排列成线性序列,若存在边 u→v,则 u 在序列中出现在 v 之前(体现任务先后顺序)。 - 时间复杂度:O(n+m)
- 适用场景:
任务调度(如课程先修关系)、依赖分析。 - 解题技巧:
- 计算各顶点入度,将入度为 0 的顶点入队;
- 每次入队顶点,更新其相邻的顶点度数,继续寻找下一个入度为0的顶点,直到所有顶点入队
- 软考中常考拓扑序列的可能情况(非唯一),需注意:
- 入度为 0 的顶点可任选,可能产生不同序列;
- 若最终输出顶点数小于 n,说明图有环(软考可能考环的判断)
题目: 有向图如下,判断哪些序列是合法的拓扑排序。
A→B, A→C, B→D, C→D, C→E, D→F, E→F
解题步骤:
1. 计算入度:A=0,B=1(A), C=1(A), D=2(B,C), E=1(C), F=2(D,E)。
2. 拓扑排序步骤:
- 选入度 0 的 A,删除 A 及边,B、C 入度 - 1→B=0, C=0;
- 选 B 或 C:
- 若先选 B,删除 B 及边,D 入度 - 1→1,此时选 C,删除 C 及边,D 入度 - 1→0,E 入度 - 1→0;
- 选 D,删除 D 及边,F 入度 - 1→1;选 E,删除 E 及边,F 入度 - 1→0;最后选 F。
3. 合法序列示例:A→B→C→D→E→F 或 A→C→B→E→D→F。
4.4.5 关键路径算法(项目管理)
给出活动图并标注每段路径上(顶点的边)的工时(权重),找关键路径(从起点到终点权重最大的)
- 特点:
在 AOE 网络(带权有向图,边表示活动,权为耗时)中,找从起点到终点的最长路径(关键路径),决定项目总工期。 - 时间复杂度:O(n+m)
- 解题步骤:
- 根据给出的活动图,选出关键路径(工时最长的(权重最大的)路径)
- 一般题目有两问,关键路径必问,另一问是其中一段路径的最晚开始时间(若在关键路径上那最晚开始时间为0,其他路径上的,用关键路径时间减去其他活动时间即可)
4.4.6 强连通分量(Tarjan 算法)
连通分量
直接按照给出的图数就行了
示例
无向图结构:
A---B C---D E
| |
F G
- 连通分量为:{A,B,F}、{C,D,G}、{E}(共 3 个)。
强连通分量识别
无需使用 Tarjan 或 Kosaraju 等算法,通过观察图的结构、寻找环和双向可达路径即可高效解题
条件
- 分量内任意两点 u、v,存在 u 到 v 和 v 到 u 的有向路径
- 无法向分量中添加任何其他节点,否则破坏双向可达性
题目: 有向图如下,求所有强连通分量(SCC)。
A→B, B→C, C→A, B→D, D→E, E→D
解题:
- 根据题意画出有向图
- 找到所有 “双向可达的节点簇”,且簇间无双向路径
- 强连通分量为:{A,B,C} {D,E}
5、三角矩阵
5.1 定义与分类
上三角矩阵
主对角线(i=j)以下的元素全为 0,即当 i > j 时, a [ i ] [ j ] a [i][j] a[i][j] = 0
plaintext
[a11 a12 a13]
[0 a22 a23]
[0 0 a33]
下三角矩阵
主对角线以上的元素全为 0,即当 i <j 时, a [ i ] [ j ] a [i][j] a[i][j] = 0
plaintext
[a11 0 0 ]
[a21 a22 0 ]
[a31 a32 a33]
5.2 压缩存储(核心考点(常考下标计算))
三角矩阵的压缩存储目的是用一维数组存储非零元素,节省空间
解题技巧
明白压缩存储规则后,结合给出的矩阵图或自己画出,若题意简单只求前几个元素的数组下标,则直接穷举,若计算下标大则可自行推出 n阶矩阵元素与一维数组下标的函数关系
- 下三角矩阵的压缩存储(行优先)
- 只存储主对角线及下方元素,一维数组长度为 n (n+1)/2
- 元素 a [ i ] [ j ] a [i][j] a[i][j] 的存储位置公式:当 i ≥ j 时(非零元素), ( k = ( i − 1 ) × i 2 + ( j − 1 ) ) (k = \frac{(i-1) \times i}{2} + (j-1)) (k=2(i−1)×i+(j−1))
- 上三角矩阵的压缩存储(行优先)
- 只存储主对角线及上方元素,一维数组长度为 n (n+1)/2。
- 元素 a [ i ] [ j ] a [i][j] a[i][j] 的存储位置公式: 当 i ≤ j 时(非零元素): ( k = ( i − 1 ) × ( 2 n − i + 2 ) 2 + ( j − i ) ) (k = \frac{(i-1) \times (2n - i + 2)}{2} + (j - i)) (k=2(i−1)×(2n−i+2)+(j−i))
例题:
- 某 5 阶下三角矩阵按行优先存储在一维数组中,若矩阵下标从 1 开始,则 a [ 3 ] [ 2 ] a [3][2] a[3][2] 的存储位置是?
- 解析: ( k = ( 3 − 1 ) × 3 2 + ( 2 − 1 ) = 3 + 1 = 4 ) (k = \frac{(3-1) \times 3}{2} + (2-1) = 3 + 1 = 4) (k=2(3−1)×3+(2−1)=3+1=4)(一维数组下标从 0 开始时,结果为 4)
注意
- 题目中矩阵下标起始必须确认:未说明时默认从 1 开始,但真题可能标注 “下标从 0 开始”,需仔细审题。
- 区分行优先与列优先:软考中以行优先为主,但需注意题目是否特殊说明(列优先时公式不同)。
- 零元素不存储:三角矩阵的压缩存储只存非零元素,零元素不占空间,因此一维数组长度为 n (n+1)/2,与对称矩阵相同
拓展
在软考中,矩阵 / 二维数组的行优先和列优先存储是高频考点,核心思路是通过 “计算前面元素总量 + 当前位置偏移量” 来推导存储下标
6、算法思想
掌握四大算法(特点、是否全局最优),时间复杂度和空间复杂度等概念(用O() 表示)
| 算法 | 核心逻辑 | 是否关心全局 | 子问题关系 | 典型场景 | 例子类比 |
|---|---|---|---|---|---|
| 分治法 | 分小问题→独立解决→合并 | 关心(追求全局最优) | 独立(不重叠) | 排序、查找、大数乘法 | 分苹果→排序两半→合并结果 |
| 贪心法 | 每一步选当前最优(局部最优) | 不关心(仅求当前最优) | 无(仅依赖当前状态) | 找零钱、Dijkstra 算法 | 每次选面值最大的硬币凑钱 |
| 动态规划 | 记录子问题解→避免重复计算 | 关心(通过子问题推导全局) | 重叠(重复出现) | 背包问题、最长公共子序列 | 爬楼梯时记录每一层的方法数 |
| 回溯法 | 穷举所有路径→错了就回溯 | 关心(穷举所有可能解) | 无(通过剪枝优化搜索) | 八皇后、子集生成、数独 | 走迷宫时试错后退回换路 |
时间复杂度计算
评估执行时间随输入规模的增长趋势(O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2ⁿ) < O(n!))
- 常数时间 O (1)
- 操作次数与输入规模 n 无关,时间复杂度为 O (1)
- 输入下标查找数组元素,直接根据下标返回元素
- 线性时间 O (n)
- 循环执行 n 次,每次循环内操作时间为 O (1),总时间为 O (n)
- 一次循环遍历数组
- 平方时间 O (n²)
- 总操作次数 ≈ n*(n-1)/2 ≈ n²/2,忽略系数和低阶项,时间复杂度为 O (n²)
- 冒泡排序,两层循环,每次选取的元素都要与剩余其他元素比较
- 对数时间 O (log n)
- 每次循环将问题规模缩小一半,总次数为 log₂n,时间复杂度为 O (log n)
- 二分查找,构建树,每次比较都能将规模缩小一半
- 线性对数时间 O (n log n)
- 递归树深度为 log n,每一层合并操作时间为 O (n),总时间为 O (n log n)
- 归并排序、堆排序,构建树,合并结果。
空间复杂度计算
评估额外存储空间随输入规模的增长趋势
- 常数时间 O (1)
- 使用常数级额外变量
- 线性时间 O (n)
- 创建了一个与输入数组等大的新数组,额外空间为 O (n)
- 递归调用 会在栈上保存 n 个函数调用帧,每个帧保存局部变量,空间复杂度为 O (n)
- 递归 + 线性空间 O (n)
- 归并排序:递归栈深度为 O (log n),但每次合并创建的临时数组最大为 O (n),空间复杂度由更大的 O (n) 决定
- 对数时间 O (log n)
- 每次循环将问题规模缩小一半,总次数为 log₂n,时间复杂度为 O (log n)
- 二分查找,构建树,每次比较都能将规模缩小一半
- 线性对数时间 O (n log n)
- 递归树深度为 log n,每一层合并操作时间为 O (n),总时间为 O (n log n)
- 归并排序、堆排序,构建树,合并结果。
6.1 装包问题
将价值不同的物品装入固定容量的背包,求装包最大价值
0-1装包问题
动态规划 + 逆序遍历容量
状态转移方程
手动画表格推演
例题:有 4 个物品,重量分别为 [2, 3, 4, 5],价值分别为 [3, 4, 5, 6],背包容量为 8。求装入背包的最大价值。
解法步骤:
-
状态定义:设
dp[i][j]表示前i个物品放入容量为j的背包中的最大价值。 -
状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])- 依赖上一行物品状态,
dp[i-1][j-w[i]]避免重复选择
-
填表计算:
| 物品 \ 容量 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 (2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 2 (3,4) | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 |
| 3 (4,5) | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 9 |
| 4 (5,6) | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
结果:最大价值为 10(选择物品 2 和 4,重量 3+5=8,价值 4+6=10)。
完全装包问题
动态规划 + 正序遍历容量
状态转移方程
dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i])- 依赖上一行和当前行,
dp[i][j-w[i]]可以多次选取当前物品
| 物品 \ 容量 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 (2,3) | 0 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 12 |
| 2 (3,4) | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
| 3 (4,5) | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
| 4 (5,6) | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
最优解:选物品 1(2/3)四次,总价值 12。
关键差异解释
-
状态转移方向
- 0-1 背包:
dp[i][j]仅依赖上一行i-1的状态(确保每个物品仅选一次)。
例如,处理物品 2(3/4)时,dp[2][6] = max(dp[1][6]=3, dp[1][3]+4=7)。 - 完全背包:
dp[i][j]依赖上一行i-1(不选当前物品)和当前行i(选当前物品)。
例如,处理物品 1(2/3)时,dp[1][8] = max(dp[0][8]=0, dp[1][6]+3=9)→ 选两次物品 1。
- 0-1 背包:
-
遍历顺序的影响
- 0-1 背包:
一维数组优化时需逆序遍历容量,防止重复选取。
例如,容量 8 在处理物品 1 时,若正序遍历会导致dp[8] = dp[6]+3(选两次物品 1)。 - 完全背包:
一维数组优化时需正序遍历容量,允许重复选取。
例如,容量 8 在处理物品 1 时,dp[8] = dp[6]+3表示 “在已选两次物品 1 的基础上再选一次”。
- 0-1 背包:
-
最优解的来源
- 0-1 背包:
每个物品仅能选 0 次或 1 次,最优解由不同物品组合而成(如物品 2+4)。 - 完全背包:
同一物品可重复选,最优解可能来自单一物品的多次选取(如四次物品 1)
- 0-1 背包:
部分装包问题
贪心算法
例题:有 3 个物品,重量分别为 [10, 20, 30],价值分别为 [60, 100, 120],背包容量为 50。求装入背包的最大价值(物品可分割)。
解法步骤:
-
计算单位价值:
- 物品 1:60/10 = 6
- 物品 2:100/20 = 5
- 物品 3:120/30 = 4
-
按单位价值降序排序:物品 1 → 物品 2 → 物品 3。
-
贪心选择:
- 选物品 1 全部(10kg,价值 60),剩余容量 40kg。
- 选物品 2 全部(20kg,价值 100),剩余容量 20kg。
- 选物品 3 的 2/3(20kg,价值 120×2/3=80),剩余容量 0kg。
结果:最大价值为 60 + 100 + 80 = 240。
6.2 查找
二分查找(折半查找)
- 必须有序
- 每次查询取中间元素比较,每次能将规模减半
- 时间复杂度为 O(logn)
例:下列序列中,不可能是二分查找某数的比较序列的是
A.
[
5
,
3
,
4
]
[5, 3, 4]
[5,3,4]
B.
[
4
,
6
,
5
]
[4, 6, 5]
[4,6,5]
C.
[
4
,
2
,
5
]
[4, 2, 5]
[4,2,5]
D.
[
3
,
5
,
7
]
[3, 5, 7]
[3,5,7]
答案:A
- 初始假设:数组包含 5、3、4,升序为
[3,4,5],长度 3,中间索引为 1(值为 4)。- 但序列第一个元素是 5,而数组中间值应为 4,矛盾 → A 不可能。
- 假设数组:如
[1,2,3,4,5,6,7](升序),长度 7,初始中间索引 3(值为 4)- 目标值 >4,右半区为
[5,6,7],中间索引 5(值为 6) - 目标值 <6,左半区为
[5],中间索引 4(值为 5) → 符合逻辑 → B 可能
- 目标值 >4,右半区为
哈希表(散列表)
- 哈希函数
- 将关键字(Key)映射为哈希表索引的函数,记为
h(key)
- 将关键字(Key)映射为哈希表索引的函数,记为
- 哈希碰撞
- 不同关键字通过哈希函数映射到同一索引的现象
- 哈希函数
h(key) = key % 10,则h(13) = 3和h(23) = 3发生碰撞
- 哈希函数
- 同义词的概念
- 具有相同哈希地址的关键字互为同义词
- 处理方法
- 开放寻址法(线性探测)
- 发生hash碰撞时,遍历该索引的后续索引若无元素则放置
- 会有元素扎堆的情况
- 链地址法
- 在冲突位置形成链表(头插法)
- 开放寻址法(线性探测)
- 不同关键字通过哈希函数映射到同一索引的现象
- 负载因子
- 哈希表中已存储元素数(n)与表长(m)的比值,即
α = n/m - 初始表长 m=8,阈值
8×0.75 = 6,即插入第 7 个元素时需扩容,扩容为原来长度的两倍,所有元素重新hash计算
- 哈希表中已存储元素数(n)与表长(m)的比值,即
6.3 排序
|
三、操作系统
1、进程状态切换
要掌握进程状态变化是主动行为还是被动行为
进程状态
- 新建
- 就绪
- 运行
- 阻塞
- 终止
主动行为:进程自身触发的切换
| 切换方向 | 主动行为场景 | 触发原因 |
|---|---|---|
| 运行态→就绪态 | 1. 时间片用完(时间片轮转调度) 2. 进程主动放弃 CPU(如调用 yield()函数) | 进程主动让出 CPU,进入就绪队列等待调度 |
| 运行态→阻塞态 | 1. 等待 I/O 操作完成(如读取文件) 2. 等待资源(如锁、信号量) 3. 等待其他进程通知(如 wait()) | 进程因需要等待外部事件或资源而主动阻塞 |
被动行为:由操作系统或外部事件触发的切换
| 切换方向 | 被动行为场景 | 触发原因 |
|---|---|---|
| 就绪态→运行态 | 1. 调度器选择更高优先级进程抢占 CPU 2. 时间片轮转中,当前进程时间片用完,就绪队列中的进程被调度 | 操作系统根据调度算法被动分配 CPU |
| 阻塞态→就绪态 | 1. 等待的 I/O 操作完成 2. 等待的资源可用 3. 收到其他进程的通知(如 signal()) | 外部事件完成,操作系统将进程从阻塞队列移至就绪队列 |
| 运行态→终止态 | 1. 进程执行完毕(正常终止) 2. 进程因错误终止(如除零错误、越界访问) | 进程执行结束或异常,由操作系统被动终止 |
软考常见陷阱与解题技巧
-
区分 “主动阻塞” 与 “被动调度”:
- 进程因等待资源主动进入阻塞态(如
read()调用),属于主动行为; - 进程被调度器强制切换(如时间片用完),属于被动行为。
- 进程因等待资源主动进入阻塞态(如
-
典型例题场景:
- 若进程执行
wait()函数等待子进程结束,状态从运行态→阻塞态,属于主动行为; - 若进程因 I/O 完成从阻塞态→就绪态,由操作系统中断处理触发,属于被动行为。
- 若进程执行
-
记忆口诀:
- 主动行为:自己要阻塞(等资源)、自己让 CPU(时间片到或主动 yield);
- 被动行为:被系统调度(就绪→运行)、被事件唤醒(阻塞→就绪)、被系统终止(运行→终止)。
2、线程共享
线程私有
- 线程栈
- 程序计数器(PC)
线程共享 - 代码段
- 数据段
- 全局变量、静态变量(如 C 语言中的
static变量)
- 全局变量、静态变量(如 C 语言中的
- 堆内存
- 文件描述符
3、进程死锁
条件
- 互斥条件
- 不剥夺条件
- 保持资源不释放
- 请求资源形成循环链
解决 - 预防
- 通过破坏死锁产生的四个必要条件中的一个或多个来预防死锁的发生
- 避免(银行家算法)
- 存在一个安全序列,使所有进程都能在有限时间内获得所需资源完成执行(可用资源>=需求资源)
- 只要有一个安全序列那系统就是安全状态,反之进入不安全状态,可能所有进程都无法执行下去
- 死锁解除
- 通过死锁检测判断系统是否处于死锁状态,若死锁,则由系统强制剥夺部分进程的资源,将资源强行分配给别的进程
3.1 避免进程死锁的最小资源数(临界值)
题目:3个进程请求资源R,每个进程需要5个R,至少分配多少R才不会死锁
- 当每个进程都先获取 4 个R 时,系统剩余资源数必须至少为 1,这样才能让某一进程获取最后 1 台资源并释放所有资源,进而允许其他进程依次完成
- 3 ∗ 4 + 1 = 13 3*4+1=13 3∗4+1=13;因为只要再多 1 个资源 R,就可以打破这种死锁的临界状态,使其中一个进程能够获得足够的资源去执行,进而释放资源供其他进程使用,避免死锁的发生
用银行家算法来验算
- 当 总资源为=13 时
- 总分配资源:13 R,1 R(
Available=[2])。 - 每个进程的需求矩阵
Need=[5-4]=1 - 安全性检查
- 可用资源
(
1
≥
1
)
(1 \geq 1)
(1≥1),可任选一个进程(如 P1)分配剩余 1 个,使其完成并释放 5 个资源。此时
Available变为 ( 0 + 5 = 5 ) (0+5=5) (0+5=5),剩余 2 个进程均可依次获取资源完成
- 可用资源
(
1
≥
1
)
(1 \geq 1)
(1≥1),可任选一个进程(如 P1)分配剩余 1 个,使其完成并释放 5 个资源。此时
- 存在安全序列(如 P1→P2→P3→P4),系统安全
- 总分配资源:13 R,1 R(
- 当 总资源为=12 时:
- 总分配资源:12 R,剩余 0 R(
Available=[0])。 - 每个进程的
Need=[5-4=1],但无可用资源,所有进程阻塞,系统进入死锁状态
- 总分配资源:12 R,剩余 0 R(
4、进程PV操作
P(占有资源)V(释放资源)
解题步骤
- 结合给出的前趋图和PV操作图+答案
- 填入给定的信号量即可
- 主要还是理解PV操作及进程间资源的依赖关系
5、文件系统
5.1 文件逻辑结构
用户视角,关注数据组织
- 分类:
- 顺序文件:记录按顺序排列,适合批量访问(如日志文件)。
- 索引文件:通过索引表记录各记录位置,支持随机访问。
- 索引顺序文件:结合前两者,将文件分块,块内顺序、块间索引。
- 常考点:不同逻辑结构的访问效率、适用场景对比。
5.2 文件物理结构
操作系统 / 存储设备视角(关注物理存储)
- 连续存储:文件在磁盘上占用连续块,优点是访问快,缺点是易产生碎片。
- 链接存储:
- 隐式链接:每个块存下一块地址,缺点是查找需遍历。
- 显式链接:用 FAT(文件分配表)记录所有块链接,如 FAT32 文件系统。
- 索引存储:
- 直接索引:文件目录项直接存数据块地址。
- 多级索引:通过一级索引找二级索引,再找数据块,如 UNIX 的 i-node 结构。
- 常考点:多级索引的文件大小计算(如二级索引下最大文件块数)。
5.3 目录结构
- 单级目录:所有文件在同一目录,易冲突。
- 二级目录:分主目录和用户目录,解决命名冲突。
- 树形目录:最常用,如 Windows 的目录结构,通过路径名访问(绝对路径 / 相对路径)。
- 常考点:
- 路径名解析(如
/usr/local/file.txt的层级查找) - 绝对路径 / 相对路径
- 路径名解析(如
5.4 磁盘管理与调度算法
- 磁盘结构:磁头、磁道、扇区、柱面等概念。
- 磁盘调度算法:
- FCFS(先来先服务):按请求顺序处理,可能导致磁头来回移动。
- SSTF(最短寻道时间优先):优先处理离当前磁头最近的请求,可能产生 “饥饿”。
- SCAN(电梯算法):磁头按一个方向移动,处理该方向所有请求后反转,避免饥饿。
- C-SCAN(循环扫描):磁头单向移动,返回时直接跳到起始端,适合磁盘外圈频繁访问场景。
- 常考点:算法特点(根据算法名理解)
5.5 文件保护与安全
- 访问控制:
- ACL(访问控制列表):为每个文件设置用户 / 组的读 ®/ 写 (W)/ 执行 (X) 权限。
- Capability(能力表):用户持有访问文件的 “能力凭证”,如令牌。
- 文件加密:对称加密(如 AES)或非对称加密(如 RSA)保护数据。
- 常考点:
- ACL 与 Capability 的区别、
- 权限位的表示(如 Linux 的
rwxr-xr--对应数字 754)。- r-read/w-write/x-execute/-无权限
rwxr-xr--- 所有者
rwx= 4+2+1 = 7。 - 所属组
r-x= 4+0+1 = 5。 - 其他用户
r--= 4+0+0 = 4
- 所有者
5.6 文件系统性能优化
了解即可 主要是raid技术
- 磁盘缓存:利用内存缓存磁盘数据,减少 I/O 次数。
- 预读与延迟写:提前读取预测数据,延迟写入以批量操作。
- RAID 技术(磁盘阵列(组合)):
- RAID0:无冗余,速度快,一块坏全完。
- RAID1:双盘镜像,50% 空间,坏一块不怕。
- RAID5:奇偶校验分散存,n-1 可用,坏一块能恢复。
- RAID10:先镜像再条带,性能可靠双保险,50% 空间用得值。
- 常考点:RAID 级别特点、容错能力、磁盘利用率。
- 问 “高性能 + 无冗余”:选 RAID 0;
- 问 “高可靠 + 50% 利用率”:选 RAID 1(2 块盘)或 RAID 10(≥4 块盘);
- 问 “平衡性能与冗余”:选 RAID 5;
- 利用率计算:RAID 5 用 (n-1)/n,RAID 1/10 用 50%。
6、虚拟内存
6.1 基本概念
虚拟内存通过内存与外存(如硬盘)的动态交换,让程序认为自己拥有连续的可用内存空间,解决物理内存不足的问题
核心技术
- 分页(Paging)、分段(Segmentation)、段页式(Segmented Paging)
- 考察:虚拟地址对应的物理地址
虚拟地址
- 内存+外存构成庞大的虚拟存储系统,划分给进程虚拟地址
- 虚拟地址 “相同但不冲突”:不同进程的虚拟地址空间在逻辑上独立且范围相同,但通过页表映射到不同的物理内存,实现完全隔离
- 考察:页面置换算法的特点
6.2 存储管理
6.2.1 分页存储管理(重点)
考察重点,也是现代操作系统主流技术
基本概念
- 页(Page):将进程逻辑地址空间划分为固定大小的块(如 4KB)。
- 页框(Page Frame):物理内存划分为与页等大的块。
- 页表(Page Table):记录逻辑页号与物理页框号的映射关系。
地址转换(必考计算)
- 逻辑地址结构:
页号(P) + 页内偏移(d)。- 例:逻辑地址为 32 位,页大小 4KB(2^12),则页内偏移占 12 位,页号占 20 位。
- 转换过程:
- 逻辑地址 → 分解为页号、页内偏移;
- 查页表得物理页框号;
- 物理地址 = 页框号 × 页大小 + 页内偏移
6.2.2 分段存储管理
基本概念
- 段(Segment):按程序逻辑模块(如代码段、数据段)划分,长度可变。
- 段表(Segment Table):记录段号、段长、段基址(物理起始地址)。
地址转换
- 逻辑地址结构:
段号(S) + 段内偏移(d)。- 段最大长度为 64KB(2¹⁶),则偏移量占 16 位
- 32 位地址空间,段内偏移占 16 位,则段号占 32-16=16 位
- 转换过程:
- 查段表得段基址和段长;
- 若段内偏移 ≤ 段长,物理地址 = 段基址 + 段内偏移;
6.2.3 分段存储管理
分段与分页的结合:段页式存储先将程序分段,再将每个段分页
- 逻辑地址结构:
段号 + 段内页号 + 页内偏移量 - 物理地址 = (物理块号 × 页大小) + 页内偏移量
三种存储技术对比
- 内存划分:
- 分页:内存和进程均划分为固定大小的页(如 4KB)
- 分段:进程按逻辑分段(代码段、数据段等),段大小可变
- 段页:先分段,每个段再划分为固定大小的页
- 应用:
- 分页是现代 OS 的内存管理基础,分段更多作为保护机制存在(逻辑上分段,物理上分页)
- 段页式:两级查表开销大,需额外硬件支持(如段表寄存器)
- 碎片对比:
- 分页无外部碎片,分段有外部碎片,段页式结合两者但开销大
- 虚拟存储支持:三者都支持
6.3 页面置换
当内存中页面已满,需要置换出旧页面腾出页框,不同算法的策略和效率是核心考点
算法分类及原理
这些策略共同目标是减少缺页中断次数(缺页中断是指虚拟地址合法但对应页面不在内存,需要与外存换页腾出物理页框)、降低磁盘 I/O 开销,确保虚拟内存系统高效运行,支撑多任务并发和大程序运行
| 算法名称 | 英文 | 策略 | 特点 |
|---|---|---|---|
| 最优置换 | OPT(Optimal) | 置换未来最长时间不再使用的页面(理论上缺页率最低,但无法实现)。 | 用于对比其他算法的理论基准。 |
| 先进先出 | FIFO(First In First Out) | 置换最早进入内存的页面。 | 可能出现Belady 异常(内存增加,缺页率反而上升)。 |
| 最近最少使用 | LRU(Least Recently Used) | 置换最长时间未被访问的页面(需记录页面访问时间)。 | 效率高,但实现成本高(需硬件支持)。 |
Belady 异常
- 在 FIFO 页面置换算法中,增加物理内存页框数量后,程序的缺页率可能不降反升
- FIFO 算法仅考虑页面进入内存的时间先后,而不考虑页面的使用频率或未来访问模式。当内存帧数增加时,可能导致关键页面被过早置换,反而增加缺页次数
页面置换算法例题
- 题目:页面访问序列为 1,2,3,4,1,2,5,1,2,3,4,5,内存容量为 3,用 FIFO/LRU 算法计算缺页次数。
- 解析:
- LRU:
访问 5 时置换 3(最近最少用),后续访问 3 时缺页(置换 4),缺页次数:7 次。 - FIFO:
访问 1-4 时缺页(内存:1,2,3,4 → 需置换 1),后续访问 5 缺页(置换 2),最终缺页次数:9 次。- 访问 1:内存空,装入 1 → [1] ✅
- 访问 2:装入 2 → [1,2] ✅
- 访问 3:装入 3 → [1,2,3] ✅
- 访问 4:置换最早的 1,装入 4 → [2,3,4] ✅
- 访问 1:置换最早的 2,装入 1 → [3,4,1] ✅
- 访问 2:置换最早的 3,装入 2 → [4,1,2] ✅
- 访问 5:置换最早的 4,装入 5 → [1,2,5] ✅
- 访问 1:1 在内存中 → [1,2,5] ❌
- 访问 2:2 在内存中 → [1,2,5] ❌
- 访问 3:置换最早的 1,装入 3 → [2,5,3] ✅
- 访问 4:置换最早的 2,装入 4 → [5,3,4] ✅
- 访问 5:5 在内存中 → [5,3,4] ❌
- 缺页次数:9 次(带✅的步骤)
- LRU:
四、数据库
1、三层模型概念
分层加映射是为了解耦(表示层-数据结构层-物理层),当某一层改动只需修改映射
| 模式层 | 操作视角 / 用户角色 | 典型操作场景 |
|---|---|---|
| 外模式 | 应用开发者、终端用户 | 编写 SQL 查询视图、通过应用程序操作局部数据 |
| 模式 | 数据库设计师、管理员 | 设计表结构、建立表间关系、定义约束规则 |
| 内模式 | 系统管理员、存储工程师 | 优化索引、调整存储路径、管理磁盘空间分配 |
| 对于程序员来说相当于:外模式-sql查询结果/模式-表结构设计/内模式-存储引擎选择,索引优化选择 |
考点总结
-
三级模式的核心作用:
- 外模式:屏蔽用户间的数据差异;
- 模式:统一全局数据逻辑;
- 内模式:管理物理存储细节。
-
两级映射的独立性:
- 外模式 - 模式映射 → 逻辑独立性(改逻辑结构不影响应用);
- 模式 - 内模式映射 → 物理独立性(改存储方式不影响逻辑)。
-
应试记忆技巧:
- 外模式→用户视角,模式→设计视角,内模式→存储视角;
- 映射如 “翻译器”,隔离上层与下层的变化影响。
2、关系模式的基本概念
2.1 基本元素概念
类比mysql
- 关系模式 → 表结构(列定义,如字段名、类型)。
- 元组 → 表中的一行数据(记录)。
- 属性 → 表中的列(字段)。
2.2 主外键
超键>候选键> 主键 = 主属性
关系模式
├─ 键体系:
| |─ 超键(能唯一标识任意属性集,包含候选键作为子集)
│ ├─ 候选键(最小唯一标识属性集)
│ ├─ 主键(选定的候选键)
│ └─ 主属性(候选键中的属性)
│ └─ 外键(引用其他关系主键的属性,可为主/非主属性)
例
学生表(Student)
属性:学号(Sno)、姓名(Sname)、身份证号(ID)、班级(Class)
| Sno | Sname | ID | Class |
|---|---|---|---|
| 001 | 张三 | 1101011990 | 计科 1 班 |
| 002 | 李四 | 1101011991 | 计科 1 班 |
键的解析
- 超键(Super Key):
- 能唯一标识元组的任意属性集,包含候选键作为子集。
- 例子:
{Sno},{ID},{Sno, Sname},{ID, Class}等(只要包含候选键即可)。
- 候选键(Candidate Key):
- 能唯一标识元组的最小属性集(不可再拆分)。
- 例子:
{Sno},{ID}(两者均可唯一标识学生,且去掉任何一个属性后无法唯一标识)。
- 主键(Primary Key):
- 从候选键中选定的一个,设为
{Sno}(实际业务中常用学号作为主键)。
- 从候选键中选定的一个,设为
- 主属性(Prime Attribute):
- 所有候选键中的属性,即
Sno和ID。
- 所有候选键中的属性,即
2.3 函数依赖
属性之间的依赖关系
函数的依赖(考点)
- 部分函数依赖:A-C || B-C
- 传递函数依赖:A-B-C b不可以返a
- 考点:给出关系模式中的依赖关系(有向图形式),求其候选键(候选码)和主属性(候选键中每一位都可以成为主属性)
3、关系代数运算
七种基本运算:交、并、差、笛卡尔积、选择(对行)、投影(队列)、连接(join)
3.1 运算简介
- 集合运算:
- 作用于结构相同的关系
- 并: ( R ∪ S ) (R \cup S) (R∪S) 并运算结果会去重
- 交: ( R ∩ S ) (R \cap S) (R∩S) 两者都有
- 差: ( R − S ) (R - S) (R−S) R相较于S独有的
- 选择与投影:
- 分别对 “行” 和 “列” 筛选
- 选择:选择 “年龄> 20” 的学生,符号: ( σ 年龄>20 ( R ) ) (\sigma_{\text{年龄>20}}(R)) (σ年龄>20(R)) 根据条件筛选元祖
- 投影:选择列并且去重,符号: ( π 属性1, 属性2,... ( R ) ) (\pi_{\text{属性1, 属性2,...}}(R)) (π属性1, 属性2,...(R))
- 笛卡尔积(
R × S):- 无约束的组合,两个关系模式的元祖相互组合 mxn,结果属性列和元组数量爆炸式增长。
- 连接:
- 通过共同属性关联两个关系,是多表查询的核心运算(等值连接需显式条件)。
- 等值连接(`R ⋈ S)
- 显式指定连接条件,例如
R ⋈ S WHERE R.A = S.B - 结果表包含两个关系的所有属性列(可能有重复列),仅保留满足等值条件的元组
- 示例:若 R 有属性 A、B,S 有属性 B、C,等值连接结果为
R.A, R.B, S.B, S.C中满足R.B = S.B的元组
- 显式指定连接条件,例如
- 自然连接(
R ∞ S)- 一种特殊的等值连接,要求两个关系具有至少一个同名公共属性,自动在公共属性上进行等值连接,并去除重复属性列
- 示例:R (A, B) 和 S (B, C) 的自然连接结果为
A, B, C,仅保留 R.B = S.B 的元组,且 B 列只出现一次
- 外连接
R ⟕ S或R LEFT JOIN S(以左为主,保留左边所有)R ⟖ S或R RIGHT JOIN S(以右为主,保留右边所有)R ⟗ S或R FULL JOIN S(相当于左外连接和右外连接的并集)
3.2 运算例题
关系 R(学生表:学号,姓名)
| 学号 | 姓名 |
|---|---|
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
关系 S(学生表:学号,姓名)
| 学号 | 姓名 |
|---|---|
| 2 | 李四 |
| 3 | 王五 |
| 4 | 赵六 |
关系 T(课程表:学号,课程)
| 学号 | 课程 |
|---|---|
| 1 | 数学 |
| 2 | 英语 |
3.2.1、集合运算:交、并、补
交运算(R ∩ S)
定义:取两关系的公共元组。
示例:
R ∩ S = {(2, 李四), (3, 王五)}
说明:仅保留 R 和 S 中完全相同的行。
并运算(R ∪ S)
定义:取两关系的所有元组,去重。
示例:
R ∪ S = {(1, 张三), (2, 李四), (3, 王五), (4, 赵六)}
说明:合并 R 和 S,重复行只保留一次。
补运算(R 的补集,假设全域 U 为所有学生)
定义:全域 U 中不属于 R 的元组。
假设 U = {(1, 张三), (2, 李四), (3, 王五), (4, 赵六), (5, 钱七)}
示例:
R的补集 = {(4, 赵六), (5, 钱七)}
说明:补集依赖于预先定义的全域 U。
3.2.2、一元运算:选择、投影
选择运算(σ 条件 ®)
定义:从关系中筛选满足条件的元组。
示例:筛选 R 中学号 > 1 的学生
σ 学号>1 (R) = {(2, 李四), (3, 王五)}
符号:σ 为选择运算符,条件写在括号内。
投影运算(π 列名 ®)
定义:从关系中选取指定列,去重。
示例:从 R 中投影出学号列
π 学号(R) = {(1), (2), (3)}
符号:π 为投影运算符,列名用逗号分隔。
3.2.3、二元运算:笛卡尔积、连接
笛卡尔积(R × T)
定义:两关系所有元组的无序组合。
示例:
R × T = [
(1,张三,1,数学), (1,张三,2,英语),
(2,李四,1,数学), (2,李四,2,英语),
(3,王五,1,数学), (3,王五,2,英语)
]
结果行数:3×2=6 行,列数:2+2=4 列。
等值连接(R ⋈ R. 学号 = T. 学号 T)
定义:按指定条件(如 R. 学号 = T. 学号)连接两关系,保留重复列。
示例:连接 R 和 T,条件为学号相等
结果 = [
(1,张三,1,数学),
(2,李四,2,英语)
]
说明:仅保留学号相等的元组,列名包含 R. 学号和 T. 学号(重复列)。
自然连接(R ∞ T)
定义:基于公共属性(学号)等值连接,去重重复列。
示例:
结果 = [
(1,张三,数学),
(2,李四,英语)
]
说明:公共属性 “学号” 只保留一列,等价于π 去重列(σ R.学号=T.学号 (R×T))。
左外连接(R ⟕ T)
定义:保留左关系(R)所有元组,右关系(T)未匹配的元组补空值。
示例:
结果 = [
(1,张三,数学),
(2,李四,英语),
(3,王五, NULL) -- R中3号学生在T中无课程记录
]
SQL 对应:SELECT * FROM R LEFT JOIN T ON R.学号=T.学号。
右外连接(R ⟖ T)
定义:保留右关系(T)所有元组,左关系(R)未匹配的元组补空值。
示例:
结果 = [
(1,张三,数学),
(2,李四,英语),
(NULL, NULL, 未定义) -- T中无额外元组,结果与等值连接相同(若T有新学号则会补空)
]
说明:若 T 中所有学号都在 R 中存在,则右外连接结果与等值连接一致。
全外连接(R ⟗ T)
定义:保留两关系所有元组,未匹配的元组补空值。
示例:
结果 = [
(1,张三,数学),
(2,李四,英语),
(3,王五, NULL) -- R独有元组
]
说明:若 T 有 R 中不存在的学号(如 T 有 (5, 物理)),则结果会增加(NULL, NULL, 5, 物理)。
4、三大范式
数据库的规范化(设计标准)重点在1 2 3NF
- 1NF
- 属性原子性,不可再分
- 2NF
- 满足1的前提下,消除非主属性部分依赖
- 非主属性必须依赖整个主键
- 3NF
- 满足2的前提下,消除非主属性对主属性的传递函数依赖
- 非主属性只与主键直接相关
- BCNF
- 满足3的前提下,消除主属性间的依赖(更严格)
- 每个依赖的左侧都是超键
例
假设有一个关系模式
StudentCourse,包含以下属性:学号、姓名、年龄、课程号、课程名、成绩、教师姓名、教师电话
- 这里只满足1NF
- 分解为
student(学号、姓名、年龄) course(课程号、课程名、教师姓名、教师电话) student_course(学号、课程号、成绩)三个表后满足2NF 这三个表完全依赖主键- 原模式中同一学生的姓名、年龄会随选课次数重复存储,拆分后仅存一次
- 细分课程表
course(课程号、课程名、教师姓名) teacher(教师姓名、教师电话)后满足第3NF- 教师电话仅存一次,原模式中同一教师的电话会随课程数重复存储
- 若基于3NF的前提下,
teacher -教师姓名不是候选键,那不满足BCNF
5、并发控制
- X锁(exclude独占锁)
- X锁的前提下不允许添加其他锁
- S锁(share共享锁)
- S锁的前提下,允许加S锁,不允许加X锁
五、软件工程
1、开发模型
瀑布、螺旋、喷泉、敏捷(常考)
| 模型 | 一句话图形联想 | 简笔画记忆点 | 描述 |
|---|---|---|---|
| 瀑布模型 | 一条直线向下,阶段按顺序排列 | ↓ 需求→设计→开发→测试 | 线性流程(需求→设计→开发→测试→交付),强调阶段文档与严格控制。 |
| 螺旋模型 | 带风险分析的螺旋圈 | 🔄 每圈 4 个象限(风险核心) | 结合瀑布与原型,引入风险评估环节,通过 “计划→风险评估→原型→评审” 循环迭代。 |
| 喷泉模型 | 上下循环的喷泉状 | 💦 迭代无间隙(分析↔设计↔实现) | 面向对象开发,强调迭代和无间隙,各阶段活动交叉进行 |
| 增量模型 | 分块叠加的积木 | 🧱 模块 1→模块 2→模块 3 | 分阶段交付可运行的增量模块,逐步集成完整系统。 |
| 原型模型 | 先画草图再细化 | ✏️ Demo→修改→成品 | 先构建简化原型供用户确认,再基于反馈迭代开发。 |
| V 模型 | 左右对称的 V 字 | V 左开发→右测试对应 | 强调测试与开发阶段的对应关系,早期介入测试 |
| 敏捷模型 | 多个短冲刺的跑道 | 🏃♂️ 短周期(Sprint)迭代 | 以用户价值为核心,通过短周期迭代、快速反馈应对需求变化,强调团队协作与自适应调整。 |
记忆技巧:
- 瀑布模型:线性流程文档全,需求稳定才适用。
- 螺旋模型:风险驱动循环走,复杂项目它拿手。
- 喷泉模型:面向对象迭代快,无缝开发文档严。
- 敏捷开发:短冲刺、快反馈,需求多变它最对。
敏捷模型补充
- 个体和互动 高于 流程和工具;
- 工作的软件 高于 详尽的文档;
- 客户合作 高于 合同谈判;
- 响应变化 高于 遵循计划
主流敏捷方法(软考重点)
- Scrum(最常考敏捷框架)
- 关键词:冲刺会议、迭代周期、待办列表
- 应用:需求频繁变化、需快速迭代验证的项目
- 极限编程(XP)
- 关键词:测试先行(先写测试用例)、 客户参与
- 适用场景:对代码质量要求极高、需求明确但需快速响应变化的中小型团队
- 看板方法(Kanban)
- 关键词:可视化 + WIP 限制 + 流程优化
- 适用场景:流程优化、持续交付场景
| 模型 | 最突出的 1-2 个特征 | 典型场景 / 关键词 |
|---|---|---|
| XP | ✅ 测试驱动开发(TDD) ✅ 结对编程 | TDD、结对编程、持续集成 |
| Crystal | ✅ 以人为本,按项目调整流程 ✅ 轻量化流程 | 颜色分类、反思会议 |
| Scrum | ✅ 固定仪式(冲刺、站会、Sprint) ✅ 产品待办项(Backlog) | 冲刺、站会、Backlog |
| ASD | ✅ 自适应与价值驱动 | 探索 - 适应 - 交付循环 |
| 看板 | ✅ 可视化流程 ✅ 限制 WIP | 看板墙、WIP 限制、流动指标 |
2、面向对象程序设计
面向对象的相关概念
- 封装
- 继承
- 多态
- 多态分类:参数多态(泛型)、包含多态(接口实现)、过载多态(方法重载)
设计原则:
- 开放-封闭:对拓展开放 对修改关闭
- 共同重用:
- 相关联的类应被打包在同一个模块中,使得它们要么一起被重用,要么一起被排除,避免用户被迫依赖不需要的部分
- 共同封闭:
- 一个变化若对包产生影响 则将对包中所有的类产生影响 而对于其他包不造成任何影响
- 接口分离:
- 不应该要求强迫客户依赖于他们不用的方法(接口拆分单一职责) 及依赖于抽象不应该依赖于具体
口诀记忆法(SOLID+C+L)
- SOLID 口诀(重要):
- S单一职责(Single)
- 单个类或接口只完成一项功能(功能内聚,方便重用)
- O开闭原则(Open/Closed)
- 对扩展开放,对修改封闭(通过抽象类 / 接口实现新功能)
- L里氏替换(Liskov)
- 子类可替换父类而不影响程序正确性(如正方形子类应符合矩形行为)
- I接口隔离(Interface)
- 客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
- D依赖倒置(Dependency)
- 高层模块依赖抽象而非具体实现(如
Person类依赖Vehicle接口而非具体汽车类)
- 高层模块依赖抽象而非具体实现(如
- S单一职责(Single)
- 补充 2 原则:
- C合成复用(Composite)
- 优先使用对象组合(聚合 / 组合)而非继承来实现复用
- L迪米特法则(Demeter,首字母 L,联想 “最少知识”)
- 一个对象应该对其他对象有最少的了解,即只与直接朋友通信
- C合成复用(Composite)
3、程序系统耦合内聚分类
程序设计追求低耦合高内聚,这些耦合内聚类型的特点需要记忆
耦合内聚分类
- 内聚:
- 逻辑内聚:
- 模块包含若干逻辑相关但功能不同的操作(如处理不同类型的输入),通过参数区分行为
功能边界模糊,修改其中一个操作可能影响其他操作,维护成本高
- 模块包含若干逻辑相关但功能不同的操作(如处理不同类型的输入),通过参数区分行为
- 通信内聚:
- 模块内操作基于相同的数据(如处理同一数据集),但操作逻辑未必连续
- 功能内聚:
- 所有的元素共同完成一个功能,最强内聚
- 过程内聚:
- 模块内操作按特定流程顺序执行(如先输入、再处理、最后输出),但操作之间可能涉及不同功能
- 偶然内聚:
- 模块内元素无实质关联,仅因物理位置相近(如代码复用)而组合,功能完全无关;内聚度最低,模块功能混乱,难以维护和复用,应避免
- 顺序内聚
- 模块内前一个操作的输出是后一个操作的输入,功能紧密关联且顺序固定
逻辑连贯,依赖明确;不足:若流程中的某一步需要独立复用,较难拆分
- 模块内前一个操作的输出是后一个操作的输入,功能紧密关联且顺序固定
- 时间内聚
- 模块内操作因执行时间相近而组合(如初始化、清理等步骤),但功能无直接关联
- 逻辑内聚:
- 耦合:
- 内容耦合
- 模块直接访问另一模块的内部数据(如修改全局变量、跳转至其他模块的代码行)
- 公共耦合
- 多个模块共享全局数据区(如全局变量、公共数据结构),通过操作共享数据交互
- 外部耦合
- 模块依赖外部环境(如操作系统、硬件配置)或统一的外部接口(如文件格式、通信协议)
- 控制耦合
- 模块间通过传递控制参数(如标志位、开关量)影响对方的逻辑流程
- 标记耦合
- 模块间通过传递复杂数据结构(如结构体、对象)进行交互,但仅使用其中部分字段
- 数据耦合
- 模块间通过传递简单数据(如基本类型、单一参数)进行交互,不依赖复杂结构
- 无直接耦合
- 模块间无直接交互,通过第三方中介(如事件总线、消息队列)或完全独立
- 内容耦合
4、UML图
4.1 类图
类图的基本元素
- 类名(接口名)
- 访问修饰符 属性名:属性类型
- 访问修饰符 方法名(参数):返回值类型
类与类之间的关系(耦合程度逐渐增大)
- 依赖
- 虚线箭头,箭头从使用类指向被依赖的类
- 表示使用关系如通过方法参数或静态方法访问对象 (public void test(OtherObj obj){})
- 关联
- 一般关联
- 可单可双,实线箭头,使用类指向被关联的类 (private OtherObj obj)
- 对象间的引用关系,通常将一个类的对象作为另一个类的成员变量来实现关联关系
- 无严格生命周期依赖
- 聚合(has-a)
- 带空心菱形的实线,部分指向整体(obj -> List)
- 汽车(Car) ◇← 轮胎(Tire)
- 是强关联关系,是整体和部分之间的关系;也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在(如老师-学校)
- 组合 (contains-a)
- 带实心菱形的实线,部分指向整体(实体属性)
- 人(Person) ◆← 心脏(Heart)
- 也表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系
- 在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在(结构体密不可分)
- 一般关联
- 泛化(is-a)
- 带空心箭头的实线,箭头从子类指向父类
- 耦合度最大的一种关系,表示一般与特殊的关系;是父类与子类之间的关系,是一种继承关系。
- 实现
- 带空心箭头的虚线,箭头从实现类指向接口
4.2 用例图
描述系统与外部参与者的交互,定义功能边界(“系统做什么”)
需掌握:参与者(Actor)、用例(UseCase)、关联 / 扩展 / 包含关系
核心元素符号:
- 参与者:人形符号
- 可以是用户也可以是外部系统
- 用例:椭圆
[用例名]- 系统中的一个功能单元,用例≠功能点,而是 “用户想达成的目标”
- 用例之间关系
- 关联
- 实线
- 表示执行者和系统之间的关系
- 泛化:
- 空心实线箭头
- 用例继承,一个抽象用例被多个具体的子用例继承
- 包含关系:
- 虚线箭头,需要在箭头上标注: < < i n c l u d e > > <<include>> <<include>>
- 由
包含用例指向被包含用例 - 指一个用例作为另一个用例必需的部分被使用,包含关系是依赖关系的一种
- 扩展关系:虚线箭头 +标注
<<extend>>- 虚线箭头,需要在箭头上标注:<< e x t e n d extend extend>>
- 由
拓展用例指向基本用例 - 扩展是指一个用例扩充了另一个用例的功能,但这个扩充功能不是必需的,扩展关系也是依赖关系的一种
- 关联
示例:图书馆系统用例图
☺ User
[借阅书籍]
[查询书籍]
[归还书籍]
User - [借阅书籍]
User - [查询书籍]
User - [归还书籍]
[借阅书籍] <<include>> [查询书籍]
[归还书籍] <<extend>> [借阅书籍]
4.3 序列图
核心作用:按时间顺序展示对象间消息交互,重点是 “谁何时发送什么消息”
描述各系统或对象间的请求响应交互
用户登录时序图字符示例
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ UserClient │ │ AuthSystem │ │ Database │
└──────┬──────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
[UserClient] [AuthSystem] [Database]
│ │ │
│ 1. login() │ │
├─────────────────► │
│ │ 2. verify() │
│ ├────────────────►
│ │ │ 3. query()
│ │ ├──────────────►
│ │ │ 4. result
│ │ ◄────────────┘
│ │ 5. validate()
│ ◄────────────┘
│ 6. loginResult
◄─────────────────┘
│
▼
[UserClient]: 登录成功!
5、测试
4.1 测试覆盖
给出流程图问:语句覆盖、判定(分支)覆盖、条件覆盖、路径覆盖等至少需要多少测试用例、环路复杂度(McCabe)计算
覆盖强度对比:语句覆盖 < 判定覆盖 < 条件覆盖 < 路径覆盖,路径覆盖强度最高。
例题:代码片段
实际会是流程图,分析测试用例是一样的,而且看图更直观
int test(int a, int b, boolean c) {
int x = 0, y = 0;
if (a > 5 || b < 10) { // 判定1:条件a>5或b<10
x = x + 1; // 语句1
if (c) { // 判定2:条件c
y = y + 1; // 语句2
} else {
y = y - 1; // 语句3
}
} else {
x = x - 1; // 语句4
}
y = x + y; // 语句5
return x + y;
}
- 语句覆盖
- 覆盖所有可执行语句(不考虑条件真假)
- 用例 1:a=6, b=5, c=true
- 用例 2:a=6, b=5, c=false
- 用例 3:a=4, b=15, c=true
- 判定(分支)覆盖
- 覆盖所有判定的真假结果(判定 1 的真假、判定 2 的真假)
- 用例 1:a=6, b=5, c=true(判定 1 真、判定 2 真)
- 用例 2:a=4, b=15, c=false(判定 1 假、判定 2 假)
- 条件覆盖
- 覆盖所有条件的真假组合((a>5、b<10、c) 的真假)
- 用例 1:a=6, b=5, c=true(a>5 真、b<10 真、c 真)
- 用例 2:a=4, b=15, c=false(a>5 假、b<10 假、c 假)
- 路径覆盖
- 覆盖所有可能的执行路径(共 3 条路径)
- 用例 1:a=6,b=5,c=true(路径 1:判定 1 真→判定 2 真)
- 用例 2:a=6,b=5,c=false(路径 2:判定 1 真→判定 2 假)
- 用例 3:a=4,b=15,c=true(路径 3:判定 1 假)
环路复杂度计算
- 环路复杂度 V (G) 等于程序的线性独立路径数,例题中 V (G)=3,对应 3 条路径
4.2 软件产品的各阶段测试
- 单元测试-开发阶段-某个接口
- 集成测试-模块之间的交互功能性测试
- 系统测试-软件整体的测试,功能、性能、兼容、安全、可靠性测试
- 验收(确认)测试:验证软件是否满足用户需求,阿尔法测试(内部模拟用户测试)和贝塔测试(真实用户测试 公开版)
4.3 软考常见测试考点总结
- 各测试阶段的顺序与目标:单元测试→集成测试→系统测试→验收测试,前一阶段未通过不得进入下一阶段。
- 白盒与黑盒测试的方法区别:逻辑覆盖(白盒)vs 等价类 / 边界值(黑盒)是高频考点。
- 性能测试的细分类型:负载测试(预期负载)vs 压力测试(超负载)的定义易混淆。
- α 测试与 β 测试的场景:α 是内部用户,β 是外部真实用户。
- 回归测试的触发条件:代码修改后必须执行,避免 “涟漪效应”。
六、程序语言设计
1、编译器的编译流程
- 词法分析
- 任务:代码字符流->关键字词
- 算法:正规式+自动机
- 语法分析
- 任务:语法结构检查(如是否闭合,是否允许),构建语法树
- 算法:上下文无关文法(CFG)
- 语义分析
11. 任务:类型检查、作用域分析
12. 算法: - 生成中间代码(可选)
- 任务:如java的class文件
- 算法:后缀表达式(逆波兰式)-表达式优化
- 代码优化(可选)
- 生成目标机器码
2、编译流程中用到方法
- 正规式(正则表达式)
- 自动机
- 确定有限自动机(起点->终点:每一步都确定)
- 非确定有限自动机(起点->终点:多条路径到达)
- 考点:可识别的序列
- 根据图来判断是否可达
- 后缀表达式
- 考点:中缀表达式生成后缀表达式或识别字符序列
- 上下文无关文法(CFG)
- 考点:求符合给定文法的表达式
- 从顶构建树,根据是否为终结符及嵌套符判断
- 考点:求符合给定文法的表达式
例题
程序设计语言的大多数语法现象可以用CFG(上下文无关文法)表示。下面的CFG产生式集用于描述简单算术表达式,其中+、-、* 表示加、减、乘运算,id表示单个字母表示的变量,那么符合
该文法的表达式为()
P: E -> E+T|E-T|T
T -> T*F|F
F -> -F|id
A. a±b-c B. a*(b+c) C. a*-b+2 D. -a/b+c
解题
- E -> E+T|E-T|T(产生式 E可以产生E+T 或 E-T 或 T。可嵌套)
- 自顶向下,构建生成树,根节点E,叶子节点为id,根据答案查看是否合理
3、python语法考察
python 语言特点、语法必须掌握(常见数据结构、循环、异常处理、列表推导式)
python特点
- 面向对象、解释型语言
类的定义
- 属性 私有
__双下划线 “_保护” 单下划线 公有 - 函数 函数名 私有
__双下划线 “_保护” 单下划线 公有 静态函数及类函数加注解 - 构造函数
__init__双下划线
继承
- 单继承 class A (Parent)
- 多继承 class A (ParentA,ParentB)
- 自定义异常类 class A (Exception)
循环
左闭右开
- for range(1, 5) 从1到4 打印 1 2 3 4
- for range(1, 5, 2) 从1到4 步长为2 打印结果 1, 3
数据结构
- 不可变:
- String 字符串
- tuple 元祖
- (1, “a”, True)
- 类似于数组定义后不可改变,若是单元素必须以“,”结尾,不要求数据类型一致
- 可变:
- dict 字典(类似于map)
- list 列表
- [ 1 , " a " , T r u e ] [1, "a", True] [1,"a",True]
- 元素不要求一致类型)
- set 集合
- 1 , 2 , 3 , 4 {1,2,3,4} 1,2,3,4
- 无序,自动去重
参数传递
- 参数传递都是对象传递(地址传递),主要看传递的参数是可变类型还是不可变类型。
is 比较地址, == 比较值
异常处理
- try-except 捕获异常
- try-except-finally 捕获异常
- raise 手动跑出异常
列表推导式(必考)
- 核心语法:
[表达式 for 变量 in 可迭代对象 if 条件]。 - 后面的条件 if x % 2 == 0 偶数 if a%2 奇数
例如
表达式 [a*a for a in range(5) if a%2] 是一个列表推导式
- 遍历范围:
range(5)生成整数序列0, 1, 2, 3, 4。 - 条件过滤:
if a%2仅保留余数非零的数(即奇数)。- 当
a为偶数(如 0、2、4)时,a%2返回0(条件为假),被过滤。 - 当
a为奇数(如 1、3)时,a%2返回1(条件为真),保留。
- 当
- 元素处理:对保留的奇数
a,计算其平方a*a。
函数定义与参数传递
- 位置参数、默认参数、可变参数(
*args、**kwargs)
def func(a, b=2, *args, **kwargs):
print(a, b, args, kwargs)
func(1, 3, 4, 5, x=6) # 输出:1 3 (4, 5) {'x': 6}
七、网络基础
1、ISO七层网络模型
| 层次 | 主要作用 | 核心协议 | 涉及硬件 |
|---|---|---|---|
| 7. 应用层 | 为用户提供直接服务(如网页浏览、邮件、文件传输) | HTTP、FTP、SMTP、POP3、DNS、Telnet | 客户端 / 服务器软件 |
| 6. 表示层 | 数据格式转换(加密、压缩、解析) | SSL/TLS、JPEG、ASCII、XML/JSON | 无(软件层面处理) |
| 5. 会话层 | 建立、管理应用间会话(如断点续传、登录状态维护) | NetBIOS、RPC、ZIP(部分场景) | 无(软件层面处理) |
| 4. 传输层 | 端到端数据传输(可靠 TCP / 不可靠 UDP),通过端口号区分应用 | TCP、UDP、SPX(Novell) | 无(协议层面) |
| 3. 网络层 | 路由选择、IP 寻址、数据包分片重组 | IP、ICMP、ARP、RIP、OSPF、BGP | 路由器、三层交换机 |
| 2. 数据链路层 | 组帧、MAC 地址寻址、差错控制(CRC 校验) | Ethernet、PPP、HDLC、VLAN | 交换机、网桥、网卡(MAC 层) |
| 1. 物理层 | 传输比特流(0/1 电信号),定义物理接口标准(如电压、线缆类型) | RJ45、光纤、双绞线、IEEE 802.3 | 网线、集线器、中继器、光纤 |
网络通讯
串联七层网络模型及相应网络知识
主机 A(跨网段)→主机 B 的消息传输全流程
消息封装阶段(主机 A)
- 应用层:
- 生成消息(如 HTTP 请求),按应用协议(如 HTTP)格式化数据 (如微信消息用 TCP/IP,DNS 查询用 UDP)**。
- 传输层:
- 选择协议(TCP/UDP),添加源端口(如 A 的随机端口)和目标端口(如 B 的 HTTP 端口 80)
- 网络层:
- 封装 IP 头部,源 IP(A 的 IP)、目标 IP(通过 DNS 解析 B 的域名到 IP)
- 数据链路层:
- 发现 A 与 BIP 不在同一网段(通过子网掩码判断),需发往网关(路由器 LAN 口);
- 用 ARP 协议获取网关的 MAC 地址(若缓存无,A 发送 ARP 广播 “谁是网关 IP?”,网关回复 MAC)
- 封装帧头:源 MAC(A 的 MAC)、目标 MAC(网关 MAC)
- 物理层:将帧转为比特流(电信号)通过网线发送
网络设备转发阶段
- 交换机(连接主机 A):
- 接收 A 的帧,根据目标 MAC(网关 MAC)查找 MAC 地址表,若有则转发到路由器端口;若无则广播学习(首次通信时)
- 路由器:
- 接收帧,剥离数据链路层头部,查看 IP 分组的目标 IP(B 的 IP);
- 查路由表:若 B 在目标网段,确定下一跳为目标网段的交换机(或直接主机);
- 重新封装数据链路层:源 MAC(路由器 WAN 口 MAC)、目标 MAC(目标网段交换机的 MAC,需通过 ARP 获取)
- 目标网段交换机 B:
- 接收路由器发来的帧,目标 MAC 为自己,剥离帧头后查 IP 分组,发现目标 IP 为 B;
- 用 ARP 解析 B 的 IP→MAC(若缓存无,交换机广播 ARP 请求,B 回复单播 MAC)
- 记录 B 的 MAC→端口映射,后续直接单播转发
消息解封装阶段(主机 B)
- 物理层→应用层:逐层解封装(与发送流程反向),传输层根据端口号将数据交给对应应用(如 HTTP 交给浏览器),最终获取应用层消息。
2、常见协议与端口号
端口号记忆技巧(软考应试)
除了SNMP 其他都要记
-
邮件协议端口:
- SMTP(25)、POP3(110)、IMAP(143)
联想:25(发送)→ 110(接收下载)→ 143(接收保留)。
- SMTP(25)、POP3(110)、IMAP(143)
-
加密协议端口:
- HTTPS(443)= HTTP(80)+ SSL(安全)
- SMTPS(465)= SMTP(25)+ SSL(443-25=418 → 418+47=465)
- IMAPS(993)= IMAP(143)+ SSL(443+550=993)。
-
基础服务端口:
- DNS(53):联想 “53 度白酒”(域名解析是网络 “酒水”)。
- DHCP(67/68):67(服务器)→ 68(客户端),顺序递增。
- SNMP(161/162):161(查询)→ 162(陷阱),陷阱比查询多 1。
-
20/21/22/23/25 规律:
- 20/21:FTP(数据 / 控制)
- 22:SSH(安全远程)
- 23:Telnet(非安全远程)
- 25:SMTP(邮件发送)
口诀:“20 数据 21 控,22 安全 23 明,25 邮件发不停”。
3、IPV4与IPV6
IPV4和IPV6的地址
- IPV4:32位
- 采用 点分十进制(Dotted Decimal),将 32 位二进制数分为 4 个 8 位组,每组转换为十进制(0-255),用
.分隔
192.168.1.1 对应二进制为11000000.10101000.00000001.00000001
- 采用 点分十进制(Dotted Decimal),将 32 位二进制数分为 4 个 8 位组,每组转换为十进制(0-255),用
- IPV6:128位
- 采用 冒号十六进制(Colon Hexadecimal),将 128 位二进制数分为 8 个 16 位组,每组转换为十六进制(0-FFFF),用
:分隔
2001:0db8:85a3:0000:0000:8a2e:0370:7334
- 采用 冒号十六进制(Colon Hexadecimal),将 128 位二进制数分为 8 个 16 位组,每组转换为十六进制(0-FFFF),用
考点
- 可用地址:
-
IPv4:可用地址数 = ( 2 主机位数 − 2 ) (2^{\text{主机位数}} - 2) (2主机位数−2)(必减 2)。
- 必须排除网络地址和广播地址,两者均为 IPv4 的保留地址,不可分配给主机。
- 网络地址
- 用于指明 “某一网络”,而非网络中的具体主机(由网络位和全 0 的主机位组成)
- 案例 1:子网
192.168.1.0/24(C 类,掩码255.255.255.0) - 网络地址:
192.168.1.0(主机位00000000全 0)
- 广播地址
- 用于向子网内所有主机发送广播消息(由网络位和全 1 的主机位组成)
- 案例 1:子网
192.168.1.0/24 - 广播地址:
192.168.1.255(主机位11111111全 1)
-
IPv6:可用地址数 = ( 2 主机位数 ) (2^{\text{主机位数}}) (2主机位数)(不减 2)
-
口诀:“IPv4 减广播,IPv6 用组播;空间大到爆,不减地址妙”。
-
- 默认IP
- 开机后DHCP服务器未响应 那默认获取的主机IP地址属于网络:169.254.0.0/16(2 x 2 8 2^8 28 也就是IP的后两位地址)
陷阱题示例:
- 问:IPv6 的
2001:db8::/64子网可用地址数是多少? 答: ( 2 64 ) (2^{64}) (264)(直接计算,无需减 2)。 - 问:IPv4 的
10.0.0.0/8可用地址数是多少? 答: ( 2 24 − 2 = 16 , 777 , 214 ) (2^{24} - 2 = 16,777,214) (224−2=16,777,214)(必须减 2)。
4、windows操作命令
- ping: 测试网络连通性(发送 ICMP Echo 请求)
- ipconfig: 显示网络配置信息(IP、子网掩码、网关)
- netstat:获取某个网络开放端口对应的应用程序信息
- traceroute:利用ICMP协议追踪并返回本机访问目标计算机时所经过的所有路由
- nslookup:查询DNS记录 查看域名解析是否正常
5、域名
域名分级
从右到左、层级递减
域名采用 分层树状结构,由多个用 “.” 分隔的部分组成,从右到左依次为 顶级域名(TLD)、二级域名(SLD)、三级域名(子域名) 等,层级逐渐细化
示例:www.blog.example.com
- 顶级域名:
com - 二级域名:
example - 三级域名(子域名):
blog - 主机名(子域名):
www
面向全球通用,如 .com(商业机构)、.org(非营利组织)、.net(网络服务)、.edu(教育机构,仅限部分国家)、.gov(政府机构,仅限美国)等
八、信息安全与多媒体
1、防火墙
| 类型 | 工作层次 | 过滤维度 | 典型场景 |
|---|---|---|---|
| 包过滤防火墙 | 网络层 / 传输层 | IP / 端口 / 协议类型 | 基础网络隔离 |
| 状态检测防火墙 | 网络层 / 传输层 | IP / 端口 / 连接状态 | 企业网络边界防护 |
| 应用层防火墙 | 应用层 | 应用协议内容、用户行为 | 敏感数据防护、Web 安全 |
2、网络攻击
- 被动攻击的典型例子:窃听、流量分析。
- 主动攻击的典型例子:篡改、伪造(欺骗)、DoS/DDoS、中间人攻击(部分场景属于主动)。
- 防护重点:被动攻击需通过加密(如 SSL/TLS)防止信息泄露;主动攻击需通过认证、防火墙、入侵检测(IDS)等技术防御。
3、病毒分类与核心特点
** 病毒分类及软考典型案例**
| 病毒类型 | 感染对象 / 传播方式 | 软考常考特点 | 典型例题 |
|---|---|---|---|
| 文件型病毒 | 感染可执行文件(.exe/.com) | 驻留内存、修改文件内容、覆盖型 / 伴随型变种 | 例:CIH 病毒感染 PE 文件,破坏 BIOS 硬件9 |
| 引导扇区病毒 | 感染磁盘引导区(如 U 盘、硬盘) | 启动时加载到内存,隐蔽性强 | 例:Disk Killer 病毒格式化硬盘8 |
| 宏病毒 | 感染 Office 文档(Word/Excel 宏) | 跨平台传播、依赖文档执行 | 例:Macro.Melissa 通过邮件附件传播1 |
| 蠕虫病毒 | 利用网络漏洞自动传播(无需宿主文件) | 消耗带宽、拒绝服务攻击(DoS) | 例:WannaCry 利用永恒之蓝漏洞加密文件2 |
| 木马病毒 | 伪装成合法程序,窃取用户信息 | 远程控制、隐蔽性强 | 例:灰鸽子木马通过社交工程传播2 |
| 勒索病毒 | 加密用户文件并索要赎金 | 高强度加密、利用漏洞传播 | 例:Petya 病毒通过 SMB 协议漏洞感染2 |
病毒核心特点(必背)
- 传染性:通过自我复制感染其他程序或介质(如 U 盘、网络)45。
- 隐蔽性:隐藏在正常文件中,难以被用户察觉(如宏病毒嵌入文档)48。
- 潜伏性:长期潜伏,等待特定条件(如日期、用户操作)触发45。
- 破坏性:删除文件、格式化硬盘、窃取数据(如 CIH 破坏 BIOS 硬件)911。
- 可触发性:通过时间、文件类型等条件激活恶意行为45。
- 寄生性:依赖宿主程序生存,无法独立运行510。
3、看门狗
基本概念
- 本质:一种硬件或软件定时器,用于监测系统运行状态,防止程序跑飞或陷入死循环。
- 工作机制:
- 系统正常运行时,需定期向看门狗发送 “喂狗” 信号(清零计数器)。
- 若系统因故障(如程序崩溃、硬件异常)未能及时喂狗,看门狗超时后触发复位信号,重启系统。
软考高频考点与避坑指南
-
看门狗超时时间设置:
- 需大于系统正常操作周期,但小于系统可承受的最大故障时间。
- 例:若系统正常处理周期为 200ms,看门狗超时可设为 500ms。
-
喂狗策略:
- 应分散在关键代码段,避免集中在一处(如主循环首尾),确保各模块正常运行。
-
禁用看门狗的场景:
- 调试阶段(避免频繁复位影响调试),但需在发布版本中重新启用。
-
多级看门狗设计:
- 硬件看门狗(秒级)+ 软件看门狗(毫秒级),实现分层保护。
-
真题示例:
- 问:看门狗的主要作用是什么?
- 答:检测系统故障并自动复位,提高系统可靠性。
- 问:硬件看门狗与软件看门狗的核心区别?
- 答:硬件看门狗独立于主系统,可靠性更高;软件看门狗依赖主程序。
六、记忆口诀
- 看门狗功能:“定期喂狗防死机,超时复位保安全”。
- 配置要点:“超时设置要合理,喂狗分散关键区”。
4、信息加密签名
- 对称加密(密钥一致):RC2 RC4 AES SM4
- 非对称加密(公私钥):RSA
- 签名:Hash(不安全) SHA-256(替代Hash) RSA公钥签名
证书
X.509数字证书使用的标准加密算法是RSA
SM2国密数字证书使用的标准是我国研发的ECC(比RSA加密度高且加计算速度快)
对称加密
- AES/DES
- 在安全性、性能和实用性上全面超越 DES,是现代加密的唯一选择
- SM4
- SM4相较于AES国际兼容性安全性略低,但在国内 金融、政务、通信行业必须使用
国密体系
政务、金融需使用
| 算法 | 类型 | 安全强度 | 应用场景 |
|---|---|---|---|
| SM2 | 非对称 | 等效 RSA-2048 | 数字签名、密钥交换 |
| SM3 | 哈希 | 抗碰撞(2^{128}),安全性与 SHA-256相当 | 数据完整性校验 |
| SM4 | 对称 | 等效 AES-128 | 数据加密、批量存储 |
| SM9 | 标识加密 | 等效 RSA-3072 | 无证书身份认证 |
| ZUC | 流加密 | 128/256 位密钥 | 移动通信、实时数据传输 |
5、多媒体
- 图像计算
- 分辨率x像素的位深/8 (转成字节Byte)
- 音频计算
- 需要注意双声道x2
- 音频采样
- 音频的采样是原声音最高音频的两倍
- 视频计算
- 每一帧图像容量x帧数+音频容量
九、设计模式
除了几个冷门的 状态、迭代器、访问者、中介者、解释器,其他的都要熟悉,重点:工厂、适配器、策略、责任链、观察者、模板方法。
1、创建型对象模型
| 模式 | 核心思想 | 应用场景 | 优点 |
|---|---|---|---|
| 单例 | 全局唯一实例 | 订单管理器、配置中心 | 避免重复创建,节省资源 |
| 工厂 | 封装对象创建 | 菜品创建、支付方式选择 | 解耦客户端与具体实现 |
| 抽象工厂 | 产品族创建 | 套餐组合(主食 + 饮料 + 甜点) | 保证产品兼容性 |
| 建造者 | 分步构建复杂对象 | 定制化订单(多配料、多选项) | 避免构造函数参数过多 |
| 原型 | 复制现有实例 | 套餐克隆、促销活动模板复制 | 提高对象创建效率 |
结构型对象模型
| 模式 | 核心思想 | 应用场景 | 优点 |
|---|---|---|---|
| 代理 | 控制访问 | 订单权限控制、远程服务代理 | 增强功能,保护目标对象 |
| 装饰器 | 动态扩展功能 | 菜品加料、订单附加服务 | 灵活扩展,避免继承爆炸 |
| 适配器 | 接口转换 | 第三方支付接口适配 | 复用现有类,提高兼容性 |
| 桥接 | 分离抽象与实现 | 菜品与烹饪方式分离 | 支持多角度变化 |
| 组合 | 树形结构管理 | 菜单层级管理、套餐组合 | 简化客户端操作 |
| 外观 | 统一接口 | 点餐流程整合、复杂业务封装 | 简化调用,降低依赖 |
| 享元 | 共享对象 | 菜品规格缓存、餐厅座位管理 | 减少内存占用 |
行为型对象模型
| 模式 | 核心思想 | 应用场景 | 优点 |
|---|---|---|---|
| 策略 | 算法替换 | 支付方式选择、优惠计算 | 符合开闭原则,灵活切换 |
| 观察者 | 一对多依赖 | 订单状态通知、库存预警 | 松耦合,支持广播通信 |
| 责任链 | 请求传递 | 订单审核流程、优惠折扣计算 | 动态组合,解耦发送者与接收者 |
| 模板方法 | 定义骨架 | 订单处理流程、烹饪流程 | 提取公共代码,提高复用 |
| 状态 | 状态行为封装 | 订单状态管理、餐厅座位状态 | 避免大量条件语句 |
| 命令 | 请求封装 | 点餐命令队列、撤销操作 | 支持撤销、队列处理 |
| 备忘录 | 状态保存 | 订单历史记录、配置备份 | 保持封装性,支持恢复 |
| 迭代器 | 遍历抽象 | 菜单遍历、订单列表浏览 | 统一遍历接口 |
| 访问者 | 操作分离 | 订单报表生成、菜品价格计算 | 易于添加新操作 |
| 中介者 | 集中交互 | 餐厅调度系统、多部门协作 | 降低耦合,简化关系 |
| 解释器 | 语法解释 | 自定义优惠规则解析、简单脚本执行 | 实现简单语言解释 |
十、排序算法
重点:快速排序、归并排序、堆排序、希尔排序
| 排序分类 | 排序算法 | 时间复杂度(平均) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 | 适用场景 |
|---|---|---|---|---|---|---|
| 插入排序 | 直接插入排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 数据量小、基本有序 |
| 插入排序 | 希尔排序 | O ( n 1.3 ) O(n^{1.3}) O(n1.3) - O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 不稳定 | 数据量较大 |
| 交换排序 | 冒泡排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 数据量小 |
| 交换排序 | 快速排序 | O ( n log n ) O(n \log n) O(nlogn) | O ( n 2 ) O(n^2) O(n2) | O ( log n ) O(\log n) O(logn) | 不稳定 | 数据量大、随机分布 |
| 选择排序 | 简单选择排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 不稳定 | 数据量小 |
| 选择排序 | 堆排序 | O ( n log n ) O(n \log n) O(nlogn) | O ( n log n ) O(n \log n) O(nlogn) | O ( 1 ) O(1) O(1) | 不稳定 | 数据量大 |
| 归并排序 | 归并排序 | O ( n log n ) O(n \log n) O(nlogn) | O ( n log n ) O(n \log n) O(nlogn) | O ( n ) O(n) O(n) | 稳定 | 数据量大、要求稳定 |
| 基数排序 | 基数排序 | O ( d ( n + b ) ) O(d(n + b)) O(d(n+b))(d为位数,b为基数) | O ( d ( n + b ) ) O(d(n + b)) O(d(n+b)) | O ( n + b ) O(n + b) O(n+b) | 稳定 | 数据范围不大,数字位数有一定规律 |
考察重点
- **时间复杂度
- 能构建树的(或递归的)都是O(nlogn)
- 特殊的快速排序,若原序列基本有序时间复杂度为O( n 2 n^2 n2)
- 其他最坏的都是O( n 2 n^2 n2)
- 基数排序特殊
- 能构建树的(或递归的)都是O(nlogn)
- 空间复杂度
- 快速排序(涉及递归操作 O(logn))
- 归并排序(递归+合并结果 O(n))
- 其他都是O(1)
- 基数排序特殊
- 稳定性
- 是指经过多次排序后元素的位置不变
- 只有4个稳定(插入、冒泡、归并、基数)
- 具体排序操作
- 给出一列乱序集合,经过某个算法一次排序操作后的集合序列
- 堆排序构建大小顶堆
八大排序算法的手动推导示例与对比
以下用数组 [5, 3, 8, 4, 6] 作为示例,展示各排序算法的核心步骤和每趟排序后的结果。为便于手动推算,简化了部分过程,重点展示关键变化。
1. 简单选择排序(Selection Sort)
核心思想:每趟从未排序部分选择最小元素,与未排序部分的第一个元素交换。
初始:[5, 3, 8, 4, 6]
第1趟:[3, 5, 8, 4, 6] // 选择最小值3,与5交换
第2趟:[3, 4, 8, 5, 6] // 选择最小值4,与5交换
第3趟:[3, 4, 5, 8, 6] // 选择最小值5,与8交换
第4趟:[3, 4, 5, 6, 8] // 选择最小值6,与8交换
最终:[3, 4, 5, 6, 8]
2. 插入排序(Insertion Sort)
核心思想:将未排序元素逐个插入已排序序列的正确位置。
初始:[5, 3, 8, 4, 6]
第1趟:[3, 5, 8, 4, 6] // 插入3到[5]的正确位置
第2趟:[3, 5, 8, 4, 6] // 插入8到[3, 5]的正确位置(已在正确位置)
第3趟:[3, 4, 5, 8, 6] // 插入4到[3, 5, 8]的正确位置
第4趟:[3, 4, 5, 6, 8] // 插入6到[3, 4, 5, 8]的正确位置
最终:[3, 4, 5, 6, 8]
3. 希尔排序(Shell Sort)
核心思想:按间隔分组进行插入排序,逐步缩小间隔直至为 1。
初始:[5, 3, 8, 4, 6]
间隔2排序:[5, 3, 6, 4, 8] // 分组:[5,8,6]→[5,6,8],[3,4]→[3,4]
间隔1排序:[3, 4, 5, 6, 8] // 直接插入排序(同插入排序的最终结果)
最终:[3, 4, 5, 6, 8]
4. 冒泡排序(Bubble Sort)
核心思想:相邻元素比较,较大元素逐步 “冒泡” 到右侧。
初始:[5, 3, 8, 4, 6]
第1趟:[3, 5, 4, 6, 8] // 比较5-3→交换,5-8→不交换,8-4→交换,8-6→交换
第2趟:[3, 4, 5, 6, 8] // 比较3-5→不交换,5-4→交换,5-6→不交换
第3趟:[3, 4, 5, 6, 8] // 无交换,已完成排序
最终:[3, 4, 5, 6, 8]
5. 快速排序(Quick Sort)
核心思想:选择基准值,将数组分为两部分,小于基准的放左边,大于的放右边,递归排序。
初始:[5, 3, 8, 4, 6]
第1趟:[3, 4, 5, 8, 6] // 基准5,左部分[3,4],右部分[8,6]
递归左部分:[3, 4] → 已排序
递归右部分:[8, 6] → [6, 8]
最终:[3, 4, 5, 6, 8]
6. 归并排序(Merge Sort)
核心思想:分治法,将数组分成两半,分别排序后合并。
初始:[5, 3, 8, 4, 6]
拆分:[5, 3] 和 [8, 4, 6]
再拆分:[5]、[3]、[8]、[4, 6]
排序合并:[3, 5]、[8]、[4, 6] → [3, 5]、[4, 6, 8] → [3, 4, 5, 6, 8]
最终:[3, 4, 5, 6, 8]
7. 堆排序(Heap Sort)
核心思想:将数组构建为最大堆,反复提取最大值并调整堆。
初始:[5, 3, 8, 4, 6]
构建最大堆:[8, 6, 5, 4, 3]
第1趟:[6, 4, 5, 3, 8] // 交换8和3,调整堆
第2趟:[5, 4, 3, 6, 8] // 交换6和3,调整堆
第3趟:[4, 3, 5, 6, 8] // 交换5和3,调整堆
第4趟:[3, 4, 5, 6, 8] // 交换4和3,调整堆
最终:[3, 4, 5, 6, 8]
8. 基数排序(Radix Sort)
核心思想:按位排序,从低位到高位依次处理每一位。
初始:[5, 3, 8, 4, 6]
按个位排序:[3, 4, 5, 6, 8] // 个位分别为5,3,8,4,6 → 排序后为3,4,5,6,8
按十位排序:[3, 4, 5, 6, 8] // 十位均为0,顺序不变
最终:[3, 4, 5, 6, 8]
十一、法律法规
核心法律特点(必背)
- 著作权:自动取得,保护表达而非思想,软件需登记作为维权证据。
- 署名权、修改权、保护作品完整权(永久)
- 自然人:终生 + 死后 50 年;法人:首次发表后 50 年
- 专利权:需申请,保护技术方案,要求新颖性、创造性、实用性。
- 涉及硬件控制或数据处理(如算法与硬件结合)
- 发明 20 年,实用新型和外观设计 10 年(自申请日起算)
- 商标权:需注册,保护标识唯一性,有效期 10 年可续展。
- 商业秘密:未公开且采取保密措施,保护期限不确定
十二、计算题总结
1、海明码校验位计算
记住公式计算即可( 2 k − 1 > = n + k 2^k-1>=n+k 2k−1>=n+k)(k是校验位,n是数据位)
例: 设信息位是8位,用海明码来发现并纠正1位出错的情况,则校验位的位数至少为几?
解:直接代入公式,求得k=4
2、总线带宽计算
核心公式 ( 总线带宽 = 总线宽度 × 时钟频率 传输周期 ) (总线带宽 = \frac{总线宽度 \times 时钟频率}{传输周期}) (总线带宽=传输周期总线宽度×时钟频率)
注意: 单位转换
例 (2022 年下半年) 某系统总线的宽度为 64 位,工作频率为 200MHz,每 4 个时钟周期传输一次数据,则该总线的带宽为多少?
步骤 1:确定参数
- 总线宽度 = 64 位 = 8Byte。
- 时钟频率 = 200MHz = (200 \times 10^6) Hz。
- 传输周期 = 4 个时钟周期。
步骤 2:代入公式 ( 总线带宽 = 总线宽度 × 时钟频率 传输周期 = 8 × 200 × 1 0 6 4 B/s ) ( = 400 × 1 0 6 B/s = 400 MB/s ) (总线带宽 = \frac{总线宽度 \times 时钟频率}{传输周期} = \frac{8 \times 200 \times 10^6}{4} \text{ B/s})(= 400 \times 10^6 \text{ B/s} = 400 \text{ MB/s}) (总线带宽=传输周期总线宽度×时钟频率=48×200×106 B/s)(=400×106 B/s=400 MB/s)
答案:该总线的带宽为 400 MB/s。
3、文件系统多级索引地址计算
例题
某文件系统采用案引节点管理,其磁盘索引块和磁盘数据块大小均为 1kB 字节且每个文件索引节
点有8个地址项iaddr[0] ~ iaddr[7],每个地址项大小为4字节,其中iaddr[0] ~ iaddr[4]采用直接地址索引,iaddr[5]和 iaddr[6]采用一级间接地址索引,iaddr[7]采用二级间接地址索引。若用户要访问文件userA中逻辑块号位4和5的信息,则系统应分别采用什么访问?该文件系统可表示的单个文件最大长度为()KB?
解题
问1:直接地址访问和一级间接地址索引
问2:
明确:索引存数据块,数据块存地址
- 提取信息,磁盘索引块和磁盘数据块大小均为 1kB 字节,索引节点有8个地址项,每个地址项大小为4字节
- 索引块的数据块地址数:1KB/4B = 256地址
- 一个文件(iaddr[0] ~ iaddr[7])
- 0-4 直接地址: 5 × 1 K B = 5 K B 5×1KB=5KB 5×1KB=5KB
- 5-6 一级索引: 2 × 256 × 1 K B = 512 K B 2×256×1KB=512KB 2×256×1KB=512KB
- 7 二级索引: 1 × 256 × 256 × 1 K B = 65536 K B 1×256×256×1KB=65536KB 1×256×256×1KB=65536KB
- 汇总结果为: 5 K B + 512 K B + 65536 K B = 66053 K B 5KB+512KB+65536KB=66053KB 5KB+512KB+65536KB=66053KB
4、逻辑地址转物理地址计算
例题
假设计算机系统的页面大小为4K,进程P的页面变换表如下表所示。若P要访问的逻辑地址为十六进制3C20H,那么该逻辑地址经变换后,其物理地址应为()
| 页号 | 物理块号 |
|---|---|
| 0 | 2 |
| 1 | 3 |
| 2 | 5 |
| 3 | 6 |
解题
- 地址位数:逻辑地址3C20H为 16 位二进制,页大小为 4KB(2^12)12位,则页内偏移占 12 位,页号占 4位即十六进制的3
- 因为逻辑地址与物理地址偏移量相同,所以只需改变页号为块号即可
- 获得页号为3对应的块号6,替换页号,物理地址为6C20H
5、磁盘存储时间计算
磁盘存取时间公式:存取时间=寻道时间+旋转延迟+数据传输时间
例题
在磁盘上存储数据的列方式会影响IO服务的总时间。假没每个磁道被划分成10个物理块,每个物理块存放1个逻辑记录。逻辑记录R1,R2.…R10存放在同一个磁道上,记录的排列顺序为1-10顺序排列;
假定磁盘的旋转速度为 10ms/周,磁头当前处在 R1的开始处。若系统顺序处理这些记录,使用单
缓冲区,每个记录处理时间为 2ms,则处理这10个记录的最长时间为(),若对存储数据的排列顺序
进行优化,处理10个记录的最少时间为()
解题
前提:
- 磁盘旋转到R1的时间为10ms/10=1ms,处理时间为2ms,总耗时3ms,等R1处理完,磁头已要过R3处
- 按顺序处理下一个R2需要再等待10-3+1=8ms,
- 依次类推,处理完所有则需要 (3+8)x10-8=102ms
- 顺序优化后,不需要按指定序列处理,则无需考虑等待时间,处理完所有则需要 3x10=30ms
6、位示图与磁盘使用情况计算
例题
某计算机系统的字长为128 位,磁盘的容量为 2048G,物理块的大小为 8MB。假设文件管理系统采用位示图法记录计算机系统磁盘的使用情况,那么位示图的大小需要多少个字?
解题
- 明确位示图表示磁盘使用情况(0-未使用,1-已使用)
- 计算需要表示的物理块:2048G/8MB = 256 × 2 10 256 \times 2^{10} 256×210Byte
- 计算需要多少字: 256 × 2 10 ÷ 128 256 \times 2^{10}\div128 256×210÷128=2048
7、装包问题计算
例题
考虑下述背包问题的实例。有5件物品,背包容量为100,每件物品的价值和重量如下所示,并已经按照物品的单位重量价值从大到小排好序。根据物品单位重量价值大优先的策略装入背包中,则采用了()设计策略。考虑 0-1背包问题(每件物品或者全部装入背包或者不装入背包)和部分背包问题(物品可以部分装入背包),求解该实例得到的最大价值分别为()
| 物品编号 | 价值 | 重量 |
|---|---|---|
| 1 | 50 | 5 |
| 2 | 200 | 25 |
| 3 | 180 | 30 |
| 4 | 225 | 45 |
| 5 | 200 | 50 |
解题
问1:贪心
问2:完全背包和部分背包问题
- 0-1装包(动态规划算法)
- 根据状态转移方程
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]),列出二维数组或表格进行手动推演 - 尝试组合物品 2(25)、3(30)、4(45):
- 总重量:25+30+45=100,刚满容量。
- 总价值:200+180+225=605。
- 其他组合(如选物品 1+2+3+4)总重量超容,或价值更低
- 根据状态转移方程
- 部分装包(贪心算法)
- 目标:按单位价值从高到低选择,可分割剩余物品。
- 选物品 1(5/50):全选,重量 5,价值 50,剩余容量 95。
- 选物品 2(25/200):全选,重量 25,价值 200,剩余容量 70。
- 选物品 3(30/180):全选,重量 30,价值 180,剩余容量 40。
- 选物品 4(45/225):选 40 重量,价值 ( 225 × 40 45 = 200 ) (225 \times \frac{40}{45} = 200) (225×4540=200),剩余容量 0。
- 总价值:50+200+180+200=630
0-1装包(动态规划算法)推演图
| 物品\重量 | 0 | 5 | 25 | 30 | 45 | 50 | 100 |
|---|---|---|---|---|---|---|---|
| 1(5/50) | 0 | 50 | 50 | 50 | 50 | 50 | 50 |
| 2(25/200) | 0 | 50 | 200 | 250 | 250 | 250 | 250 |
| 3(30/180) | 0 | 50 | 200 | 250 | 250 | 250 | 430 |
| 4(45/225) | 0 | 50 | 200 | 250 | 250 | 275 | 605 |
| 5(50/200) | 0 | 50 | 200 | 250 | 250 | 275 | 605 |
8、哈夫曼字符串编码
例: 已知一个文件中出现的各字符及其对应的频率如下表所示,采用Huffman编码,则该文件中字符a和c的码长分别为(),若采用Huffman编码,则编码序列110001001101对应的字符应为()
| 字符 | a | b | c | d | e | f |
|---|---|---|---|---|---|---|
| 频率(%) | 45 | 13 | 12 | 16 | 9 | 5 |
解题
huffman 编码根据使用频率排序,每次选取最小频率构建树,树节点按左0右1编码即为huffman编码
- 按照使用频率升序排序字符
- 选取频率最低的字符构建树,删除原序列中被选取的节点,两者的值(父节点)再放入序列中升序排序
- 重复动作2,一直到序列中节点用完
- 最终构成的树要按左小右大的顺序(同一层级)
- 标注边:左0右1
- 将每个字符的huffman编码写出
- a = 0
- b=101
- c=100
- d=111
- e=1101
- f=1100
- 问1:1,3
- 问2:face
简答题
基本与真题中一致,但顺序会打乱,刷题即可
一、数据流图
二、数据关系
三、UML
四、C语言算法
五、java设计模式/C++设计模式(选一)
总结
- 软考知识点广而杂,多数以记忆为主,建立知识点间的协作联系可帮助加深理解和记忆,如学完一个模块可以让AI举例一个应用场景串联起这个模块的知识点。
- 注重学习主次,明确学习目标是及格达标而不是考高分,故在有效时间内,重点学习和复习分值大的模块如数据结构算法和设计模式以及面向对象,对于部分晦涩难懂的知识点可直接放弃或考前突击记忆,零基础建议先补充java基础语法。
- 学习和复习时建议结合豆包或deepseek帮串联零散知识点,自己在学习和理解后可以进行反向输出归纳总结让AI评价补充。
- 应试技巧,选择题先把概念题全部做完,遇到计算题直接标记跳过到最后做,不要卡在一题太长时间,30分的容错足够了;简答题基本与真题类型基本一致,限时刷题即可。(现在都是机考,选择题75分,简答题75分,总时长240分钟,选择题最长120分钟,考完提交立刻进行简答题)

1854


被折叠的 条评论
为什么被折叠?



