PTA电梯分析

📈 电梯分析

基于PTA题集中的电梯题的总结blog,包含圈复杂度,方法深度等分析指标。

■ 前言 && 采坑心得

前言:三次的电梯题目难度算中偏上,从分析设计到优化改进,设计面向对象封装特性,单一职责原则,java的使用,各种语法错误,运行错误,逻辑错误,在写三次迭代的时候中反复出现,实在是,唉。心得:首先,在前两次电梯题,最困惑的地方就在于电梯的处理逻辑,样例只有一个,刚开始因为要求不具体,想过去设计各种样例去找出逻辑,但没有方向,止步于想,这里删,那里改,两回生,三回熟,写两次后逻辑(见附录)才基本清晰,但还是拿不全分,现在也还没弄明白。其次,这也是一个边写边学的过程,像正则表达式,第一次写电梯的时候没有去用,后两次想着,学都学了,还是写上去巩固一下,途中也会出现各种错误,异常,多和java打点交道,慢慢地也能处理一些了。然后就是面向对象封装特性和单一职责的原则,在写题过程中也潜移默化地融入我的编程习惯。总体而言,我在这个过程中取得了一定的进步。

🛠 代码分析 (SourceMonitor) && 改进

📌 第一次电梯迭代分析

基本信息

  • 文件名称Main.java
  • 代码行数:308
  • 语句总数:191

代码复杂度相关指标

  • 分支语句占比:24.1%
  • 方法调用语句数:90
  • 注释行占比:5.5%
  • 类和接口数:3
  • 每个类的平均方法数:4.67
  • 每个方法的平均语句数:12.00
  • 最复杂方法Elevator.processRequests(),复杂度为32,位于第93行
  • 最大嵌套深度:5,位于第63行
  • 平均嵌套深度:2.26
  • 平均复杂度:8.33

最复杂方法

方法名称 复杂度 语句数 最大嵌套深度 方法调用数
Elevator.addNodeToTail() 4 10 4 0
Elevator.addRequest() 9 13 5 10
Elevator.Elevator() 1 7 2 0
Elevator.processRequests() 32 64 4 42
Main.main() 3 9 3 6
RequestNode.RequestNode() 1 2 2 0

嵌套深度与语句数分布

嵌套深度 语句数
0 13
1 46
2 54
3 36
4 40
5 2
6+ 0

从第一次迭代的分析结果可以看出,代码的整体复杂度较高。最复杂的方法是 Elevator.process-
Requests(),其复杂度达到了32,这个方法的逻辑比较复杂,后续肯定需要进一步的优化和分解。
另外,平均嵌套深度为2.26,最大嵌套深度为5,说明代码中存在比较多的嵌套结构,会对代码的可
读性和可维护性产生一定的影响,也是后面需要改进的地方。

Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------

Parameter				Value
=========				=====
Project Directory			D:\java_project\project000\giveSM\src\z\
Project Name				z
Checkpoint Name				Baseline
File Name				Main.java
Lines					308
Statements				191
Percent Branch Statements		24.1
Method Call Statements			90
Percent Lines with Comments		5.5
Classes and Interfaces			3
Methods per Class			4.67
Average Statements per Method		12.00
Line Number of Most Complex Method	93
Name of Most Complex Method		Elevator.processRequests()
Maximum Complexity			32
Line Number of Deepest Block		63
Maximum Block Depth			5
Average Block Depth			2.26
Average Complexity			8.33

--------------------------------------------------------------------------------------------
Most Complex Methods in 3 Class(es):	Complexity, Statements, Max Depth, Calls

Elevator.addNodeToTail()		4, 10, 4, 0
Elevator.addRequest()			9, 13, 5, 10
Elevator.Elevator()			1, 7, 2, 0
Elevator.processRequests()		32, 64, 4, 42
Main.main()				3, 9, 3, 6
RequestNode.RequestNode()		1, 2, 2, 0

--------------------------------------------------------------------------------------------
Block Depth				Statements

