5-7习题集blog

本次题目集5~7涵盖了Java面向对象编程的多个重要知识点,包括类设计、继承与多态、正则表达式、异常处理以及算法实现等。题目难度有简单的也有难的,题量适中但综合性较强,特别是电梯题目在三次题目集中都有出现,渐渐的提高了难度和要求。

题目集5主要考察基础编程能力,如身份证校验位计算、一元二次方程求解等;题目集6重点测试类设计能力,特别是单一职责原则的应用;题目集7则在前两次基础上增加了更复杂的场景模拟和算法实现。整体来看,这些题目很好地检验了我们对Java面向对象编程的理解和应用能力,除了电梯程序外其他的难度都不是很高,我都能比较轻松的解决

设计与分析

题目集5分析

5-1 身份证号校验位计算

这个题目要求根据身份证前17位计算校验位。实现思路是:

  1. 验证输入是否为17位数字
  2. 定义系数数组和校验码映射数组
  3. 计算加权和并取模得到校验位
int[] a1 = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
char[] a2 = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
int sum = 0;
for (int i = 0; i < 17; i++) {
    sum += (input.charAt(i) - '0')  a1[i];
}
int r = sum % 11;
char a2v = a2[r];

SourceMonitor分析显示该代码复杂度较低,方法平均复杂度为1.0,符合要求。

5-2 一元二次方程求解

这个题目要求设计一个QuadraticEquation类来求解一元二次方程。我按照题目要求实现了所有必要的方法:

class QuadraticEquation{
    private double a;
    private double b;
    private double c;
    
    public QuadraticEquation(double a, double b, double c){
        this.a = a;
        this.b = b;
        this.c = c;
    }
    
    public double getDiscriminant(){
        return b  b - 4  a  c;
    }
    
    public double getRoot1(){
        return (-b + Math.pow(getDiscriminant(), 0.5)) / (2  a);
    }
    
    // 其他方法...
}

5-3 验证码校验

这个题目要求验证输入字符串是否为4位数字或字母。我的实现使用了字符数组遍历:

for(int i=0;i<ch.length;i++){
    if(!((ch[i]>='0'&&ch[i]<='9')||(ch[i]>='a'&&ch[i]<='z')||(ch[i]>='A'&&ch[i]<='Z'))){
        System.out.printf(new String(ch) + "不属于验证码");
        return;
    }
}

虽然实现了功能,但使用正则表达式应该会更简洁高效。

题目集6分析

6-1 点与线类设计阿

这个题目要求设计Point和Line类来表示坐标系中的点和线。我的实现如下:

class Point{
    private double x;
    private double y;
    
    public Point(double x, double y){
        this.x = x;
        this.y = y;
    }
    
    public void display(){
        if (x<=0||y<=0||x>200||y>200){
            System.out.println("Wrong Format");
        }
        else{
            System.out.printf("(%.2f,%.2f)",x,y);
        }
    }
    // 其他方法...
}

class Line{
    private Point p1;
    private Point p2;
    private String color;
    
    public double getDistance(){
        return Math.sqrt((p1.getX()-p2.getX())(p1.getX()-p2.getX())+
               (p1.getY()-p2.getY())(p1.getY()-p2.getY()));
    }
    // 其他方法...
}

SourceMonitor分析显示代码复杂度适中,方法平均复杂度为1.5。类设计符合题目要求,但可以进一步优化异常处理。

6-2 汽车雨刷问题

这个题目要求设计多个类来模拟雨刷控制系统。我按照单一职责原则设计了Lever、Dial、Brush和Agent类:

class Lever {
    private int pos;
    public void upPos() { if (pos < 4) pos++; }
    public void downPos() { if (pos > 1) pos--; }
    // 其他方法...
}

class Agent {
    private Lever lever;
    private Dial dial;
    private Brush brush;
    
