当前位置: 首页 > news >正文

PTA 作业集 4~6总结博客_NCHU

PTA 作业集 4~6 总结性 Blog

前言

本阶段的三次 PTA 作业围绕“数字逻辑电路仿真”这一主题逐步展开。作业集 4 主要完成基础逻辑门电路的解析、连接和输出计算,作业集 5 在此基础上扩展到三态门、译码器、数据选择器、数据分配器等复杂器件,作业集 6 继续引入子电路定义与复用,使题目从单层电路模拟推进到具有模块封装特征的电路系统。三次作业的变化不是简单增加若干输入格式,而是不断提高对抽象能力、对象协作能力、边界处理能力和程序可维护性的要求。

从知识点看,三次作业覆盖了正则表达式解析、集合管理、面向对象继承、多态调用、输入输出格式控制、图状连接关系建模、迭代式电路求值、非法连接检测、模块化封装等内容。作业集 4 的核心是把“输入信号、输入引脚、输出引脚、逻辑门”这些概念建模出来,并能按连接关系计算逻辑门输出。作业集 5 的重点转向多输入、多输出器件的统一表达,要求程序能够识别某个端口究竟是信号源还是信号接收端。作业集 6 则进一步要求把一组内部元件封装为子电路,并允许主电路通过子电路端口完成连接,这对数据结构和流程控制提出了更高要求。

从题量与难度看,三次作业都属于综合性程序设计题,题目数量并不多,但单题规模较大,调试成本较高。根据本地源代码统计,PTA4 的 Main.java 约 524 行,包含 15 个类或接口;PTA5 的 Main.java 约 951 行,包含 20 个类或接口;PTA6 的 Main.java 约 1348 行,包含 24 个类或接口。代码规模和类数量持续增长,说明问题领域在不断扩大。难度也从“能正确计算单层逻辑门”逐步变为“能稳定表示复杂器件和子电路”。这三次作业给我的最大感受是,面向对象程序设计不能只停留在会写类的层面,更重要的是能否让每个类承担清晰、稳定、可扩展的职责。

三次作业整体规模如下:

作业集 源码行数 类/接口数量 核心新增内容 难度判断
PTA4 524 15 基础逻辑门、信号源、输入输出引脚、连接构建 中等
PTA5 951 20 三态门、译码器、选择器、分配器、多输出端口 较难
PTA6 1348 24 子电路、命名端口、主电路输出端口、错误检测

一、设计与分析

1. PTA4:基础逻辑门电路仿真

PTA4 是三次作业的起点,程序的目标是根据输入信号和连接描述,建立基础逻辑门之间的连接关系,并输出各逻辑门的计算结果。代码中已经形成了较清晰的基本模型:SignalSource 表示所有可以输出信号的对象,StartSignal 表示外部输入信号,InputPinOutputPin 分别表示输入端和输出端,LogicGate 是所有逻辑门的抽象父类,AndGateOrGateNotGateXorGateXnorGate 负责具体逻辑计算,GateController 管理所有信号和门对象,GateCreator 负责根据文本标识创建或复用逻辑门,GateConnectBuilder 负责建立端口连接,CircuitOutput 负责电路求值和输出排序。

PTA4 的代码规模图如下:

代码规模

PTA4 的类图如下:

PTA4类图

PTA4 的类复杂度图如下:

类复杂度

从类图可以看出,PTA4 已经尝试把电路中的“元件”和“连接”拆分成不同对象。LogicGate 抽象出了逻辑门的共同属性,包括编号、类型、输入引脚、输出引脚和无效状态。具体门类只需关心自身的计算规则。这样的继承结构比较符合题目特征,因为与门、或门、非门、异或门、同或门在外部连接方式上具有相似性,差异主要体现在计算公式上。

PTA4 的整体流程可以概括为:

flowchart TDA["读取全部输入行"] --> B["识别 INPUT 行并登记起始信号"]B --> C["解析连接行"]C --> D["根据文本标识创建或查找逻辑门"]D --> E["建立输出端到输入端的连接"]E --> F["多轮遍历逻辑门并计算输出"]F --> G["按类型和编号输出结果"]

