•问题描述
设 停车场 是一个可停放 n 辆车 的狭长通道,且 只有一个大门 可供汽车 进出 。在停车场内,汽车按 到达的先后 次序,由北向南依次排列(假设大门在最南端)。若停车场内已 停满 n 辆车,则后来的汽车需在门外的 便道 上等候,当有车 开走 时,便道上的 第一辆车即可开入 。当停车场内某辆车要 离开 时,在 它之后进入 的车辆必须 先退出 停车场为它让路,待该辆车开出大门后,其他车辆再按原次序返回车场。每辆车离开停车场时,应按其停留时间的长短 交费 (在便道上停留的时间不收费)。
•问题分析
• 停车场
1 )停车场是一个可停放 n 辆车的狭长通道;
(线性结构)
2 )只有一个大门可供汽车进出;
(受限的线性结构——栈)
3 )当停车场内某辆车要离开时,在它之后进入的车辆必须先退出停车场为它让道,待该辆车开出大门后,其他车辆再按原次序返回车场。
(另一个栈,大小?)
•便道
便道是一个狭长通道,且等待车辆数不确定;
(线性结构)
便道中的车辆以排队方式 先进先出 ;
(队列)
当有车到达时,若停车场已满或便道上有等待车辆,则进入便道排队等待;
(入队)
当停车场有车出场时,便道中排在最前的车辆先进入停车场。
(出队,并进栈)
•收费
1 )车辆离开按在停车场停留时间的长短交费
2 )在便道上停留的时间不收费
•实现代码
package 实验2;
//登记车辆信息
public class Car
{
public String CarNum;//车牌号码
public String Arrive;//存放车辆到达时间
public String Leave;//存放车辆离开时间
public long ArriveTime;//获取车辆到达时间
public long LeaveTime;//获取车辆离开时间
//设置车牌号码
public void setCarNum(String CarNum)
{
this.CarNum=CarNum;
Arrive=Timeset.getTimeStamp(ArriveTime);//通过时间戳获取时间
}
//设置车辆到达时间和车辆到达状态
public void setArriveTime(long ArriveTime)
{
this.ArriveTime=ArriveTime;//设置车辆到达的时间
// Arrive=Timeset.getTimeStamp(ArriveTime);//通过时间戳获取时间
}
//设置车辆离开时间和车辆离开状态
public void setLeaveTime(long LeaveTime)
{
this.LeaveTime=LeaveTime;//设置车辆离开的时间
Leave=Timeset.getTimeStamp(LeaveTime);//通过时间戳获取时间
}
//返回车牌号码
public String getCarNum()
{
return CarNum;
}
public int getTime(){
return (int)((LeaveTime-ArriveTime)*10)/60000;
}
public String toString()
{
return "Car{" +
"carNo='" + CarNum + '\'' +
", arrive='" + Arrive + '\'' +
", leave='" + Leave + '\'' +
'}';
}
}
package 实验2;
//汽车节点类,用于链队列中
public class CarNode {
public Car car;// 汽车
public CarNode next;// 下一个节点
public CarNode()
{
this(null,null);
}
public CarNode(Car car)
{
this(car,null);
}
public CarNode(Car car,CarNode next)
{
this.car=car;
this.next=next;
}
}
package 实验2;
//1,2,3,分别代表查询的位置,0是没问题
public class CarPark
{
CarQueue pavement=new CarQueue();//便道(链式队列)
CarStack transitstation=new CarStack();//中转区(顺序栈)
CarStack parking=new CarStack();//停车场(顺序栈)
double price=3;//停车的单位时间费用为3元
//停车场业务
/**
* 功能:汽车驶入。 将carNo车牌的汽车驶入,如果停车场有车位则进入停车场,设定入场时间,否则在便道等待进入
* 参数:
* carNo -- 车牌信息
* 返回值:成功与否
*/
//当有车到达时,若停车场已满或便道上有等待车辆,则进入便道排队等待(入队)
public boolean arrival(String CarNum)
{
//创建一个对象代表刚进来的车
Car car=new Car();
//设置进来车辆的车牌号
car.setCarNum(CarNum);
//先看看停车场有没有空位置,如果停车场没有位置了,那么这个车直接进入便道等候
if(parking.isFull())
{
pavement.offer(car);//刚来的车进去便道,要提示已经去了便道。
System.out.println("由于停车场已经满了,车牌号为"+CarNum+"的车辆已经进入便道等待。");
}
//如果还有停车位,还要再看看便道上有没有车在等待
else
{
//如果便道上还有其他车已经在等待,那么就便道上的车先进去停车,刚到的这个车要到便道上面等候
if(!pavement.isEmpty())
{
parking.push((Car) pavement.poll());//便道上的车进入停车场
pavement.offer(car);//刚来的车进入便道等候
}
//如果便道上是空的,那么这个车就可以直接进去停车场了
else
{
car.setArriveTime(System.currentTimeMillis());//目标车辆进车库,需要记下它的时间
}
}
return parking.push(car);//刚来的车进去停车场,返回一个布尔型,验证它有没有成功进入车库
}
/**
* 功能: 骑车驶离。将carNo车牌的汽车驶离停车场,设定离开时间,同时便道汽车进入停车场
* 参数:
* carNo -- 车牌信息
* 返回值:离开汽车
*/
//当停车场有车出场时,便道中排在最前的车辆先进入停车场(出队,并进栈)
public Car leave(String CarNum)
{
if(parking.isEmpty()) //如果车库是空的,就返回空值
{
return null;
}
//创建一个对象代表要出去的车,为空,最后赋值
Car leaveCar=null;
//先看看停车场是不是只有它自己一辆车,如果不止一辆车,在它之后进入的车辆必须先退出停车场为它让路,进入中转区
//如果停车场里面只有它自己一辆车,它就可以直接自己出来,并记录出来的时间
while(parking.length()>=1)
{
//创建对象代表退出停车场进入中转区的车
Car carTransform=(Car) parking.pop();
//用TransformNum来代表进去中转区的车的车牌号码
String TransformNum=carTransform.getCarNum();
//判断正从停车场出来的车的车牌号是不是和要离开的车的车牌号一样,如果一样,这辆车就是目标出来车辆,要记录它离开的时间
if(TransformNum.equals(CarNum))
{
carTransform.setLeaveTime(System.currentTimeMillis());
leaveCar=carTransform;
}
//如果不一样,这个车不是目标车辆,不必记录时间,直接移到中转区就好
else
{
transitstation.push(carTransform);//从停车场出来的车进去中转区
}
}
//待目标辆车开出大门后,其他车辆再按原次序返回车场
while(!transitstation.isEmpty())
{
parking.push(transitstation.pop());//从中转区出来的车进去停车场
}
return leaveCar;
}
/**
* 功能: 费用计算。根据车辆的出入时间,计算费用及停车时长
* 参数:
* car -- 车辆信息
* 返回值:停车费用
* @return
*/
//车辆离开后,要计算它的停车费用
public double charging(Car car)
{
return car.getTime()*price;
}
// 显示所有入库车辆信息
public void showPark()
{
if(parking.isEmpty())
{
//当停车场没有车辆在等的时候,就提示没有车子在停车场
System.out.println("停车场暂时没有停放车辆!");
}
//当停车场有车辆的时候,就输出它们的信息
else
{
System.out.println("入场车辆的信息为:");
parking.display();
}
}
// 显示所有在便道上等待信息
public void showWaiting()
{
if(pavement.isEmpty())
{
//当便道上没有车辆在等的时候,就提示没有车子在等待
System.out.println("便道上暂时没有车辆在等待!");
}
else
{
//当便道上有车辆在等待的时候,就输出它们的信息
System.out.println("正在便道上等待的车辆有:");
pavement.display();
}
}
//查找车辆是否在场
public void searchCar(String carNo)
{
int flagInParking = searchParking(carNo);//查找车在不在停车场
int flagInpavement = searchPavement(carNo);//查找车在不在便道
if (flagInParking == 1)
{
System.out.println("车牌为" + carNo + "在停车场内。");
}
else if (flagInpavement == 1)
{
System.out.println("车牌为" + carNo + "在便道内。");
}
else
{
System.out.println("不好意思!找不到此车!");
}
}
//查找便道上的车辆
public int searchPavement(String CarNum){
//停车场查找不到,就查找便道,查到了就提示该车辆在便道,并退出查找
CarQueue tmpQueue=new CarQueue();//中间队列,存放取出来的车
int flag=0;
while(!pavement.isEmpty())
{
//用searchPavement存放便道的车辆车牌号码
Car searchPavement=((Car) pavement.poll());
if(searchPavement.getCarNum().equals(CarNum))
{//在便道上查找到车辆
flag=1;
}
tmpQueue.offer(searchPavement); //停进中间队列
}
while (!tmpQueue.isEmpty())//当中间队列不为空的时候,要把取出来的车子都放回去
{
pavement.offer((Car) tmpQueue.poll());
}
return flag;
}
//查找停车场上的车辆
public int searchParking(String CarNum)
{
int flag=0;
//从停车场开始查找,查到了就提示该车辆在停车场,并退出查找
while(!parking.isEmpty())
{
//用searchPark存放刚刚从停车场中取出来的车辆
Car searchPark=parking.pop();
if(searchPark.getCarNum().equals(CarNum))
{
//车牌号是CarNum的车辆现在在停车场!
flag=1;
}
//取出来的车辆不是目标车辆,就把它先放进中转区里面
transitstation.push(searchPark);
}
while (!transitstation.isEmpty())
{//查找完毕,当中转区非空的时候,要把里面的车辆全都放回去停车场
parking.push(transitstation.pop());
}
return flag;
}
//离开便道,这个跟查询便道的方法一样,要先确定有没有这辆车
public Car leavepavement(String carNo)
{
Car leaveCar = null; //用来指向我们想要离开的车辆
CarQueue searchQueue=new CarQueue();//建一个新的队列作为中间队列
while(!pavement.isEmpty())//如果便道不为空
{
Car pavementTopCar=(Car) pavement.poll();//便道上第一个车给取出来
if(carNo.equals(pavementTopCar.getCarNum()))//看看是不是目标车辆
{//如果是,就取出,并且提示已经离开了便道
leaveCar=pavementTopCar;
System.out.println("便道上车牌号为"+leaveCar.getCarNum()+"车辆已离开!");
}
else //如果不是目标车辆,就把它放进去中间队列里面
{
searchQueue.offer( pavementTopCar);
}
}
//最后查找完毕,要把取出来放在中间队列里的车放回去便道
while (!searchQueue.isEmpty()){
pavement.offer((Car) searchQueue.poll());
}
return leaveCar;
}
}
package 实验2;
//设计链队数据结构及其基本操作
public class CarQueue {
private CarNode front;//队首指针
private CarNode rear;//队尾指针
//链队列类的构造函数
public CarQueue()
{
front=rear=null;
}
//队列置空
public void clear()
{
front=rear=null;
}
//车辆队列判空
public boolean isEmpty()
{
return front==null;
}
//求队列长度
public int length()
{
CarNode p=front;
int length=0;
while(p!=null)
{
p=p.next;//指针下移
++length;//计数器+1
}
return length;
}
//取出队首元素
public Object peek()
{
if(front!=null)//队列非空
return front.car;//返回队首结点的数据域值
else
return null;
}
//车辆入队
public boolean offer(Car car)
{
CarNode p=new CarNode(car);//初始化新结点
if(front!=null)//队列非空
{
rear.next=p;
rear=p;//改变队尾位置
}
else
{
front=rear=p;
}
return true;
}
//车辆出队
public Object poll()
{
if(front!=null)//队列非空
{
CarNode p=front;//p指向队首结点
front=front.next;//队首结点出列
if(p==rear)//被删除的结点是队尾结点时
rear=null;
return p.car;//返回队首结点的数据域值
}
else
return null;
}
//输出队列中的所有数据元素(从头到尾)
public void display()
{
CarNode p=front;
while(p!=null)
{
System.out.println(p.car+",");
p=p.next;
}
}
}
package 实验2;
//设计顺序栈数据结构及其基本操作
public class CarStack {
private Car[] Carstack;//对象数组
private int top;//在非空栈中,top始终指向栈顶元素的下一个存储位置栈
private static int MAXSIZE=3;
//栈的构造函数,构造一个存储空间为MAXSIZE的空
public CarStack()
{
top=0;
Carstack = new Car[MAXSIZE];
}
//栈置空
public void clear()
{
top=0;
}
//判空
public boolean isEmpty()
{
return top==0;
}
//判满
public boolean isFull()
{
return top==MAXSIZE;
}
//求栈中元素的个数
public int length()
{
return top;
}
//取栈顶元素
public Object peek()
{
if(!isEmpty())
return Carstack[top-1];
else
return null;
}
//车辆进栈
public boolean push(Car car)
{
if(top >= MAXSIZE)
return false;//车子没有成功停进停车场,返回false
else
Carstack[top++] = car;
return true;//车子成功停进停车场,返回true
}
//车辆出栈
public Car pop()
{
if(isEmpty())
return null;
else
return Carstack[--top];
}
//输出栈中的所有元素
public void display()
{
if(isEmpty())
{
System.out.println("停车场暂时没有车!");
}
else
{
for(int i=top-1;i>=0;i--)
System.out.println(Carstack[i].toString()+" ");
}
}
}
package 实验2;
import java.text.DecimalFormat;
import java.util.Scanner;
public class Test
{
// 操作菜单
public static void menu()
{
System.out.println("\n §※§※§※§※§※§ 欢迎使用停车场系统.§※§※§※§※§※§\t\n");
System.out.println("\t※◎※◎※◎※◎ 1. 车辆到达登记.※◎※◎※◎※◎\t");
System.out.println("\t※◎※◎※◎※◎ 2. 车辆离开登记.※◎※◎※◎※◎\t");
System.out.println("\t※◎※◎※◎※◎ 3. 显示车辆信息.※◎※◎※◎※◎\t");
System.out.println("\t※◎※◎※◎※◎ 4. 退出系统※◎※◎※◎※◎\t");
System.out.println("\n\t请选择:\t");
}
public static void main(String[] args)
{
CarPark carPark = new CarPark();
Scanner scanner = new Scanner(System.in);
String carNo;
while(true) {
menu();
int item = -1;
while (true) {
item = scanner.nextInt();
if(item>0 && item <5)
break;
System.out.println("\n 输入有误,请重新选择: 1~4: ");
}
switch(item)
{
//代号为1,//车辆到达登记,提示并输入车牌号并进场
case 1:
System.out.println("请输入车牌号码:");
carNo=scanner.next();//要先查找是不是已经有这辆车了,车牌号码不能重复
if (carPark.searchParking(carNo)!=1 && carPark.searchPavement(carNo)!=1)
{
if (carPark.arrival(carNo))
{
System.out.println("车牌号为"+carNo+"的车辆停车成功,现在已经进入停车场!");
}
}
else
{
System.out.println("抱歉!该车辆已经存在了,请重新输入车牌号。");
}
break;
//代号为2,车辆离开登记,提示输入车牌号、输出停车时长以及费用
case 2:
System.out.println("请输入车牌号码:");
carNo=scanner.next();
if (carPark.searchParking(carNo)==1)//出来之前,要先看看车子有没有在停车场里面,如果在
{
Car car=carPark.leave(carNo);//接受返回值
long time = car.getTime();
DecimalFormat df = new DecimalFormat("#.00");
String fee = df.format(carPark.charging(car));
System.out.println("离开车辆的车牌号为:"+carNo);
System.out.println("该车到达时间为:"+car.Arrive+" 离开时间为:"+car.Leave+" 停车时长为:"+time+" 分钟,停车费用共计:"+fee+"元。");
}
else if (carPark.searchPavement(carNo)==1)//如果停车场上没有,就在便道上找,如果找到了这辆车
{//那么就把这辆车从便道上取出来,使它直接从便道上离开
Car car = carPark.leavepavement(carNo);
}
else //否则提示便道上也没有这辆车,那就提示没车
{
System.out.println("抱歉!停车场和便道内都没有找到车牌为" + carNo + "的车。");
}
break;
//代号为3,显示车辆信息
case 3:
carPark.showPark();
carPark.showWaiting();
break;
//代号为4,退出系统
case 4:
System.exit(0);
//代号为5,查找车辆
case 5:
System.out.println("请输入车牌号码:");
Scanner scanner3 = new Scanner(System.in);
carNo=scanner3.next();
carPark.searchCar(carNo);
break;
}
}
}
}
package 实验2;
import java.text.SimpleDateFormat;
import java.util.Date;
//计时不会写,去CSDN找到了对应的写法,网址为:
public class Timeset
{
//获取时间戳
public static String getTimeStamp(long times)
{
Date date = new Date();
times = date.getTime();
return getFormatDate();
}
//获取格式化的时间
public static String getFormatDate()
{
Date date = new Date();
long times = date.getTime();//时间戳
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(date);
return dateString;
}
}
运行结果: