第一次Blog作业

前言:


几次题目集的知识点涵盖基础语法, 模板类的使用, 设计原则, 正则表达式等;
一周时间对于该题目集的题目量而言相对充裕;
程序的实现本身难度一般,但不准确的、自相矛盾的、误导性的描述和解释让题目的通过难度可谓是上了几层楼;


设计与分析:

第一次代码分析:
image
image
主要问题:
1.高复杂度方法
Main.main() 方法复杂度高达 11(24条语句/7层嵌套/20次调用)
2.深层嵌套逻辑
最大块深度达到 7 层(行号281)
3.分支逻辑密集
分支语句占比 25%(约33个分支点)
第一次代码设计

点击查看代码
package pta05_5_1;


import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Lift{
	//最大楼层,最小楼层,当前楼层,当前方向,运行状态
		private int maxFloor, minFloor, curFloor, curDirection, state, aim, preDirection, preFloor;
		//内部请求队列
		private int[] rstIn = new int[0];
		//外部请求队列
		private int[][] rstOut = new int[0][2];
		
		public Lift(){
			
		}
		
		public int getMaxFloor() {
			return maxFloor;
		}
		
		public int getMinFloor() {
			return minFloor;
		}
		
		//带参构造方法
		public Lift(int minFloor, int maxFloor){
			this.minFloor = minFloor;
			this.maxFloor = maxFloor;
			//默认在1楼
			this.curFloor = 1;
			this.curDirection = 1;
			state = 0;
			aim = (int)1e9;
		}
		
		//上楼
		public void upFloor() {
			curFloor++;
		}
		
		//下楼
		public void downFloor() {
			curFloor--;
		}
		
		//停止
		public void stopFloor() {
			state = 0;
		}
		
		//添加内部请求
		public void addRstIn(int floor) {
			int[] newArray = new int[rstIn.length+1];
			System.arraycopy(rstIn, 0, newArray, 0, rstIn.length);
			newArray[rstIn.length] = floor;
			rstIn = newArray;
		}
		
		//添加外部请求
		public void addRstOut(int floor, int direction) {
			int[][] newArray = new int[rstOut.length+1][2];
			System.arraycopy(rstOut, 0, newArray, 0, rstOut.length);
			newArray[rstOut.length][0] = floor;
			newArray[rstOut.length][1] = direction;
			rstOut = newArray;
		}
		
		//删除外部队列头部
		public void popRstOut() {
			if (rstOut.length == 0) { 
			        return; 
			}
			int[][] newArray = new int[rstOut.length-1][2];
			System.arraycopy(rstOut, 1, newArray, 0, rstOut.length-1);
			rstOut = newArray;
		}
		
		//删除内部队列头部
		public void popRstIn() {
			if (rstIn.length == 0) { 
		        return; 
		    }
			int[] newArray = new int[rstIn.length-1];
			System.arraycopy(rstIn, 1, newArray, 0, rstIn.length-1);
			rstIn = newArray;
		}
		
		//StringToInt
		public int toInt(String s) {
			int num = 0;
			for(int i = 0; i < s.length(); i++) {
				if(s.charAt(i) == '-') continue;
					num *= 10;
					num += s.charAt(i) - '0';
			}
			if(s.charAt(0) == '-') return -num;
			else return num;
		}
		
		//判断外部队列是否重复
//		public boolean reRstOut(int floor, int direction) {
//			for(int i = 0; i < rstOut.length; i++) {
//				if(rstOut[i][0] == floor && rstOut[i][1] == direction) {
//					return true;
//				}
//			}
//			return false;
//		}
		
		//判断内部队列是否重复
//		public boolean reRstIn(int floor) {
//			for(int i = 0; i < rstIn.length; i++) {
//				if(rstIn[i] == floor) {
//					return true;
//				}
//			}
//			return false;
//		}
		
		//输出当前楼层和状态
		private void pCurr() {
			System.out.println("Current Floor: " + curFloor + " Direction: " + (curDirection == 1 ? "UP" : (curDirection == -1 ? "DOWN" : "IDLE")));
		}
		
		//开门关门
		private void pDoor() {
			System.out.println("Open Door # Floor " + curFloor);
			System.out.println("Close Door");
		}
		
		//判断目标楼层
		private int checkAim() {
			//内部请求队列为空时返回外部请求队列头部楼层
			if(rstIn.length == 0) 
			{
				if(rstOut.length != 0) 
				{
					return rstOut[0][0];
				}
			}
			//外部请求队列为空时返回内部请求队列头部楼层
			if(rstOut.length == 0) 
			{
				if(rstOut.length == 0) 
				{
					return rstIn[0];
				}
			}
			//内部外部都存在请求时返回最近且方向相同的
			if(rstIn.length != 0 && rstOut.length != 0) 
			{
				
				int dstOut = Math.abs(rstOut[0][0] - curFloor), dstIn = Math.abs(rstIn[0] - curFloor);
				int drtIn = (rstIn[0] - curFloor) > 0 ? 1 : -1, drtOut;
				
//				if(curDirection == 0) return (dstIn <= dstOut) ? rstIn[0] : rstOut[0][0];
				
				//当前楼层存在外部请求
				if(rstOut[0][0] == curFloor) 
				{
					drtOut = rstOut[0][1];
				}
				else drtOut = (rstOut[0][0] - curFloor) > 0 ? 1 : -1;
				
				//外部请求to方向和go方向相同
				if(drtOut == rstOut[0][1]) 
				{
					//内外部请求在同一侧
					if(drtIn == drtOut) 
					{
						return (dstIn < dstOut) ? rstIn[0] : rstOut[0][0];
					}
					
					//在不同侧则返回当前方向侧请求
					if(drtIn == curDirection) 
					{
						return rstIn[0];
					}
					else return rstOut[0][0];
				}
				//外部请求to方向和go方向不同
				else 
				{
					//内外部请求在同一侧必定返回内部请求
					if(drtIn == drtOut) 
					{
						return rstIn[0];
					}
					//在不同侧则返回当前方向侧请求
					if(drtOut == curDirection) return rstOut[0][0];
					else return rstIn[0];
				}
			}
			return 0;
		}
		
		//运行电梯
		public void run() {
			
			//判断有无请求
			if(rstIn.length == 0 && rstOut.length == 0) {
				return;
			}
			
			//确定首个目标楼层
			aim = checkAim();
//			if(flag == 1) {
//				if(aim > 1) {
//					curDirection = 1;
//				}
//				else if(aim < 1) curDirection = -1;
//				else if(aim == 1) curDirection = 0;
//				flag = 0;
//			}
			pCurr();
			while(rstIn.length != 0 || rstOut.length != 0) {
				//前往目标楼层
				while(curFloor != aim) {
					if(aim > curFloor) {
						curDirection = 1;
						upFloor();
						pCurr();
					}
					if(aim < curFloor) {
						curDirection = -1;
						downFloor();
						pCurr();
					}
				}
				//到达目标楼层后弹出同楼层内部请求、弹出同楼层同方向外部楼层
				int flagout = 0, flagin = 0;
				
				
				if(rstOut.length > 0 && curFloor == rstOut[0][0]) {
					//内部请求队列为空时忽略方向直接弹出
					if(curDirection == rstOut[0][1] || rstIn.length == 0 || rstOut[0][1] == ((rstIn[0] - curFloor) == 0 ? 0 : (rstIn[0] - curFloor > 0 ? 1 : -1))) {
						popRstOut();
						flagout = 1;
					}
				}
				
				if(rstIn.length > 0 && curFloor == rstIn[0]) {
					popRstIn();
					flagin = 1;
				}
				
				
				//到达目标楼层后开关门
				if(flagin == 1 || flagout == 1)
				pDoor();
				
				//到达目标楼层后确定下一个目标楼层
				if(rstIn.length != 0 || rstOut.length != 0) aim = checkAim();
				
				
			}
		}
}

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		//输入匹配规则
		Pattern pattern = Pattern.compile("<(-?\\d+)(?:,(DOWN|UP))?>");
		Pattern end = Pattern.compile("(?i)end");
		//最大最小楼层输入
		int min, max;
		min = in.nextInt();
		max = in.nextInt();
		Lift lift = new Lift(min, max);
		
		while(true) 
		{
			String s = new String(in.next());
			Matcher endf = end.matcher(s);
			if(endf.find()) {
				break;
			}
			Matcher matcher = pattern.matcher(s);
			if(!matcher.find()) continue;
			int floor = lift.toInt(matcher.group(1));
			//判断请求楼层是否有效
			if(floor >= lift.getMinFloor() && floor <= lift.getMaxFloor()) 
			{
				//判断内部、外部请求
				if(matcher.group(2) != null) 
				{
					String direction = matcher.group(2);
					
					//判断是否重复 若重复不添加
					if(direction.equals("DOWN")) {
						if(/*!lift.reRstOut(floor, -1) &&*/ floor != min) {
							lift.addRstOut(floor, -1);
						}
					}
					else if(direction.equals("UP")) {
						
						if(/*!lift.reRstOut(floor,  1) &&*/ floor != max) {
							lift.addRstOut(floor,  1);
						}
					}
					
				}
				else {
					//判断是否重复 若重复不添加
//					if(!lift.reRstIn(floor)) {
						lift.addRstIn(floor);
//					}
				}
			}
		}
		
		lift.run();
	}
}