这一版设计的优点是主方法非常简洁,程序入口只负责启动输入流程。电路中的基本概念也有对应的类承载,没有把所有逻辑堆在 main 中。CircuitOutput 中采用多轮遍历的方式求值,可以在一定程度上处理前后门依赖关系,不要求输入连接完全按照拓扑顺序排列。

但是 PTA4 也暴露出几个问题。首先,端口模型还不够统一。基础门只有一个输出端,所以 LogicGate 中直接保留单个 OutputPin 还可以满足需求;但到了 PTA5,多输出器件出现后,这种设计就需要调整。其次,InputPingetOutput() 默认直接访问已连接输出端,如果调用前没有充分检查连接状态,容易产生空指针风险。再次,连接解析中对端口合法性的判断较弱,例如某些非法下标主要依赖题目输入的规范性,程序自身的防御能力不够。最后,所有类仍集中在一个 Main.java 文件中,虽然适合 PTA 单文件提交,但不利于后续维护。

2. PTA5:复杂器件与多端口连接

PTA5 在 PTA4 的基础上明显扩大了器件范围。新增的 TriStateGateDecoderGateMuxGateDemuxGate 使程序必须面对多输入、多输出、控制端和数据端并存的情况。此时,单纯用“某个逻辑门只有一个输出端”的思路已经不够。因此 PTA5 重新抽象了 LogicGate 的端口访问方式,用 getSinkPin(int pinIndex) 表示取得某个输入端,用 getSourcePin(int pinIndex) 表示取得某个输出端,再由具体器件决定不同编号端口的意义。这是 PTA5 相比 PTA4 最关键的结构进步。

PTA5 的代码规模图如下:

代码规模

PTA5 的类图如下:

PTA5类图

PTA5 的类复杂度图如下:

类复杂度1

类复杂度2

PTA5 新增了 PinRef,用于把文本中的端口引用拆成类型、参数、编号和引脚号。它的作用不只是保存解析结果,更重要的是判断一个端口在当前器件规则下是否为输出端。例如基础门的 0 号端口是输出,三态门的 2 号端口是输出,译码器和数据分配器存在多个输出端,数据选择器则需要根据控制位数计算输出端编号。这个类的出现,使“端口方向判断”从输入流程中独立出来,提高了可读性。

在求值方式上,PTA5 将原来的 calculate() 改成了 evaluate()。基础门的计算结果不再由输出阶段临时计算,而是由每个器件把结果写入自己的输出端。对于多输出器件,这种方式更合适。例如译码器需要根据输入组合设置多个输出端状态,数据分配器也要根据控制信号选择某一路输出。如果仍沿用 PTA4 的单布尔返回值,就无法自然表达这些器件。

PTA5 的核心流程如下:

flowchart TDA["读取 INPUT 与连接行"] --> B["解析端口引用 PinRef"]B --> C["判断首端口是否为输出源"]C --> D["根据器件类型创建对象"]D --> E["通过 getSourcePin 与 getSinkPin 建立连接"]E --> F["按固定轮数迭代 evaluate"]F --> G["各器件按自身格式生成输出行"]

这一版的主要优点是端口方向、器件创建、连接构建和输出格式之间的职责更加清楚。新增器件虽然使代码行数从 524 行增长到 951 行,但程序结构没有完全失控。GateCreator 继续承担工厂职责,新增器件只需在创建分支中注册;CircuitOutput 仍然按指定类型顺序输出,保证了结果格式的稳定。

不过 PTA5 仍有改进空间。第一,PinRef.isOutput() 中集中写入了大量器件端口规则,随着器件增多,这个方法会越来越复杂。更合理的方式是让每个器件自己判断端口方向,或者建立端口描述对象。第二,电路求值仍采用固定次数迭代,虽然实现简单,但没有显式拓扑排序,也没有检测环路稳定性。第三,多输出器件的状态非法传播依赖 -1 这样的特殊值,规则虽然能用,但语义不够鲜明。第四,输出格式散落在各个具体门类中,一旦题目调整格式,需要修改多个类。

3. PTA6:子电路封装与错误处理