0					13
1					46
2					54
3					36
4					40
5					2
6					0
7					0
8					0
9+					0
--------------------------------------------------------------------------------------------

📌 第二次电梯迭代分析

基本信息

  • 项目目录D:\java_project\project000\giveSM\src\zz\
  • 项目名称zz
  • 文件名称Main.java
  • 代码行数:457
  • 语句总数:257

代码复杂度相关指标

  • 分支语句占比:19.5%
  • 方法调用语句数:187
  • 注释行占比:7.4%
  • 类和接口数:7
  • 每个类的平均方法数:6.14
  • 每个方法的平均语句数:5.16
  • 最复杂方法Main.main(),复杂度为11,位于第9行
  • 最大嵌套深度:5,位于第36行
  • 平均嵌套深度:1.50
  • 平均复杂度:1.52

最复杂方法

方法名称 复杂度 语句数 最大嵌套深度 方法调用数
Controller.Controller() 1 2 2 0
Controller.getElevator() 1 1 2 0
Controller.getNextFloor() 1 1 2 0
Controller.getQueue() 1 1 2 0
Controller.move() 1 0 0 0
Controller.processRequest() 3 3 3 6
Controller.removeRequest() 1 0 0 0
Controller.setElevator() 1 1 2 0
Controller.setQueue() 1 1 2 0
Controller.shouldStop() 1 1 2 0
Elevator.Elevator() 1 4 2 0
Elevator.getCurrentFloor() 1 1 2 0
Elevator.getDirection() 1 1 2 0
Elevator.getMaxfloor() 1 1 2 0
Elevator.getMinfloor() 1 1 2 0
Elevator.getState() 1 1 2 0
Elevator.setCurrentFloor() 1 1 2 0
Elevator.setDirection() 1 1 2 0
Elevator.setState() 1 1 2 0
ExternalRequest.ExternalRequest() 1 2 2 0
ExternalRequest.getDirection() 1 1 2 0
ExternalRequest.getFloor() 1 1 2 0
Main.main() 11 27 5 24
RequestQueue.addExternalRequest() 1 1 2 1
RequestQueue.addInternalRequest() 1 1 2 1
RequestQueue.getExternalRequests() 1 1 2 0
RequestQueue.getInternalRequests() 1 1 2 0
RequestQueue.isEndHadIn() 3 6 4 2
RequestQueue.isEndHadOut() 4 5 3 7
RequestQueue.RequestQueue() 1 0 0 0
RequestQueue.setExternalRequests() 1 1 2 0
RequestQueue.setInternalRequests() 1 1 2 0

嵌套深度与语句数分布

嵌套深度 语句数
0 38
1 95
2 96
3 16
4 10
5 2
6+ 0

在第二次迭代中,非常明显,代码的复杂度有了很大的降低。最复杂的方法是 Main.main()复杂度是11,
比起第一次迭代的32有了很大的改善,是一次质的飞跃。另外,平均复杂度也降低到了1.52,说明代码
的整体复杂度得到了有效的控制。而且,平均嵌套深度降低到了1.50,嵌套深度大于3的代码块数量明显
减少,提高了代码的可读性和可维护性,这次的改进比较可以,利用单一职责原则减轻之前第一次代码中
Elevator.processRequests()的负担。不过最大嵌套深度还是5,有点难改,这点在写电梯题目的时候
也没有注意,所以这点到第三次也没有大的改进,主要是因为处理逻辑在第二次迭代后基本清晰,第三次
的迭代大部分沿袭的第二次,只是根据题目要求的变化改了一些输入的方法,请求方向用输入的两个楼层
算,其它的只做了微小的改动和优化。

Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------

Parameter				Value
=========				=====
Project Directory			D:\java_project\project000\giveSM\src\zz\
Project Name				zz
Checkpoint Name				Baseline
File Name				Main.java
Lines					457
Statements				257
Percent Branch Statements		19.5
Method Call Statements			187
Percent Lines with Comments		7.4
Classes and Interfaces			7
Methods per Class			6.14
Average Statements per Method		5.16
Line Number of Most Complex Method	9
Name of Most Complex Method		Main.main()
Maximum Complexity			11
Line Number of Deepest Block		36
Maximum Block Depth			5
Average Block Depth			1.50
Average Complexity			1.52