设计思路:
通过checkAim()方法判断目标楼层,当抵达目标楼层时判断请求队列是否出队, 然后判断下一目标楼层;
核心:
checkAim()方法的实现;对请求情况进行分类 分为
1.内外部都无请求 直接结束电梯运行
2.内部有请求外部无请求 直接前往相应楼层
3.内部无请求外部有请求 直接前往相应楼层
4.内外部都有请求;
情况四则仍需细分为以下几种情况:
A.前往外部请求的方向和外部请求前往的方向相同
a.当内部请求和外部请求在电梯当前所在楼层的同一侧时, 目标楼层应当为距离最近的;
b.当内部请求和外部请求在电梯当前所在楼层的不同侧时, 目标楼层应当为与当前方向相同的一侧;
B.前往外部请求的方向和外部请求前往的方向不同
a.当内部请求和外部请求在电梯当前所在楼层的同一侧时,目标楼层应当为内部请求楼层;
b.当内部请求和外部请求在电梯当前所在楼层的不同侧时, 目标楼层应当为与当前方向相同的一侧;

第二次代码分析
image
image
主要问题:
1.复杂度爆炸式增长
RequestQueue.run() 复杂度 16(27语句/5层嵌套/28次调用)
Main.main() 复杂度继续攀升至 13
2.注释质量恶化
注释行占比从22.3% 暴跌至10.4%
3.RequestQueue类异常膨胀
包含 12个方法,其中:
4个方法复杂度>3
reRstOut() 块深度5
checkAim() 调用21次方法
4.深度嵌套持续恶化
行403出现 7层嵌套块