PTA6 是三次作业中规模最大、综合性最强的一次。它在 PTA5 的基础上加入了子电路概念,允许先定义 C1C2 这样的子电路,再在主电路中引用子电路的输入输出端口。这个变化对程序结构的影响很大,因为程序不再只有一张扁平的电路图,而是出现了“主电路”和“子电路内部电路”两个层次。

PTA6 的代码规模图如下:

代码规模

PTA6 的类图如下:

PTA6类图

PTA6 的类复杂度图如下:

类复杂度1

类复杂度2

PTA6 中最重要的新增类是 SubCircuitTerminalRefMainOutputPortSubCircuit 继承自 LogicGate,这意味着子电路也被当作一种可参与主电路求值的元件。它内部维护自己的 GateControllerGateCreator,并用输入端口、输出端口把外部信号与内部电路连接起来。TerminalRef 则把任意连接标识解析成“信号源”“接收端”或“无效引用”,为后续错误判断提供统一依据。MainOutputPort 用于表示主电路最终输出端,避免把主输出简单当成字符串处理。

PTA6 的输入处理明显比前两次复杂。程序先扫描并注册所有子电路,使主电路后续引用子电路时可以找到对应对象;然后再解析子电路内部连接;最后处理主电路输入和主电路连接。这种“两阶段注册,再分层解析”的思路是必要的,因为子电路可能在主电路连接出现之前已经需要被识别。如果只按输入顺序即时创建,遇到跨层引用时很容易出现找不到对象或端口未登记的问题。

PTA6 的整体流程如下:

flowchart TDA["读取全部行"] --> B["预注册子电路及其端口"]B --> C["解析子电路内部连接"]C --> D["解析主电路 INPUT 行"]D --> E["解析主电路连接行"]E --> F["检测输入源数量、输出端数量与顺序错误"]F --> G["主电路与子电路分别迭代求值"]G --> H["先输出子电路内部结果,再输出主电路结果"]

PTA6 的优点主要体现在两个方面。第一,子电路被纳入统一的逻辑门体系,主电路对它的使用方式和普通器件较为一致,这降低了主流程的特殊判断。第二,错误处理比前两次更完整,能够识别一条连接语句中输入源数量过多、没有输入源、没有输出端、输入输出顺序错误、输入端信号冲突等问题,并保留第一处错误输出。这说明程序已经从“只处理正确输入”转向“能解释错误输入”。

不过 PTA6 的复杂度也明显上升。StdInput 同时承担读取、子电路注册、子电路解析、主电路解析、端口解析和错误生成等职责,已经成为全程序中最重的类。resolveTerminal() 需要根据当前是否处于子电路、端口是否带短横线、是否是首端口、是否匹配子电路端口等条件进行判断,是典型的复杂热点。SubCircuit 内部又维护一套独立控制器和创建器,虽然结构合理,但也增加了调试难度。代码中还保留了一段被注释掉的旧输入类,这在提交版本中会增加阅读干扰,说明重构后的清理还不够彻底。

二、采坑心得

1. 输入解析的坑:正则匹配只是第一步

这三次作业最容易出问题的地方不是单个逻辑门的计算公式,而是输入解析。逻辑门标识中同时包含类型、参数、编号和端口号,例如基础门、译码器、选择器等规则并不完全一致。如果只用字符串截取,很容易在多位编号、可选参数或中文冒号等情况下出错。因此代码采用正则表达式统一拆解端口引用,这是必要的。

但是,正则匹配成功并不代表端口语义一定正确。一个文本标识可以被拆成类型和端口号,但该端口究竟是输入端还是输出端,还要根据器件类型继续判断。PTA4 中这部分判断较弱,到了 PTA5 才通过 PinRef 明确表达。我的体会是,解析输入至少应分成两个层次:第一层判断格式是否合法,第二层判断语义是否合法。只做格式解析,会让后续连接阶段承担过多隐含风险。

2. 端口方向的坑:不能默认第一个就是输出