--------------------------------------------------------------------------------------------
Most Complex Methods in 5 Class(es):	Complexity, Statements, Max Depth, Calls

Controller.Controller()			1, 2, 2, 0
Controller.Controller()			1, 0, 0, 0
Controller.getElevator()		1, 1, 2, 0
Controller.getNextFloor()		1, 1, 2, 0
Controller.getQueue()			1, 1, 2, 0
Controller.move()			1, 0, 0, 0
Controller.processRequest()		3, 3, 3, 6
Controller.removeRequest()		1, 0, 0, 0
Controller.setElevator()		1, 1, 2, 0
Controller.setQueue()			1, 1, 2, 0
Controller.shouldStop()			1, 1, 2, 0
Elevator.Elevator()			1, 4, 2, 0
Elevator.getCurrentFloor()		1, 1, 2, 0
Elevator.getDirection()			1, 1, 2, 0
Elevator.getMaxfloor()			1, 1, 2, 0
Elevator.getMinfloor()			1, 1, 2, 0
Elevator.getState()			1, 1, 2, 0
Elevator.setCurrentFloor()		1, 1, 2, 0
Elevator.setDirection()			1, 1, 2, 0
Elevator.setState()			1, 1, 2, 0
ExternalRequest.ExternalRequest()	1, 2, 2, 0
ExternalRequest.getDirection()		1, 1, 2, 0
ExternalRequest.getFloor()		1, 1, 2, 0
Main.main()				11, 27, 5, 24
RequestQueue.addExternalRequest()	1, 1, 2, 1
RequestQueue.addInternalRequest()	1, 1, 2, 1
RequestQueue.getExternalRequests()	1, 1, 2, 0
RequestQueue.getInternalRequests()	1, 1, 2, 0
RequestQueue.isEndHadIn()		3, 6, 4, 2
RequestQueue.isEndHadOut()		4, 5, 3, 7
RequestQueue.RequestQueue()		1, 0, 0, 0
RequestQueue.setExternalRequests()	1, 1, 2, 0
RequestQueue.setInternalRequests()	1, 1, 2, 0

--------------------------------------------------------------------------------------------
Block Depth				Statements

0					38
1					95
2					96
3					16
4					10
5					2
6					0
7					0
8					0
9+					0
--------------------------------------------------------------------------------------------

📌 第三次电梯迭代分析

基本信息

  • 项目目录D:\java_project\project000\giveSM\src\zzz\
  • 项目名称zzz
  • 文件名称Main.java
  • 代码行数:396
  • 语句总数:238

代码复杂度相关指标

  • 分支语句占比:12.6%
  • 方法调用语句数:135
  • 注释行占比:3.8%
  • 类和接口数:8
  • 每个类的平均方法数:6.38
  • 每个方法的平均语句数:4.25
  • 最复杂方法Controller.processRequest(),复杂度为6,位于第79行
  • 最大嵌套深度:4,位于第31行
  • 平均嵌套深度:1.42
  • 平均复杂度:1.25

最复杂方法