第二次代码设计

点击查看代码
package pta06_3;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

enum State{
		STOPPED,MOVING
}

enum Direction{
		UP,DOWN,IDLE
}

class RequestQueue{
		//内部请求队列
		private int[] rstIn = new int[0];
		//外部请求队列	
		private int[][] rstOut = new int[0][2];
		
		public RequestQueue() {
			// TODO 自动生成的构造函数存根
		}
		
		public RequestQueue getQueueInstance(){
			return new RequestQueue();
		}
	
		public int[] getRstIn() {
			return rstIn;
		}
	
		public void setRstIn(int[] rstIn) {
			this.rstIn = rstIn;
		}
	
		public int[][] getRstOut() {
			return rstOut;
		}
	
		public void setRstOut(int[][] rstOut) {
			this.rstOut = rstOut;
		}
		
		//添加内部请求
		public void addRstIn(int floor) {
			int[] newArray = new int[rstIn.length+1];
			System.arraycopy(rstIn, 0, newArray, 0, rstIn.length);
			newArray[rstIn.length] = floor;
			rstIn = newArray;
		}
		
		//添加外部请求
		public void addRstOut(int floor, int direction) {
			int[][] newArray = new int[rstOut.length+1][2];
			System.arraycopy(rstOut, 0, newArray, 0, rstOut.length);
			newArray[rstOut.length][0] = floor;
			newArray[rstOut.length][1] = direction;
			rstOut = newArray;
		}
		
		//删除外部队列头部
		public void popRstOut() {
			if (rstOut.length == 0) { 
			        return; 
			}
			int[][] newArray = new int[rstOut.length-1][2];
			System.arraycopy(rstOut, 1, newArray, 0, rstOut.length-1);
			rstOut = newArray;
		}
	
		//删除内部队列头部
		public void popRstIn() {
			if (rstIn.length == 0) { 
		        return; 
		    }
			int[] newArray = new int[rstIn.length-1];
			System.arraycopy(rstIn, 1, newArray, 0, rstIn.length-1);
			rstIn = newArray;
		}

		//判断外部队列是否重复
		public boolean reRstOut(int floor, int direction) {
			if(rstOut.length > 0) {
				if(rstOut[rstOut.length-1][0] == floor && rstOut[rstOut.length-1][1] == direction) {
					return true;
				}
			}
			return false;
		}
				
		//判断内部队列是否重复
		public boolean reRstIn(int floor) {
			if(rstIn.length > 0) {
				if(rstIn[rstIn.length-1] == floor) {
					return true;
				}
			}
			return false;
		}	
		
}

class Controller{
	
		private Lift lift;
		private RequestQueue queue;
		
		public Lift getLift() {
			return lift;
		}