在 PTA4 中,连接语句基本可以理解为“第一个端口是信号来源,后面的端口是接收端”。当只有基础门和输入信号时,这种理解比较自然。但 PTA5、PTA6 中出现多输出器件和子电路端口以后,端口方向不能再靠位置简单判断。尤其在 PTA6 中,一条连接语句需要检查输入源数量是否为一个、输出端数量是否至少为一个、输入源是否出现在首位。如果不进行这些判断,程序可能把接收端误认为信号源,或者把多个输出源连接到同一条语句中。

PTA6 中增加 TerminalRef 后,这个问题有了更清楚的处理方式。每个 token 先被解析成 source、sink 或 none,再统计 sourceCount 和 sinkCount。这样错误信息的生成也更自然。这个过程让我认识到,复杂题目中不要急着连接对象,应该先把“当前符号代表什么”建模清楚。

3. 多输出器件的坑:返回一个布尔值不够用

PTA4 的 calculate() 返回布尔值,适合表达与门、或门、非门这类单输出器件。但 PTA5 的译码器、数据分配器具有多个输出端,一个返回值无法表达多个端口的状态。如果继续沿用 PTA4 的接口,就会导致父类抽象和子类需求冲突。

PTA5 改用 evaluate() 后,具体器件可以直接修改自己的输出引脚状态。这种方式更符合电路仿真的思路。对象不是简单返回一个计算结果,而是在求值后更新自身端口状态。这个坑说明,抽象父类不能只根据当前题目最简单的情况设计,还要考虑问题域可能扩展的方向。

4. 迭代求值的坑:顺序依赖会影响结果

电路连接本质上是一张有向图。某个门的输出可能依赖另一个门,而输入文件中的连接顺序未必刚好等于计算顺序。因此程序采用多轮遍历求值的方式,让信号在若干轮迭代中逐步传播。PTA5 和 PTA6 使用 Math.max(n * 16 + 40, 80) 这样的固定上限,能够覆盖一般规模下的传播过程。

这种做法实现简单,符合课程作业的时间成本,但也有局限。它没有真正判断电路是否已经稳定,也没有对环路进行专门分析。若题目继续增加反馈电路或时序器件,固定轮数求值就可能不够严谨。更好的做法是建立拓扑关系,对无环组合电路进行拓扑排序;如果存在环路,则根据题目规则决定是否报错或进入稳定性分析。

5. 文件组织的坑:单文件提交方便,但维护困难

三次作业的所有类都写在 Main.java 中,这符合 PTA 提交习惯,但从工程角度看并不理想。PTA6 已经超过 1300 行,类数量达到 24 个。阅读时需要在输入类、子电路类、基础门类、复杂器件类之间来回跳转。如果每个类拆分为独立文件,再按 modelgateparserruntimeoutput 等包组织,结构会清晰很多。

单文件的另一个问题是旧代码容易残留。PTA6 中保留了被注释的旧输入类,虽然不影响运行,但会影响阅读和 SourceMonitor 统计结果,也会让后续维护者误以为这段逻辑仍有参考价值。提交前不仅要检查程序是否能运行,还应检查无用代码是否已经清理。

6. 测试与环境的坑:编译通过不等于能运行

本次复盘中,我对三份代码进行了本地编译和最小样例验证。最初直接使用命令行默认 javacjava,出现了 class 版本不匹配问题:默认 javac 版本为 24,而默认 java 运行环境为 1.8,导致运行器无法识别较新版本生成的 class 文件。改用本机 JDK 17 的 javac.exejava.exe 重新编译运行后,最小样例可以正常输出。

测试记录如下:

作业集 验证内容 结果
PTA4 两个输入信号连接二输入与门 输出 A(2)1-0:0
PTA5 与门结果继续连接到非门 输出 A(2)1-0:0N1-0:1
PTA6 在无子电路的主电路中复用 PTA5 最小样例 输出 A(2)1-0:0N1-0:1

这组测试不是完整测试,但能说明基本解析、连接和求值流程可以跑通。它也提醒我,提交前测试不能只看编译是否通过,还要确认编译器和运行器版本一致。对于 PTA 这类在线评测平台,最好在本地使用与平台相近的 JDK 版本,避免因为环境差异造成不必要的问题。

三、改进建议

