目录
前言
队列:是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。假设队列是q=(a1,a2,-----an),那么a1就是队头元素,an就是队尾元素。这样我们就可以删除总是从a1开始,而插入时,列在最后。这也比较符合我们通常生活的习惯,排在第一个的优先出列,最后来的当然排在队伍最后。
以上就是关于队列的简单定义,不论是接触过还是没接触过的同学,我们在阅读文章的时候只需要有这些概念即可,剩下的我们下面慢慢介绍。
1.项目要求
问题描述:
1.停车场设置
一个停车场,拥有100个停车位。车辆停放在一条单行道上,而且只能从停车场的一侧进入,从一段离开。停车场另外提供一条过道,可供10辆汽车临时停靠。
车辆在进入停车场时,只能从一端进入,另外一端出去。若停车场内已经停满,则后来的车就只能停在门外的过道上等候。一旦停车场有空位,过道上的第一辆车就可进入停车场,过道也是只有一段进入,另外一段出去。
2.收费规则
每辆停在停车场的车,在离开停车场时,必须按照停留的时间长短缴纳费用。停车场按每小时5元计费,进出时间均为整数,不足一小时不收费,超过3h后每小时价格为10元。
3.实现功能
(1)车辆进入停车场(开始计时)
(2)车辆离开停车场(停止计时并计算费用)
(3)查看停车场(查看当前停车场的使用状态)
2.项目思路
停车场设置:要求中提到停车场需要100个停车位,当停车位满后需要停在过道上等候,过道可容纳10辆车。由停车场先进先出的性质,我们发现这与队列的性质非常接近,所以我们在这里需要两个队列来实现这个项目需求。
收费规则:计算费用按照时间的长短,说明我们不仅要记录每一辆车同时也要记录每一辆车进入停车场的时间以及出停车场的时间,再按照收费的规则来计算费用。
实现功能:以上三个功能涉及到,队列的创建、入队列、出队列、遍历队列等操作。
本项目通过三个步骤来实现
一、队列的相关操作
1.队列的创建以及初始化
关于队列的定义我们通常使用循环队列,用结构体来定义,需要定义队列的队首front以及队尾rear,还有队列的大小size,最后就是队列元素的类型——这里是我们开头定义的Car类型的数据类型。
队列的初始化,首先利用malloc函数给队列中的Car数组分配空间,然后初始化队列的队尾队首为0,最后初始化队列的长度nSize。
代码如下:
// 定义车的结构体
struct Car{
char lisence_plate[10]; //车牌
int time; //进入停车场的时间
};
// 循环队列
typedef struct SqQueue{
Car *base; //数组
int front;
int rear;
int size;
}Queue;
//初始化队列
int InitQueue(Queue &q,int nSize){
q.base=(Car*)malloc(nSize*(sizeof(Car)));
if(!q.base){
printf("初始化队列失败\n");
return -1;
}
q.front=0;
q.rear=0;
q.size=nSize;
return 0;
}
2.队列的插入以及删除操作
关于队列的插入操作,我们要做的第一步就是判断队列是否以及队满,这里给出了一个公式 (q.rear+1)%q.size==q.front 当它为真时,表示队列已经队满无法再进行插入操作了。第二步就是将car赋值给base的队尾rear的位置,最后用公式(q.rear+1)%q.size 更新队尾的位置。(关于公式本文的最后会讲解)
要想删除队列中的元素,我们首先要认识到一点,在数组中我们无法真正的删除里面的元素,这是与链表区别之一。在队列中,front和rear这两个指针可以帮助我们完成删除,由于队列先进先出的性质,front指向的是最先进入也就是最先被删除的元素,只要我们将front指针指向另一个元素就代表另一个元素变成的最先进入的元素,相应的原来的元素就被“删除”了。
代码如下:
//往队尾插入元素
int EnQueue(Queue &q,Car car){
//判断队列是否满
if((q.rear+1)%q.size==q.front){
return -1;
}
q.base[q.rear]=car;
q.rear=(q.rear+1)%q.size;
return 0;
}
//从队列头中删除元素
int DeQueue(Queue &q,Car &car){
if(q.rear==q.front){
printf("该停车场已经没有车了\n");
return -1;
}
car=q.base[q.front];
q.front=(q.front+1)%q.size;
return 0;
}
3.队列的遍历操作
遍历队列首先需要检查队列是否是空的,如果是空的就无法遍历返回-1。在这里,我们只需要利用front和rear其中一个指针就可以完成遍历,利用while循环以队空为条件,取出q.base中的元素printf输出,最后用公式 i=(i+1)%q.size 更新 i 的位置。
代码如下:
//遍历队列中的序列并输出
int QueueTraverse(Queue q){
if(q.front==q.rear){
return -1; //该队列是空的,所以无法输出
}
int i=q.front;
while(i!=q.rear){
Car car;
car=q.base[i];
printf("车牌号:%d,入场时间为:%d\n",car.lisence_plate,car.time);
i=(i+1)%q.size;
}
return 0;
}
4.队列的其他操作
销毁队列的操作首先第一步就是利用free函数将base数组给销毁掉,然后将队列的队首、队尾、队列的长度全都清零(赋值为0)。返回队列的长度需要利用一个公式(q.rear-q.front+q.size)%q.size
代码如下:
//销毁队列
int DestoryQueue(Queue &q){
if(q.base){
free(q.base);
q.base=NULL;
}
q.front=0;
q.rear=0;
q.size=0;
return 0;
}
//返回当前队列中的元素个数
int QueueLength(Queue &q){
return (q.rear-q.front+q.size)%q.size;
}
二、利用队列相关操作实现停车场的功能
1.进入停车场
代码如下:
int inpark(Queue &park1,Queue &park2){
printf("------进入停车场-------\n");
Car car;
printf("请输入你的车牌号\n");
scanf("%s",&car.lisence_plate);
printf("请输入进入停车场的时间\n");
scanf("%d",&car.time);
if(EnQueue(park1,car)==0){
printf("该车已进入停车场的第%d个位置\n",QueueLength(park1));
}
else if(EnQueue(park2,car)==0){
printf("停车位已满,车停在过道的第%d个位置\n",QueueLength(park2));
}
else{
printf("已没有空余位置,请离开\n");
}
return 0;
}
2.离开停车场
这里需要注意的是,有一辆车离开停车场,如果过道中有车,还需要添加一步操作就是将过道的车进入停车场,从park2中取出,在放进park1中。
代码如下:
int outpark(Queue &park1,Queue &park2){
printf("-------离开停车场---------\n");
Car car;
int outtime;
int alltime;
printf("请输入离开时间\n");
scanf("%d",&outtime);
alltime=outtime-car.time; //汽车的停车总时间
if(DeQueue(park1,car)==0){
printf("汽车在停车场待的时间为%d h\n",alltime);
if(alltime<1){
printf("时间不足一小时,不收钱\n");
}
else if(alltime>=1&&alltime<=3){
printf("停车费用为%d元\n",alltime*5);
}
else if(alltime>3){
printf("停车费用为%d元\n",15+(alltime-3)*10);
}
if(DeQueue(park2,car)==0){
printf("车牌号为%s的车从过道进入停车场\n",car.lisence_plate);
printf("请输入入场时间\n");
scanf("%d",car.time);
EnQueue(park1,car);
}
}
else{
printf("没有车要离开\n");
}
return 0;
}
3.查看停车场的状态
代码如下:
int seepark(Queue &park1,Queue &park2){
printf("-------停车场--------\n");
QueueTraverse(park1);
QueueTraverse(park2);
return 0;
}
三、完成停车场管理系统的界面
首先创建两个队列,在while循环中实现管理系统的重复操作,再利用switch-case来实现用户可自己选择想要使用的功能,最后在结束之前销毁两个队列。
代码如下:
int main()
{
Queue park1; //声明停车场序列
Queue park2; //声明过道序列
InitQueue(park1,100); //100个车位
InitQueue(park2,10); //10个临时停车位
bool truth=true;
while(truth){
printf("----欢迎来到停车管理系统------\n");
printf("1.车辆进入\n");
printf("2.车辆离开\n");
printf("3.查看停车场\n");
printf("4.退出系统\n");
printf("输入你想进行的操作序号\n");
int i;
scanf("%d",&i);
switch(i){
case 1:
inpark(park1,park2);
break;
case 2:
outpark(park1,park2);
break;
case 3:
seepark(park1,park2);
case 4:
truth=false;
printf("bye\n");
break;
}
}
//程序结束前,消除创建的两个队列
DestoryQueue(park1);
DestoryQueue(park2);
}
四、完整代码以及测试样例
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<iostream>
struct Car{
char lisence_plate[10]; //车牌
int time; //进入停车场的时间
};
// 循环队列
typedef struct SqQueue{
Car *base; //数组
int front;
int rear;
int size;
}Queue;
//初始化队
int InitQueue(Queue &q,int nSize){
q.base=(Car*)malloc(nSize*(sizeof(Car)));
if(!q.base){
printf("初始化队列失败\n");
return -1;
}
q.front=0;
q.rear=0;
q.size=nSize;
return 0;
}
//销毁队列
int DestoryQueue(Queue &q){
if(q.base){
free(q.base);
q.base=NULL;
}
q.front=0;
q.rear=0;
q.size=0;
return 0;
}
//返回当前队列中的元素个数
int QueueLength(Queue &q){
return (q.rear-q.front+q.size)%q.size;
}
//往队尾插入元素
int EnQueue(Queue &q,Car car){
//判断队列是否满
if((q.rear+1)%q.size==q.front){
return -1;
}
q.base[q.rear]=car;
q.rear=(q.rear+1)%q.size;
return 0;
}
//从队列头中删除元素
int DeQueue(Queue &q,Car &car){
if(q.rear==q.front){
printf("该停车场已经没有车了\n");
return -1;
}
car=q.base[q.front];
q.front=(q.front+1)%q.size;
return 0;
}
//遍历队列中的序列并输出
int QueueTraverse(Queue q){
if(q.front==q.rear){
return -1; //该队列是空的,所以无法输出
}
int i=q.front;
while(i!=q.rear){
Car car;
car=q.base[i];
printf("车牌号:%d,入场时间为:%d\n",car.lisence_plate,car.time);
i=(i+1)%q.size;
}
return 0;
}
int inpark(Queue &park1,Queue &park2){
printf("------进入停车场-------\n");
Car car;
printf("请输入你的车牌号\n");
scanf("%s",&car.lisence_plate);
printf("请输入进入停车场的时间\n");
scanf("%d",&car.time);
if(EnQueue(park1,car)==0){
printf("该车已进入停车场的第%d个位置\n",QueueLength(park1));
}
else if(EnQueue(park2,car)==0){
printf("停车位已满,车停在过道的第%d个位置\n",QueueLength(park2));
}
else{
printf("已没有空余位置,请离开\n");
}
return 0;
}
int outpark(Queue &park1,Queue &park2){
printf("-------离开停车场---------\n");
Car car;
int outtime;
int alltime;
printf("请输入离开时间\n");
scanf("%d",&outtime);
alltime=outtime-car.time; //汽车的停车总时间
if(DeQueue(park1,car)==0){
printf("汽车在停车场待的时间为%d h\n",alltime);
if(alltime<1){
printf("时间不足一小时,不收钱\n");
}
else if(alltime>=1&&alltime<=3){
printf("停车费用为%d元\n",alltime*5);
}
else if(alltime>3){
printf("停车费用为%d元\n",15+(alltime-3)*10);
}
if(DeQueue(park2,car)==0){
printf("车牌号为%s的车从过道进入停车场\n",car.lisence_plate);
printf("请输入入场时间\n");
scanf("%d",car.time);
EnQueue(park1,car);
}
}
else{
printf("没有车要离开\n");
}
return 0;
}
int seepark(Queue &park1,Queue &park2){
printf("-------停车场--------\n");
QueueTraverse(park1);
QueueTraverse(park2);
return 0;
}
int main()
{
Queue park1; //声明停车场序列
Queue park2; //声明过道序列
InitQueue(park1,100); //100个车位
InitQueue(park2,10); //10个临时停车位
bool truth=true;
while(truth){
printf("----欢迎来到停车管理系统------\n");
printf("1.车辆进入\n");
printf("2.车辆离开\n");
printf("3.查看停车场\n");
printf("4.退出系统\n");
printf("输入你想进行的操作序号\n");
int i;
scanf("%d",&i);
switch(i){
case 1:
inpark(park1,park2);
break;
case 2:
outpark(park1,park2);
break;
case 3:
seepark(park1,park2);
case 4:
truth=false;
printf("bye\n");
break;
}
}
//程序结束前,消除创建的两个队列
DestoryQueue(park1);
DestoryQueue(park2);
}