		public void setLift(Lift lift) {
			this.lift = lift;
		}

		public RequestQueue getQueue() {
			return queue;
		}

		public void setQueue(RequestQueue queue) {
			this.queue = queue;
		}
		
		public Controller() {
			
		}
		
		public Controller(Lift lift, RequestQueue queue) {
			this.lift = lift;
			this.queue = queue;
		}
		
		//开门关门
		private void pDoor() {
			System.out.println("Open Door # Floor " + lift.getCurFloor());
			System.out.println("Close Door");
		}
		
		//判断目标楼层
		private int checkAim() {
//			if(rstIn.length > 0 && rstOut.length > 0 && curDirection == Direction.IDLE) {
//				return (rstIn[0] > rstOut[0][0]) ? rstOut[0][0] : rstIn[0];
//			}
			//内部请求队列为空时返回外部请求队列头部楼层
			if(queue.getRstIn().length == 0) 
			{
				if(queue.getRstOut().length != 0) 
				{
					return queue.getRstOut()[0][0];
				}
			}
			//外部请求队列为空时返回内部请求队列头部楼层
			if(queue.getRstOut().length == 0) 
			{
				if(queue.getRstOut().length == 0) 
				{
					return queue.getRstIn()[0];
				}
			}
			//内部外部都存在请求时返回最近且方向相同的
			if(queue.getRstIn().length != 0 && queue.getRstOut().length != 0) 
			{
				int dstOut = Math.abs(queue.getRstOut()[0][0] - lift.getCurFloor()), dstIn = Math.abs(queue.getRstIn()[0] - lift.getCurFloor());
				Direction drtIn = (queue.getRstIn()[0] - lift.getCurFloor()) > 0 ? Direction.UP : Direction.DOWN, drtOut, teOut;
				
				if(queue.getRstOut()[0][1] == 1) {
					teOut = Direction.UP;
				}
				else teOut = Direction.DOWN;
				
				//当前楼层存在外部请求
				if(queue.getRstOut()[0][0] == lift.getCurFloor()) 
				{
					drtOut = teOut;
				}
				else drtOut = (queue.getRstOut()[0][0] - lift.getCurFloor()) > 0 ? Direction.UP : Direction.DOWN;
				
				//外部请求to方向和go方向相同
				if(drtOut == teOut) 
				{
					//内外部请求在同一侧
					if(drtIn == drtOut) 
					{
						return (dstIn < dstOut) ? queue.getRstIn()[0] : queue.getRstOut()[0][0];
					}
					
					//在不同侧则返回当前方向侧请求
					if(drtIn == lift.getCurDirection()) 
					{
						return queue.getRstIn()[0];
					}
					else return queue.getRstOut()[0][0];
				}
				//外部请求to方向和go方向不同
				else 
				{
					//内外部请求在同一侧必定返回内部请求
					if(drtIn == drtOut) 
					{
						return queue.getRstIn()[0];
					}
					//在不同侧则返回当前方向侧请求
					if(drtOut == lift.getCurDirection()) return queue.getRstOut()[0][0];
					else return queue.getRstIn()[0];
				}
			}
			return 0;
		}
		
		//运行电梯
		public void run() {
			//判断有无请求
			if(queue.getRstIn().length == 0 && queue.getRstOut().length == 0) {
				return;
			}
			
			//确定首个目标楼层
			lift.setAim(checkAim());
			pCurr();
			while(queue.getRstIn().length != 0 || queue.getRstOut().length != 0) {
				//前往目标楼层
				while(lift.getCurFloor() != lift.getAim()) {
					if(lift.getAim() > lift.getCurFloor()) {
						lift.setCurDirection(Direction.UP);
						lift.upFloor();
						pCurr();
					}
					if(lift.getAim() < lift.getCurFloor()) {
						lift.setCurDirection(Direction.DOWN);
						lift.downFloor();
						pCurr();
					}
				}
				//到达目标楼层后弹出同楼层内部请求、弹出同楼层同方向外部楼层
				int flagout = 0, flagin = 0;
				
				if(queue.getRstOut().length > 0 && lift.getCurFloor() == queue.getRstOut()[0][0]) {
					Direction teOut;
					if(queue.getRstOut()[0][1] == 1) {
						teOut = Direction.UP;
					}
					else teOut = Direction.DOWN;
				    //内部请求队列为空时忽略方向直接弹出
						if(lift.getCurDirection() == teOut || queue.getRstIn().length == 0 || queue.getRstOut()[0][1] == ((queue.getRstIn()[0] - lift.getCurFloor()) == 0 ? 0 : (queue.getRstIn()[0] - lift.getCurFloor() > 0 ? 1 : -1))) {
							queue.popRstOut();
							flagout = 1;
						}
					}
					
					if(queue.getRstIn().length > 0 && lift.getCurFloor() == queue.getRstIn()[0]) {
						queue.popRstIn();
						flagin = 1;
					}
					
					
					//到达目标楼层后开关门
					if(flagin == 1 || flagout == 1)
					pDoor();
					
					//到达目标楼层后确定下一个目标楼层
					if(queue.getRstIn().length != 0 || queue.getRstOut().length != 0) lift.setAim(checkAim());
					
					
				
			}
		}
		