第一,应拆分文件并建立更清晰的包结构。可以将 SignalSourceInputPinOutputPin 放入基础模型层,将各种门类放入器件层,将 GateCreator、端口解析类放入解析层,将 CircuitOutput 和求值调度放入运行层。这样不仅便于阅读,也便于在后续作业中增加新器件。

第二,应将端口规则下放到器件本身或独立端口描述对象中。当前 PTA5、PTA6 的 PinRef.isOutput() 需要知道所有器件的端口编号规则,违反了“谁拥有规则,谁负责解释”的原则。更好的设计是让每个 LogicGate 提供 isSourcePin()isSinkPin() 或端口元数据表。这样新增器件时,只需修改该器件类,不必修改一个越来越庞大的集中判断方法。

第三,应继续拆分 StdInput 的职责。PTA6 的 StdInput 已经承担了过多任务,可以拆成 LineReaderSubCircuitParserMainCircuitParserTerminalResolverErrorReporter 等对象。拆分后,输入流程会更长,但每个类的职责更单一,复杂度也更容易控制。

第四,应改进求值策略。固定轮数迭代虽然可以应付当前组合逻辑题,但不是最理想的电路求值方式。可以先根据连接关系构建依赖图,对无环电路进行拓扑排序,然后按依赖顺序计算。若检测到环路,则根据题目要求输出错误或采用更明确的稳定性判断规则。这样能减少无意义的重复遍历,也能让程序行为更可解释。

第五,应完善测试用例体系。除正常样例外,还应覆盖以下情况:输入信号重复定义、端口下标越界、一个输入端被多个输出源连接、连接语句没有输入源、输入源不在首位、译码器边界输出、选择器控制位边界、子电路输入输出端口重名、子电路端口未连接、主电路引用不存在的子电路等。测试不能只验证“会输出”,还要验证“错误时能按题目要求输出正确错误信息”。

第六,应减少魔法值和隐式约定。当前程序中用 -1 表示无效信号,用固定数组保存输出排序,用固定迭代次数传播信号。这些写法可以工作,但语义不够清晰。可以引入常量、枚举或结果对象,例如用 SignalValue.INVALID 表示无效信号,用 GateType 管理输出顺序,用 EvaluationResult 记录求值状态。这样程序含义更明确,也更便于调试。

第七,应在提交前进行清理和格式统一。包括删除旧代码注释块,统一命名风格,修正拼写错误,例如早期版本中的 praseGateaddStartSingal 这类拼写会降低可读性。虽然拼写错误不一定影响运行,但会影响长期维护,也容易让调用者产生误解。

四、总结

通过 PTA4~6 三次作业,我对面向对象设计的理解比前一阶段更具体。过去容易把“写了多个类”理解为面向对象,但这三次作业说明,真正重要的是类之间的职责边界是否清晰,抽象是否能承受需求变化。PTA4 中的 LogicGate 抽象适合基础门,但到了 PTA5,多输出器件要求重新设计端口访问接口;PTA6 引入子电路后,输入解析与连接语义又需要进一步抽象。这些变化让我看到,好的设计不是一次写成的,而是在需求推进中不断调整出来的。

三次作业中,我学到的第一点是要尊重问题领域本身。数字逻辑电路不是普通的顺序计算,它包含信号源、接收端、连接关系、端口方向和传播过程。如果只按字符串处理输入,很快会陷入大量特殊判断;只有把这些概念变成对象,程序才有继续扩展的基础。

第二点是接口设计要留有余地。PTA4 使用单输出模型时看起来简单,但 PTA5 的多输出器件马上暴露了限制。后续设计抽象类或接口时,不能只看最简单样例,而要尽量抓住同一类对象真正稳定的共同点。对于逻辑门来说,稳定的共同点不是“返回一个布尔值”,而是“拥有若干输入端和若干输出端,并能在求值时更新输出状态”。

第三点是错误处理也是程序设计的一部分。PTA6 的错误判断让我意识到,程序不仅要在正确输入下给出正确结果,还要在错误输入下给出可解释、可定位的反馈。错误判断如果散落在各处,就会导致输出不一致;如果先把端口统一解析为 TerminalRef,再集中统计错误条件,结构就会清楚很多。

