一、问题描述
设停车场是一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在停车场的最北端),若停车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。
二、需求分析
以栈 AStack parking1(maxSize)模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码以及到达或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车辆离去,则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。栈以顺序结构实现,队列以链表结构实现。
设n=2,输入数据为:(‘A’,1,5),(‘A’,2,10),(‘D’,1,15),(‘A’,3,20),(‘A’,4,25),(‘A’5,30),(‘D’,2,35),(‘D’,4,40),(‘E’,0,0)。其中:‘A’表示到达(arrival);‘D’表示离去(departure);‘E’表示输入结束(end)。
需另设一个栈 AStack parking2(maxSize),临时停放为给要离去的汽车让路而从停车场退出来的汽车,也用顺序存储结构实现。输入数据按到达或离去的时刻有序。栈中每个元素表示一辆汽车,包含两个数据项:汽车的牌照号码和进入停车场的时刻。
第一行提示输入停车场最大容纳车辆数目maxSize和,和停车每小时费用money,接下来输入车得离开到来D/A,和车牌号(整形数据),和车的离开到来时间(整型数据),中间以空格相间断,每输入一辆车的信息就会输出该车的停车位置或停车时间和停车费用,如数据不符合格式则会提示错误重新输入,直到输入结束标志“ E 0 0 ”。若是输出离开车辆的信息而该车并未在停车场就会输出“该车不在本停车场,请重新输入”,则重新输入该车的离开信息。
三、概要设计
1.设定栈的抽象数据类型定义为:
ADT Astack{
数据对象:D={ai|ai∈charset,i=1,2,……,n,n≥0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2……,n}
基本操作:
Astack(size)
操作结果:初始化一个大小为size大小的空栈
push(node)
初始条件:栈S已存在。
操作结果:节点进栈。
pop(&node)
初始条件:栈S已存在。
操作结果:节点出栈。
length()
初始条件:栈S已存在。
操作结果:返回栈S的长度。
topValue(&node)
初始条件:栈S已存在。
操作结果:若S为空栈,则返回FALSE。反之,返回上一个节点的位置。
}ADT Atack
2. 设定队列的抽象数据类型
ADT AQueue{
基本操作:
AQueue(size)
操作结果:初始化一个长度为size的队列。
enqueue(node)
初始条件:队列已存在。
操作结果:将节点进队列。
dequeue(&node)
初始条件:队列已存在。
操作结果:将节点从队列中取出。
length()
初始条件:队列已存在。
操作结果:返回队列的长度。
3. 本程序包含三个模块
1)主程序模块
void main( )
{ 初始化
do{
接受命令;
处理命令;
}while(命令!=“退出”);
}
2)栈模块----实现栈抽象数据类型
3)队列模块----实现队列抽象数据类型
各模块之间的调用关系如下:
4.车辆离开停车场的伪码算法:
int output(AStack &parking1, AStack &parking2, AQueue &wait, node s)
{ //出停车场
node temp;
int time;
while (停车场不为空,且要出的车的车牌号和停车场最前面的车的车牌号不相同)
{
把车停到临时停放车场;
}
if (找到要出来的车)
{
把车开出来;
停放时间=离开时间-到来时间;
}
Else//车不在停车场内
time = -1;标记时间
while (暂时停放车场内有车)
把车依次从前到后开到停车场内;
if (有车离开停车场)
{
if (便道上有车)
{
将车开出便道;
把车开进停车场;
}
}
返回停放时间;
}
parkTime = output(parking1, parking2, wait, s);
if (parkTime == -1)
该车不在本停车场,请重新输入!;
else
停车时间为: 应缴纳费用为:
四、详细设计
1车辆类
class node{
public:
int 车牌号;
int 到达离开时间;
}
2.停车场/临时停放点的类
class AStack : public node
{ //栈类
private:
int size;//栈的大小
int top;//栈的顶元素位置大小
node *listArray;//节点类型,指针类型
AStack(int sz)
//根据用户输入的size大小初始化栈
~AStack() { delete[] listArray; };
bool push(node a)
//把节点放入栈顶,放入成功返回True,否则返回False
bool pop(node &a)
//如果栈元素不为空将栈顶元素出栈
int length()
//返回栈顶元素的位置
bool topValue(node &a)
//返回栈顶元素
}
3.便道类
class AQueue : public node
{ //队列类
private:
int size;//队列大小
int front;//队列第一个元素的位置
int rear;//队列尾元素的位置
node *listArray;//队列节点类型
AQueue(int sz)
//根据用户输入的size值初始化队列大小
~AQueue() { delete[] listArray; };
bool enqueue(node it)
//将元素放入队列,放入成功返回True,否则返回False
bool dequeue(node &it)
//将元素从队列取出,成功返回True,反之返回False
int length()
//返回队列的长度
};
int output(AStack &parking1, AStack &parking2, AQueue &wait, node s)
{ //出停车场
node temp;
int time;
while (停车场不为空,且要出的车的车牌号和停车场最前面的车的车牌号不相同)
{
把车停到临时停放车场;
}
if (找到要出来的车)
{
把车开出来;
停放时间=离开时间-到来时间;
}
Else//车不在停车场内
time = -1;标记时间
while (暂时停放车场内有车)
把车依次从前到后开到停车场内;
if (有车离开停车场)
{
if (便道上有车)
{
将车开出便道;
把车开进停车场;
}
}
返回停放时间;
}
parkTime = output(parking1, parking2, wait, s);
if (parkTime == -1)
该车不在本停车场,请重新输入!;
else
停车时间为: 应缴纳费用为:
五、功能实现(用C或C++语言描述)
#include <bits/stdc++.h>
using namespace std;
class node
{ //节点类
public:
int num;//车牌号
int time;//时间
};
class AStack : public node
{ //栈类
private:
int size;
int top;
node *listArray;
public:
AStack(int sz)
{
size = sz;
top = 0;
listArray = new node[sz];
}
~AStack() { delete[] listArray; };
bool push(node a)
{
if (top == size)
return false;
listArray[top++] = a;
return true;
}
bool pop(node &a)
{
if (top == 0)
return false;
else
{
a = listArray[--top];
return true;
}
}
int length()
{
return top;
}
bool topValue(node &a)
{
if (top == 0)
return false;
a = listArray[top - 1];
return true;
}
};
class AQueue : public node
{ //队列类
private:
int size;
int front;
int rear;
node *listArray;
public:
AQueue(int sz)
{
size = sz + 1;
rear = 0;
front = 1;
listArray = new node[size];
}
~AQueue() { delete[] listArray; };
bool enqueue(node it)
{
if (((rear + 2) % size) == front)
return false;
rear = (rear + 1) % size;
listArray[rear] = it;
return true;
}
bool dequeue(node &it)
{
if (length() == 0)
return false;
it = listArray[front];
front = (front + 1) % size;
return true;
}
int length()
{
return ((rear + size) - front + 1) % size;
}
};
void input(AStack &parking1, AQueue &wait, node s)
{ //进停车场
if (parking1.push(s))
{
cout << "在停车场第" << parking1.length() << "位" << endl;
return;
}
else
{
cout << "在便道第" << wait.length() + 1 << "位" << endl;
wait.enqueue(s);
}
}
int output(AStack &parking1, AStack &parking2, AQueue &wait, node s)
{ //出停车场
node temp;
int time;
while ((parking1.topValue(temp)) && (temp.num != s.num))
{
parking1.pop(temp);
parking2.push(temp);
}
if (parking1.topValue(temp))
{ //判断该车是否存在于停车场中
parking1.pop(temp);
time = s.time - temp.time;
}
else
time = -1;
while (parking2.pop(temp))
parking1.push(temp);
if (time)
{
if (wait.length())
{
wait.dequeue(temp);
temp.time = s.time;
parking1.push(temp);
}
}
return time;
}
int main()
{
cout << "输入停车场容量和每分钟停车费" << endl;
int maxSize, money, parkTime;
cin >> maxSize >> money;
AStack parking1(maxSize), parking2(maxSize);
AQueue wait(100);
char a;
node s;
while (1)
{
cout << "输入命令:" << endl;
cin >> a >> s.num >> s.time;
while (!((a == 'A' || a == 'D' || a == 'E') && s.num >= 0 && s.time >= 0))
{
cout << "输入错误请重新输入:" << endl;
cin >> a >> s.num >> s.time;
};
if (a == 'E')
break;
else if (a == 'A')
{
input(parking1, wait, s);
continue;
}
else
{
parkTime = output(parking1, parking2, wait, s);
if (parkTime == -1)
cout << "该车不在本停车场,请重新输入!" << endl;
else
cout << "停车时间为:" << parkTime << ends << "应缴纳费用为:" << parkTime * money << endl;
}
}
system("pause");
return 0;
}
//A 1 5 A 2 10 D 1 15 A 3 20 A 4 25 A 5 30 D 2 35 D 4 40 E 0 0
六、程序测试及运行结果
七、心得体会
1.车在便道上等待的时候并不会产生停车费,要在停车场的车开出之后,该车才能进入停车场,因此要减去车在便道上的等待时间再计算出停车费用,在程序中这一点很容易被忽略。
2.进栈和出栈,进队列和出队列的时间复杂度都是O(1),大大减少了内存和时间的浪费
3.借助DEBUG调试器和数据观察窗口,可以加快找到程序中疵点。