		//输出当前楼层和状态
				private void pCurr() {
					Direction td;
					if(lift.getCurDirection() == Direction.IDLE) {
						td = Direction.UP;
					}
					else td = lift.getCurDirection();
					System.out.println("Current Floor: " + lift.getCurFloor() + " Direction: "  + td);
				}
}

class Lift{
		//最大楼层,最小楼层,当前楼层,当前方向,运行状态
		private int maxFloor, minFloor, curFloor, aim;
		public int getAim() {
			return aim;
		}

		public void setAim(int aim) {
			this.aim = aim;
		}



		private State state;
		private Direction curDirection;
		
		
		public Lift getLiftInstance(int minFloor, int maxFloor) {
			return new Lift(minFloor, maxFloor);
		}
		
		public int getCurFloor() {
			return curFloor;
		}

		public void setCurFloor(int curFloor) {
			this.curFloor = curFloor;
		}

		public State getState() {
			return state;
		}

		public void setState(State state) {
			this.state = state;
		}

		public Direction getCurDirection() {
			return curDirection;
		}

		public void setCurDirection(Direction curDirection) {
			this.curDirection = curDirection;
		}
		
		public int getMaxFloor() {
			return maxFloor;
		}
		
		public int getMinFloor() {
			return minFloor;
		}
		
		boolean isValidFloor(int floor) {
			if(floor >= minFloor && floor <= maxFloor) {
				return true;
			}
			else return false;
		}
		
		public Lift(){
					
				}
		
		//带参构造方法
		public Lift(int minFloor, int maxFloor){
			this.minFloor = minFloor;
			this.maxFloor = maxFloor;
			//默认在1楼
			this.curFloor = 1;
			this.curDirection = Direction.IDLE;
			state = State.STOPPED;
			aim = (int)1e9;
		}
		
		//上楼
		public void upFloor() {
			curFloor++;
		}
		
		//下楼
		public void downFloor() {
			curFloor--;
		}
		
		//停止
		public void stopFloor() {
			state = state.STOPPED;
		}
		
		
		
		//StringToInt
		public int toInt(String s) {
			int num = 0;
			for(int i = 0; i < s.length(); i++) {
				if(s.charAt(i) == '-') continue;
					num *= 10;
					num += s.charAt(i) - '0';
			}
			if(s.charAt(0) == '-') return -num;
			else return num;
		}
}

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		//输入匹配规则
		Pattern pattern = Pattern.compile("<(-?\\d+)(?:,(DOWN|UP))?>");
		Pattern end = Pattern.compile("(?i)end");
		//最大最小楼层输入
		int min, max;
		min = in.nextInt();
		max = in.nextInt();
		Lift lift = new Lift(min, max);
		RequestQueue queue = new RequestQueue();
		Controller controller = new Controller(lift, queue);
		while(true) 
		{
			String s = new String(in.next());
			Matcher endf = end.matcher(s);
			if(endf.find()) {
				break;
			}
			Matcher matcher = pattern.matcher(s);
			if(!matcher.find()) continue;
			int floor = lift.toInt(matcher.group(1));
			//判断请求楼层是否有效
			if(lift.isValidFloor(floor)) 
			{
				//判断内部、外部请求
				if(matcher.group(2) != null) 
				{
					String direction = matcher.group(2);
					
					//判断是否重复 若重复不添加
					if(direction.equals("DOWN")) {
						if(!controller.getQueue().reRstOut(floor, -1) && floor != min) {
							controller.getQueue().addRstOut(floor, -1);
						}
					}
					else if(direction.equals("UP")) {
						
						if(!controller.getQueue().reRstOut(floor,  1) && floor != max) {
							controller.getQueue().addRstOut(floor,  1);
						}
					}
					
				}
				else {
					//判断是否重复 若重复不添加
					if(!controller.getQueue().reRstIn(floor)) {
						controller.getQueue().addRstIn(floor);
					}
				}
			}
		}
		
		controller.run();
	}
}