第四点是测试必须覆盖结构风险。基础门计算是否正确只是一小部分,更重要的是连接顺序、端口方向、信号冲突、子电路边界、环境版本等问题。很多失分并不是因为公式不会写,而是因为边界场景没有提前验证。以后做类似题目时,应在实现过程中同步积累测试输入,而不是等全部写完才临时手测。

这三次作业仍有需要继续学习和研究的地方。首先是图结构算法,特别是拓扑排序、环路检测和依赖传播机制。其次是更成熟的解析器设计,如何把输入语言拆成词法、语法和语义三个层次,而不是在一个方法中完成全部判断。再次是软件重构方法,如何在不破坏已通过功能的前提下,把大类拆小、把规则下放、把重复逻辑提炼出来。最后是测试方法,需要进一步学习如何为面向对象程序设计单元测试和集成测试。

总体来看,PTA4~6 的价值不只在完成题目,更在于通过同一主题的连续迭代,让我看到了早期设计对后续扩展的影响。简单题目中可以暂时依靠流程堆叠解决问题,但当题目进入复杂器件、子电路和错误处理阶段,代码结构的好坏会直接决定调试效率和扩展成本。后续编程中,我应更加重视建模、接口、职责分离和测试,让程序不仅能通过当前样例,也能面对下一次需求变化时保持清晰和稳定。

http://www.rkmt.cn/news/1544682.html

相关文章:

  • Loop Engineering火了,一文带你入门!
  • 2026佛山设备搬运公司口碑排名 精密仪器搬迁定制化方案指南 - 从来都是英雄出少年
  • Baserow开源数据库平台:零代码构建企业级应用的最佳实践
  • 实现T+1交易约束校验脚本,避免A股当日买入误设置卖出指令。
  • 当AI助手成为数字员工湖南格讯为某公司农机事业部开发AI助手实战总结 - 技术瞭望台
  • 终极防撤回指南:用开源工具永久保存微信QQ聊天记录
  • ZigBee价格簇开发实战:从原理到应用,实现智能能源管理
  • 多维聚合实战:从groupby到业务语义落地的5大关键模式
  • SolidWorks第四部分_直接实体建模特征15_相交特征
  • ZigBee ZCL色彩控制集群API实战:从协议解析到智能灯光开发
  • 告别复杂驱动:Platinum-MD如何让MiniDisc音乐传输变得像拖放文件一样简单
  • 如何告别混乱时间管理?Simple Clock为您提供纯净高效的时间掌控方案
  • 【IC】【Low Power】从功耗构成到设计实践:CMOS低功耗技术全景解析
  • 腾讯云TDSQL私有云实战:从零搭建到核心组件深度解析
  • 从度量到实践:构建可落地的代码质量保障体系与AI时代新策略
  • VirtualMotionCapture终极指南:如何在VR游戏中实现实时动作捕捉
  • 2026年沈阳316L不锈钢价格口碑排行榜:性价比与耐腐蚀性能深度解析及选购指南 - 企业推荐官【官方】
  • 一线观察:长期体验科思创 2655 平替,看到的企业管理真相
  • 光伏板检测仪器:全自动对焦高清成像,精准排查组件质量缺陷
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年
  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • ZigBee OTA升级持久化数据管理与Flash存储策略详解
  • GPT-4 Turbo工程落地指南:响应速度、128K上下文与多模态协同实战
  • 2026年工厂设备回收推荐榜单:浙江/上海/江苏/福建化工、印染、电子、五金、塑胶等各类型厂家高价值处置与专业服务商精选 - 品牌发掘
  • 如何做出Nature级别的科研绘图?
  • 2026年 201不锈钢厂家推荐排行榜:冷轧/热轧卷板、不锈钢带、精密管材源头品牌实力解析 - 品牌发掘
  • makefile入门与一些简易windows命令
  • 北京瓷器玉石工艺品回收怎么选不踩坑?2026TOP5正规机构精准适配指南 - 深鉴新闻
  • Visium HD空间组学技术:从高分辨率捕获到单细胞空间图谱构建