    public void dealSpeed() {
        int leverPos = lever.getPos();
        int dialPos = dial.getPos();
        int speed = 0;
        
        if (leverPos == 1) speed = 0;
        else if (leverPos == 2) {
            switch (dialPos) {
                case 1: speed = 4; break;
                case 2: speed = 6; break;
                // 其他情况...
            }
        }
        // 其他逻辑...
        brush.setSpeed(speed);
    }
}

SourceMonitor显示方法平均复杂度为2.0,处于合理范围。

6-3 单部电梯调度程序(类设计)

这个题目是前次电梯程序的迭代版本,要求按照更严格的类设计原则实现。由于难度较大,我未能完成全部功能,但可以分析理想的设计方案:

  1. 应该设计Elevator、Request、RequestQueue和Controller类
  2. Elevator类负责电梯状态管理
  3. Request类封装请求信息
  4. RequestQueue管理请求队列
  5. Controller协调电梯运行
class Elevator {
    private int currentFloor;
    private Direction direction;
    private State state;
    // 其他属性和方法...
}

class Request {
    private int floor;
    private Direction direction;
    // 其他方法...
}

class Controller {
    private Elevator elevator;
    private RequestQueue queue;
    
    public void processRequests() {
        // 处理请求队列逻辑
    }
}

题目集7分析

7-1 销售步枪问题

这个题目要求设计销售订单类计算销售额和佣金。我的实现:

class SalesOrder{
    private int lockNum;
    private int stockNum;
    private int barrelNum;
    
    public double getTotal(){
        return lockNum45 + stockNum30 + barrelNum25;
    }
    
    public double Commission(double sales){
        if(sales <=1000) return 0.1sales;
        else if(sales <=1800) return 100 + 0.15(sales-1000);
        else return 220 + 0.2(sales-1800);
    }
}

SourceMonitor分析显示方法平均复杂度为1.8,结构清晰。类设计符合单一职责原则。

7-2 蒙特卡罗方法求圆周率

这个题目要求使用蒙特卡罗方法估算π值。我设计了Coordinate、Rectangle、Circle和MonteCarloSimulation类:

class MonteCarloSimulation{
    public double simulation(int n){
        double sum = 0;
        for(int i = 0;i < n;i++){
            double x = random.nextDouble()rectangle.getLength()+rectangle.getCoordinate().getX();
            double y = random.nextDouble()rectangle.getWidth()+rectangle.getCoordinate().getY();
            if(getDistance(new Coordinate(x,y),circle.getCoordinate()) <= circle.getRadius()){
                sum+=1;
            }
        }
        return 4sum/n;
    }
}

该方法复杂度为2.0,算法实现正确,但可以优化随机数生成效率。

在题目集5~7中,单部电梯调度程序是贯穿三次题目集的核心题目,其设计难度和复杂度逐步提升。以下是对该题目的深入分析与设计思考:
题目集5的单部电梯调度程序
初次接触电梯调度问题时,我设计了一个简单的电梯类,将所有功能集中在一个类中,导致代码臃肿且难以维护。例如,电梯的状态管理、请求队列处理和调度逻辑全部混杂在一起。虽然功能勉强实现,但代码的可读性和扩展性极差。SourceMonitor分析显示,该类的平均方法复杂度高达3.5,远超合理范围(理想值应小于2.0)。以下是部分问题代码:
class Elevator {
private int currentFloor;
private List internalRequests;
private List externalRequests;
// 其他属性和方法...
public void processRequests() {
// 处理内部和外部请求的逻辑混杂
}}
题目集6的电梯设计
在题目集6中,题目要求遵循单一职责原则,将电梯调度程序拆分为多个类。根据pta上面作业的示意图可以分为以下几类,
Elevator类:管理电梯的当前状态(楼层、方向、运行状态)。

Request类:封装乘客请求(楼层和方向)。

RequestQueue类:管理请求队列,处理请求的添加和过滤(如忽略重复请求)。

Controller类:负责调度逻辑,协调电梯运行。