设计思路:
本次主要从单类设计变为多类设计;
新增请求队列类、控制类、方向类、状态类;
对Lift类中的相关方法进行拆分, 确保单一职责原则;

第三次代码分析:
image
image
主要问题:
Main.main()复杂度16
最大方法调用次数27
平均块深度2.58

第三次代码设计

点击查看代码
package pta07_3;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

enum State{
		STOPPED,MOVING
}

enum Direction{
		UP,DOWN,IDLE
}

class RequestQueue{
		//内部请求队列
		private int[] rstIn = new int[0];
		//外部请求队列	
		private int[][] rstOut = new int[0][2];
		
		public RequestQueue() {
			// TODO 自动生成的构造函数存根
		}
		
		public RequestQueue getQueueInstance(){
			return new RequestQueue();
		}
	
		public int[] getRstIn() {
			return rstIn;
		}
	
		public void setRstIn(int[] rstIn) {
			this.rstIn = rstIn;
		}
	
		public int[][] getRstOut() {
			return rstOut;
		}
	
		public void setRstOut(int[][] rstOut) {
			this.rstOut = rstOut;
		}
		
		//添加内部请求
		public void addRstIn(int floor) {
			int[] newArray = new int[rstIn.length+1];
			System.arraycopy(rstIn, 0, newArray, 0, rstIn.length);
			newArray[rstIn.length] = floor;
			rstIn = newArray;
		}
		
		//添加外部请求
		public void addRstOut(int floor, int direction) {
			int[][] newArray = new int[rstOut.length+1][2];
			System.arraycopy(rstOut, 0, newArray, 0, rstOut.length);
			newArray[rstOut.length][0] = floor;
			newArray[rstOut.length][1] = direction;
			rstOut = newArray;
		}
		
		//删除外部队列头部
		public void popRstOut() {
			if (rstOut.length == 0) { 
			        return; 
			}
			int[][] newArray = new int[rstOut.length-1][2];
			System.arraycopy(rstOut, 1, newArray, 0, rstOut.length-1);
			rstOut = newArray;
		}
	
		//删除内部队列头部
		public void popRstIn() {
			if (rstIn.length == 0) { 
		        return; 
		    }
			int[] newArray = new int[rstIn.length-1];
			System.arraycopy(rstIn, 1, newArray, 0, rstIn.length-1);
			rstIn = newArray;
		}

		//判断外部队列是否重复
		public boolean reRstOut(int floor, int direction) {
			if(rstOut.length > 0) {
				if(rstOut[rstOut.length-1][0] == floor && rstOut[rstOut.length-1][1] == direction) {
					return true;
				}
			}
			return false;
		}
				
		//判断内部队列是否重复
		public boolean reRstIn(int floor) {
			if(rstIn.length > 0) {
				if(rstIn[rstIn.length-1] == floor) {
					return true;
				}
			}
			return false;
		}	
		
}

class Controller{
	
		private Lift lift;
		private RequestQueue queue;
		
		public Lift getLift() {
			return lift;
		}

		public void setLift(Lift lift) {
			this.lift = lift;
		}

		public RequestQueue getQueue() {
			return queue;
		}

		public void setQueue(RequestQueue queue) {
			this.queue = queue;
		}
		
		public Controller() {
			
		}
		
		public Controller(Lift lift, RequestQueue queue) {
			this.lift = lift;
			this.queue = queue;
		}
		
		//开门关门
		private void pDoor() {
			System.out.println("Open Door # Floor " + lift.getCurFloor());
			System.out.println("Close Door");
		}
		