方法名称 复杂度 语句数 最大嵌套深度 方法调用数
Controller.Controller() 1 2 2 0
Controller.getElevator() 1 1 2 0
Controller.getQueue() 1 1 2 0
Controller.processRequest() 6 11 4 16
Controller.setElevator() 1 1 2 0
Controller.setQueue() 1 1 2 0
Elevator.Elevator() 1 2 2 0
Elevator.getCurrentFloor() 1 1 2 0
`Elevator.getDirection

在第三次迭代中,代码的复杂度进一步降低。最复杂的方法是 Controller.processRequest(),
其复杂度只有6,对比前两次迭代已经有了很大的改善。而且,平均复杂度降低到了1.25,说明代
码的整体复杂度已经得到了很好的控制。另外,最大嵌套深度降低到了4,平均嵌套深度降低到了
1.42,嵌套深度大于3的代码块数量进一步减少,提高了代码的可读性和可维护性。这个最终版本
总体来说还算可以,最大的缺陷可能就是注释吧,我基本上一个方法一个方法注释,当方法基本
见名知译,实际上大多数的注释就是翻译一下英文。

Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------

Parameter				Value
=========				=====
Project Directory			D:\java_project\project000\giveSM\src\zzz\
Project Name				zzz
Checkpoint Name				Baseline
File Name				Main.java
Lines					396
Statements				238
Percent Branch Statements		12.6
Method Call Statements			135
Percent Lines with Comments		3.8
Classes and Interfaces			8
Methods per Class			6.38
Average Statements per Method		4.25
Line Number of Most Complex Method	79
Name of Most Complex Method		Controller.processRequest()
Maximum Complexity			6
Line Number of Deepest Block		31
Maximum Block Depth			4
Average Block Depth			1.42
Average Complexity			1.25

--------------------------------------------------------------------------------------------
Most Complex Methods in 6 Class(es):	Complexity, Statements, Max Depth, Calls

Controller.Controller()			1, 2, 2, 0
Controller.Controller()			1, 0, 0, 0
Controller.getElevator()		1, 1, 2, 0
Controller.getQueue()			1, 1, 2, 0
Controller.processRequest()		6, 11, 4, 16
Controller.setElevator()		1, 1, 2, 0
Controller.setQueue()			1, 1, 2, 0
Elevator.Elevator()			1, 2, 2, 0
Elevator.getCurrentFloor()		1, 1, 2, 0
Elevator.getDirection()			1, 1, 2, 0
Elevator.getMaxFloor()			1, 1, 2, 0
Elevator.getMinFloor()			1, 1, 2, 0
Elevator.getState()			1, 1, 2, 0
Elevator.setCurrentFloor()		1, 1, 2, 0
Elevator.setDirection()			1, 1, 2, 0
Elevator.setState()			1, 1, 2, 0
ExternalRequest.ExternalRequest()	1, 2, 2, 0
ExternalRequest.getDirection()		1, 1, 2, 0
ExternalRequest.getFloor()		1, 1, 2, 0
Main.main()				5, 24, 4, 18
Passenger.getDestinationFloor()		1, 1, 2, 0
Passenger.getSourceFloor()		1, 1, 2, 0
Passenger.Passenger()			1, 2, 2, 0
Passenger.Passenger()			1, 1, 2, 0
Passenger.Passenger()			1, 2, 2, 0
Passenger.setDestinationFloor()		1, 1, 2, 0
Passenger.setSourceFloor()		1, 1, 2, 0
RequestQueue.addExternalRequest()	1, 1, 2, 1
RequestQueue.addInternalRequest()	1, 1, 2, 1
RequestQueue.addRequest()		1, 1, 2, 1
RequestQueue.getExternalRequests()	1, 1, 2, 0
RequestQueue.getInternalRequests()	1, 1, 2, 0
RequestQueue.getQueueInstance()		1, 1, 2, 0
RequestQueue.RequestQueue()		1, 0, 0, 0
RequestQueue.setExternalRequests()	1, 1, 2, 0
RequestQueue.setInternalRequests()	1, 1, 2, 0

--------------------------------------------------------------------------------------------
Block Depth				Statements

0					33
1					106
2					74
3					15
4					10
5					0
6					0
7					0
8					0
9+					0
--------------------------------------------------------------------------------------------

总结

三次迭代代码质量演进分析

指标 第一次迭代 第二次迭代 第三次迭代 健康阈值 趋势
最大圈复杂度 32 11 6 <10 ↘️ 达标
平均圈复杂度 8.33 1.52 1.25 <2 ↘️ 达标
注释覆盖率 5.5% 7.4% 3.8% ≥20% ⚠️ 恶化
最深嵌套层级 5 5 4 ≤4 → 达标
方法平均语句数 12.00 5.16 4.25 <15 ↘️ 优化
最大块深度 5 5 4 ≤4 ↘️达标
平均块深度 2.26 1.50 1.42 ≤2 ↘️优化
深度>3的代码块占比 12.7% 4.9% 3.3% <5% ↘️优化

通过三次迭代的分析可以看出,每一次迭代最大圈复杂度、平均圈复杂度、最深嵌套层级、方法平
均语句数、最大块深度、平均块深度、深度>3的代码块占比都有所优化,尤其是最大圈复杂度和平
均圈复杂度,而其他方面,整体呈优化趋势。
总的来说,在后续的编程中,注重单一职责原则,面向对象,注意提高注释覆盖率,以确保代码的
质量。

🗂 附录

只剩一个队列,处理该队列;均同/异向,处理近者;一同一异,处理同者。
内队列方向根据楼层差判断方向。(例如:现在在3楼,方向朝上,内队列头请求为<5>,那么因为5-3>0且现方向为上,则同向,反之同理)
外队列方向有两个根据,一个是请求方向(1,2中根据UP,DOWN,3中根据两个请求楼层可判断请求的方向是UP还是DOWN),另一个是楼层差方向(例如:现在在3楼,方向为↑,外队列头为<5,2>,则请求方向为↓,因为2-5<0,楼层差方向为↑,因为5-3>0,都是终点减起点)。
外队列方向处理逻辑:当请求方向和楼层差同向,则外队列方向即该方向;若异向,再看内队列头的方向,如果内队列头与现方向同向,那么设置外队列头为与现方向异向,这样就可以处理内队列头,如果内队列与现方向异向,且外队列头的楼层差方向与现方向相同,那么设置外队列为与现方向同向,这样就可以处理外队列头。
相关代码如下:

public void processRequest() {
        while(!queue.getExternalRequests().isEmpty() || !queue.getInternalRequests().isEmpty()) {
            if(queue.getExternalRequests().isEmpty()) {
                processIn();
            }
            else if(queue.getInternalRequests().isEmpty()) {
                processEx();
            }
            else{
                boolean in = isInSameDir(queue.getInternalRequests().getFirst());
                boolean ex = isExRepeat(queue.getExternalRequests().getFirst());
                //均同向,执行更近的队列请求
                if(in && ex) {
                    getClosest(queue.getInternalRequests().getFirst().getDestinationFloor(), queue.getExternalRequests().getFirst().getSourceFloor());
                }
                //外同内异,执行同向的外队列请求
                else if (!in && ex) {
                    processEx();
                }
                //内同外异,执行同向的内队列请求
                else if (in && !ex) {
                    processIn();
                }
                //均异向,执行更近的队列请求
                else {
                    //turnDir();
                    getClosest(queue.getInternalRequests().getFirst().getDestinationFloor(), queue.getExternalRequests().getFirst().getSourceFloor());
                }
            }
        }
    }
public boolean isInSameDir(Passenger passenger) {
        boolean result1 = elevator.getCurrentFloor()<passenger.getDestinationFloor() && elevator.getDirection().equals(Direction.UP);
        boolean result2 = elevator.getCurrentFloor()>passenger.getDestinationFloor() && elevator.getDirection().equals(Direction.DOWN);
        if(result1 || result2){
            return true;
        }
        return false;
    }
public boolean isExSameDir(Passenger passenger) {
        int c =elevator.getCurrentFloor();
        int d = passenger.getDestinationFloor();
        int s = passenger.getSourceFloor();
        boolean r1 = c<s && elevator.getDirection().equals(Direction.UP);
        boolean r2 = c>s && elevator.getDirection().equals(Direction.DOWN);
        boolean result1 = s<d && r1;
        boolean result2 = s>d && r2;
        boolean result3 = !isInSameDir(passenger) && (r1||r2);
        if(result1 || result2 || result3){
            return true;
        }
        return false;
    }
posted @ 2025-04-17 20:36  黑伞青X  阅读(163)  评论(0)    收藏  举报