改进后各类的方法平均复杂度降至1.8,代码结构更清晰。例如,Controller类的核心方法processRequests的复杂度从4.2降至2.1,逻辑更专注:
class Controller {
public void processRequests() {
while (!queue.isEmpty()) {
Request request = queue.getNextRequest();
elevator.moveTo(request.getFloor());
if (elevator.shouldStop(request)) {
elevator.openDoor();
elevator.closeDoor();
}
}
}}
题目集7的进一步修改
PTA题目集7-3要求加入乘客类,并将外部请求格式改为<源楼层, 目的楼层>。这样加大了题目的难度,可以这样设计:

Passenger类:新增乘客信息。

Request类:关联乘客和请求信息。

逻辑优化后,当电梯处理外部请求后,将会自动将目的楼层加入内部队列。

这一阶段主要在于内外请求的动态管理。比如说,当电梯处理<5,9>请求时,需要在到达5楼后,将9楼加入内部队列。以下是我修改后的主要信息:
class RequestQueue {
public void addExternalRequest(Passenger passenger, int source, int target) {
Request externalRequest = new Request(passenger, source, Direction.UP); // 假设方向需计算
Request internalRequest = new Request(passenger, target, null); // 内部请求无方向
externalRequests.add(externalRequest);
internalRequests.add(internalRequest);
}}

采坑心得

  1. 身份证校验位计算:最初忽略了输入长度检查,导致程序可能接受非法输入。通过添加长度验证解决了问题:
if (input.length() != 17) {
    System.out.println("Wrong Format");
    return;
}
  1. 一元二次方程求解:在计算判别式时,最初没有考虑浮点数精度问题,导致比较结果不准确。改进后使用了更精确的比较方式:
if (Math.abs(discriminant) < 1E-6) { // 视为等于0
    // 处理单根情况
}
  1. 验证码校验:最初使用字符数组遍历判断,后来意识到使用正则表达式会更简洁:
if (input.matches("[0-9a-zA-Z]{4}")) {
    // 验证码有效
}
  1. 点与线类设计:在坐标范围验证时,最初只检查了大于0的条件,忽略了上限200的限制。修正后:
if (x<=0 || y<=0 || x>200 || y>200) {
    System.out.println("Wrong Format");
}
  1. 汽车雨刷问题:在实现Agent类时,最初将速度计算逻辑放在了错误的位置,导致状态更新不及时。通过重构将速度计算移到dealSpeed方法中解决了问题。

  2. 蒙特卡罗方法:在验证矩形是否为正方形时,最初使用==比较浮点数,导致精度问题。改进后:

if (Math.abs(length - width) < 1E-6) {
    // 视为正方形
}

改进建议

  1. 性能优化:比如说在PTA上求π的题目中,可以优化随机数的生成,可以使用更高效的算法这样可以让运行更流畅不会卡顿

  2. 增加状态更新的功能:电梯程序中可以使用枚举的方法来管理电梯的不同状态,这样可以让当前状态更清晰。

  3. 加入日志调试:在电梯的程序中添加调试代码,这样可以便于找出问题所在。

  4. 文档注释:可以在一些关键地方增加一写注释来提高可读性,这样可以更容易看懂代码
    总结

经过这三次题目集的练习,我可以理解了面向对象编程的基本原则和设计思想,尤其是是单一职责原则的重要性。在实现复杂系统如电梯调度程序时,良好的类设计能够大大降低代码复杂度,提高可维护性。

我掌握了以下关键技能:

  1. 类设计与实现
  2. 封装与信息隐藏
  3. 算法设计与实现
  4. 输入验证与异常处理
    5.学会了 java的基本逻辑

可以进一步学习的领域:

  1. 设计模式的深入应用![]
  2. 多线程编程
  3. 更复杂的算法设计与分析

对课程的建议:

  1. 可以降低作业的频率和难度
  2. 可以让我们学生协作编程

完成题目后,这三次题目集让我在学习Java方面有了很大的进步,虽然遇到了很多问题,但经过写完这些题目后,我学到了很多宝贵的经验和学习java的方法

posted @ 2025-04-20 19:02  曙光不是曙片  阅读(40)  评论(0)    收藏  举报