		//判断目标楼层
		private int checkAim() {
//			if(rstIn.length > 0 && rstOut.length > 0 && curDirection == Direction.IDLE) {
//				return (rstIn[0] > rstOut[0][0]) ? rstOut[0][0] : rstIn[0];
//			}
			//内部请求队列为空时返回外部请求队列头部楼层
			if(queue.getRstIn().length == 0) 
			{
				if(queue.getRstOut().length != 0) 
				{
					return queue.getRstOut()[0][0];
				}
			}
			//外部请求队列为空时返回内部请求队列头部楼层
			if(queue.getRstOut().length == 0) 
			{
				if(queue.getRstOut().length == 0) 
				{
					return queue.getRstIn()[0];
				}
			}
			//内部外部都存在请求时返回最近且方向相同的
			if(queue.getRstIn().length != 0 && queue.getRstOut().length != 0) 
			{
				int dstOut = Math.abs(queue.getRstOut()[0][0] - lift.getCurFloor()), dstIn = Math.abs(queue.getRstIn()[0] - lift.getCurFloor());
				Direction drtIn = (queue.getRstIn()[0] - lift.getCurFloor()) > 0 ? Direction.UP : Direction.DOWN, drtOut, teOut;
				
				if(queue.getRstOut()[0][1] == 1) {
					teOut = Direction.UP;
				}
				else teOut = Direction.DOWN;
				
				//当前楼层存在外部请求
				if(queue.getRstOut()[0][0] == lift.getCurFloor()) 
				{
					drtOut = teOut;
				}
				else drtOut = (queue.getRstOut()[0][0] - lift.getCurFloor()) > 0 ? Direction.UP : Direction.DOWN;
				
				//外部请求to方向和go方向相同
				if(drtOut == teOut) 
				{
					//内外部请求在同一侧
					if(drtIn == drtOut) 
					{
						return (dstIn < dstOut) ? queue.getRstIn()[0] : queue.getRstOut()[0][0];
					}
					
					//在不同侧则返回当前方向侧请求
					if(drtIn == lift.getCurDirection()) 
					{
						return queue.getRstIn()[0];
					}
					else return queue.getRstOut()[0][0];
				}
				//外部请求to方向和go方向不同
				else 
				{
					//内外部请求在同一侧必定返回内部请求
					if(drtIn == drtOut) 
					{
						return queue.getRstIn()[0];
					}
					//在不同侧则返回当前方向侧请求
					if(drtOut == lift.getCurDirection()) return queue.getRstOut()[0][0];
					else return queue.getRstIn()[0];
				}
			}
			return 0;
		}
		
		//运行电梯
		public void run() {
			//判断有无请求
			if(queue.getRstIn().length == 0 && queue.getRstOut().length == 0) {
				return;
			}
			
			//确定首个目标楼层
			lift.setAim(checkAim());
			pCurr();
			while(queue.getRstIn().length != 0 || queue.getRstOut().length != 0) {
				//前往目标楼层
				while(lift.getCurFloor() != lift.getAim()) {
					if(lift.getAim() > lift.getCurFloor()) {
						lift.setCurDirection(Direction.UP);
						lift.upFloor();
						pCurr();
					}
					if(lift.getAim() < lift.getCurFloor()) {
						lift.setCurDirection(Direction.DOWN);
						lift.downFloor();
						pCurr();
					}
				}
				//到达目标楼层后弹出同楼层内部请求、弹出同楼层同方向外部楼层
				int flagout = 0, flagin = 0;
				
				if(queue.getRstOut().length > 0 && lift.getCurFloor() == queue.getRstOut()[0][0]) {
					Direction teOut;
					if(queue.getRstOut()[0][1] == 1) {
						teOut = Direction.UP;
					}
					else teOut = Direction.DOWN;
				    //内部请求队列为空时忽略方向直接弹出
						if(lift.getCurDirection() == teOut || queue.getRstIn().length == 0 || queue.getRstOut()[0][1] == ((queue.getRstIn()[0] - lift.getCurFloor()) == 0 ? 0 : (queue.getRstIn()[0] - lift.getCurFloor() > 0 ? 1 : -1))) {
							queue.popRstOut();
							flagout = 1;
						}
					}
					
					if(queue.getRstIn().length > 0 && lift.getCurFloor() == queue.getRstIn()[0]) {
						queue.popRstIn();
						flagin = 1;
					}
					
					
					//到达目标楼层后开关门
					if(flagin == 1 || flagout == 1)
					pDoor();
					
					//到达目标楼层后确定下一个目标楼层
					if(queue.getRstIn().length != 0 || queue.getRstOut().length != 0) lift.setAim(checkAim());
					
					
				
			}
		}
		
		//输出当前楼层和状态
				private void pCurr() {
					Direction td;
					if(lift.getCurDirection() == Direction.IDLE) {
						td = Direction.UP;
					}
					else td = lift.getCurDirection();
					System.out.println("Current Floor: " + lift.getCurFloor() + " Direction: "  + td);
				}
}

class Lift{
		//最大楼层,最小楼层,当前楼层,当前方向,运行状态
		private int maxFloor, minFloor, curFloor, aim;
		public int getAim() {
			return aim;
		}

		public void setAim(int aim) {
			this.aim = aim;
		}



		private State state;
		private Direction curDirection;
		
		
		public Lift getLiftInstance(int minFloor, int maxFloor) {
			return new Lift(minFloor, maxFloor);
		}
		
		public int getCurFloor() {
			return curFloor;
		}

		public void setCurFloor(int curFloor) {
			this.curFloor = curFloor;
		}

		public State getState() {
			return state;
		}

		public void setState(State state) {
			this.state = state;
		}

		public Direction getCurDirection() {
			return curDirection;
		}

		public void setCurDirection(Direction curDirection) {
			this.curDirection = curDirection;
		}
		
		public int getMaxFloor() {
			return maxFloor;
		}
		
		public int getMinFloor() {
			return minFloor;
		}
		
		boolean isValidFloor(int floor) {
			if(floor >= minFloor && floor <= maxFloor) {
				return true;
			}
			else return false;
		}
		
		public Lift(){
					
				}
		
		//带参构造方法
		public Lift(int minFloor, int maxFloor){
			this.minFloor = minFloor;
			this.maxFloor = maxFloor;
			//默认在1楼
			this.curFloor = 1;
			this.curDirection = Direction.IDLE;
			state = State.STOPPED;
			aim = (int)1e9;
		}
		
		//上楼
		public void upFloor() {
			curFloor++;
		}
		
		//下楼
		public void downFloor() {
			curFloor--;
		}
		
		//停止
		public void stopFloor() {
			state = state.STOPPED;
		}
		
		
		
		//StringToInt
		public int toInt(String s) {
			int num = 0;
			for(int i = 0; i < s.length(); i++) {
				if(s.charAt(i) == '-') continue;
					num *= 10;
					num += s.charAt(i) - '0';
			}
			if(s.charAt(0) == '-') return -num;
			else return num;
		}
}

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		//输入匹配规则
		Pattern pattern = Pattern.compile("<(-?\\d+)(?:,(\\d+))?>");
		Pattern end = Pattern.compile("(?i)end");
		//最大最小楼层输入
		int min, max;
		min = in.nextInt();
		max = in.nextInt();
		Lift lift = new Lift(min, max);
		RequestQueue queue = new RequestQueue();
		Controller controller = new Controller(lift, queue);
		int[] a = new int[100000];
		int cnt = 0;
		while(true) 
		{
			String s = new String(in.next());
			Matcher endf = end.matcher(s);
			if(endf.find()) {
				break;
			}
			Matcher matcher = pattern.matcher(s);
			if(!matcher.find()) continue;
			int floor = lift.toInt(matcher.group(1));
			//判断请求楼层是否有效
			if(lift.isValidFloor(floor)) 
			{
				//判断内部、外部请求
				if(matcher.group(2) != null) 
				{
					int tofloor = lift.toInt(matcher.group(2));
					String direction ;
					
					if(tofloor >= floor) {
						direction = "UP";
					}
					else direction = "DOWN";
					
					//判断是否重复 若重复不添加
					if(direction.equals("DOWN")) {
						if(!controller.getQueue().reRstOut(floor, -1) && floor != min) {
							controller.getQueue().addRstOut(floor, -1);
							a[cnt++] = tofloor;
						}
					}
					else if(direction.equals("UP")) {
						if(!controller.getQueue().reRstOut(floor,  1) && floor != max) {
							controller.getQueue().addRstOut(floor,  1);
							a[cnt++] = tofloor;
						}
					}
					
				}
				else {
					//判断是否重复 若重复不添加
					if(!controller.getQueue().reRstIn(floor)) {
						controller.getQueue().addRstIn(floor);
					}
				}
			}
		}
		for(int i = 0; i < cnt; i++) {
			controller.getQueue().addRstIn(a[i]);
		}
		controller.run();
	}
}

设计思路:
只需对主函数中输入部分进行修改, 将外部队列的目标楼层在读取完内部队列后按输入顺序加入内部队列队尾即可;


踩坑心得:

1.end不区分大小写, 未做特判导致非零返回
2.最开始未考虑边界楼层,当电梯达到最高楼层方向向上时和达到最低楼层方向向下时出现死循环
3.最初只考虑以方向为判断依据,一股脑向当前方向走,对开关门和方向改变的判断情况不够准确
4.被文档误导以为要对所有请求去重,导致一直无法通过


改进建议:

1.类设计不够合理,耦合度高,功能不够单一,可复用性,可移植性差;
2.注释覆盖率低, 许多地方没有注释;
3.分支结构过多, 可读性差, 可维护性低;


总结:

1.希望能把题目出清楚, 解释文档给准确, 不要白白浪费学生时间去玩猜猜看
2.了解到了类的设计原则,和实际软件工程实现的难点;
3.对面向对象有了更深刻的认知与了解;
4.逻辑思维能力得到了提升;


posted @ 2025-04-19 22:27  郑风  阅读(33)  评论(0)    收藏  举报