c/c++ 栈与队列实现车库的出入与收费
/*
设停车场是一个可停放n辆车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列
(大门在最南端,最先到达的第一辆车停放在车场的最北段),若停车厂内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有
车开走,则排在便道上的第一辆车迹可开入;停车场内某辆车要离开时,在它之后进入的车连必须先退出车厂为它让路,待该车辆开出大门外,
其他车辆再按原次序进入车场,每辆停放在车场的车在它离开停车时必须按它停留的时间长短缴纳费用。编写按上述要求进行管理的模拟程序。
可以将停车场定义成一个顺序栈s0,便道定义成一个链队列q,而停车场中的某辆车要离开,则在它后面进停车场的车必须让道,让其离开,所
以必须有一个临时的顺序栈s1,存放让道的车辆。
当有车辆进停车场时,若栈s0不满,则直接进入栈s0;若栈s0满,则进入便道(链队列q)。若有s0中车辆x离开时,先让在x后面进栈的车从s0退栈并进入栈s1中,让x离开并收取停车费
( 在便道上停留的时间不收费),然后再把s1中所有元素退栈并重新进入s0栈,最后,将链队列q中的队头元素出队并进栈到s0中。 */
#include <iostream> #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <time.h>
#define MAXSIZE 2
#define PRICE 0.02 using namespace std; //车辆信息
typedef struct
{
char CarNum[5]; //车牌信息
time_t ArriveTime; //停车时间
time_t LeaveTime; //离开时间 }Car; //车库区——栈结构体
typedef struct
{
Car* base; //栈底指针
Car* top; //栈顶指针
int stackSize; //栈容量-车库位置数量
}Stack; //侯车区——队列结构体
typedef struct QNode
{
Car* data; //候车车牌信息
struct QNode* next;
}QNode, * QNodePtr;
typedef struct
{
QNodePtr front; //队头指针
QNodePtr rear; //队尾指针 }LinkQueue; //便道初始化——队列初始化
LinkQueue* InitQueue()
{
LinkQueue* Q = new LinkQueue;
Q->rear = new QNode; //申请队头结点空间,队头队尾均指向该结点
Q->front = Q->rear;
Q->front->next = NULL; //队头结点指针域置空,类似于单链表的头接点
return Q; //返回链队
} //车库初始化——栈初始化
Stack* InitStack()
{
Stack* CarPark = new Stack;
CarPark->base = new Car[MAXSIZE]; //申请五个Car类型空间-五个停车位
if (!CarPark->base)
cout << "空间分配失败"; //判断空间是否分配成功 CarPark->top = CarPark->base; //栈顶栈底处在同一位置,且让top有所指向
CarPark->stackSize = MAXSIZE; //分配栈容量
return CarPark;
} //车辆汇入——入栈
void push(Stack* CarPark, Car* car)
{
strcpy(CarPark->top->CarNum, car->CarNum); //车牌号录入
time(&(CarPark->top->ArriveTime)); //取得当前入库时间 //打印车辆停入时间
struct tm* tmTime;
tmTime = localtime(&(CarPark->top->ArriveTime));
printf("车号:%s 欢迎停车! 停入时间: %d:%d:%d\n", car->CarNum, (*tmTime).tm_hour, (*tmTime).tm_min, (*tmTime).tm_sec); CarPark->top++; //数据记录完后,栈顶向上移动
} //车辆进入便道——入队
void EnQueue(LinkQueue* Q, Car* car)
{ QNode* cur = new QNode; //为新结点申请空间
cur->data = new Car; //为data申请空间
strcpy(cur->data->CarNum, car->CarNum); //录入车牌信息——结点数据域赋值
time(&(cur->data->ArriveTime)); //记录到达时间
Q->rear->next = cur; //链接新结点——车辆入链队
cur->next = NULL; //指针域置空——遍历时的结束标志 Q->rear = cur; //队尾指针向后移动—— Q->rear - Q->front == 53 } //记录车辆信息并进行入栈检查——判断入队还是入栈
void RecordCar(Stack* CarPark, LinkQueue* Q, Car* car)
{
//记录车辆信息
cout << "请输入停车车牌号:";
cin >> car->CarNum; //判断车库是否已满——栈满否
if (CarPark->top - CarPark->base == CarPark->stackSize)
{
//入队
cout << "车库已满," << "车号:" << car->CarNum << " 已经进入便道等待!!!" << endl;
EnQueue(Q, car);
}
else
//否则入栈
push(CarPark, car);
} //查看车库信息——遍历栈
void StackTraverse(Stack* CarPark)
{
Car* temp = CarPark->top; //临时Car型指针temp——防止栈底指针改变 //判断栈是否为空不为空打印车辆车牌号
if (CarPark->base != temp)
{
cout << "—————— 停车库 ——————" << endl;
//打印最上面车辆一次,临时指针移动一次
while (CarPark->base != temp)
{
temp--; //栈顶指针先移动,因为栈顶指针指向的Car.CarNum没有数据
cout << " | 车:" << temp->CarNum << " ";
//打印到达时间
struct tm* tmTime;
tmTime = localtime(&(temp->ArriveTime));
printf("停入时间: %d:%d:%d", (*tmTime).tm_hour, (*tmTime).tm_min, (*tmTime).tm_sec);
cout << " |" << endl;
}
cout << "—————————————————" << endl;
}
else
cout << "——————————————车里没有车辆——————————————" << endl;
} //查看便道信息——遍历链队
void QueueTraverse(LinkQueue* Q)
{
QNodePtr temp = Q->front->next; //申请队列临时指针temp并指向队头后一结点 //判断便道是否有车——判断链队是否为空
if (temp)
{//是否有首元结点,有就打印
cout << "—————— 便车道 ——————" << endl; //打印一次,临时指针移动一次
while (temp)
{ cout << " | 车:" << temp->data->CarNum << " ";
//打印到达时间
struct tm* tmTime;
tmTime = localtime(&(temp->data->ArriveTime));
printf("停入时间: %d:%d:%d", (*tmTime).tm_hour, (*tmTime).tm_min, (*tmTime).tm_sec);
cout << " |" << endl;
temp = temp->next; //指针往后移动
}
}
//否则不打印车辆
else
cout << "——————————————便道里没有车辆——————————————" << endl;
} //便道车离开——销毁链对
void DestoryQueue(LinkQueue* Q)
{
//如果链对不为空则执行该语句
if (Q->front != Q->rear)
{
//申请临时QNodePtr temp指针;
QNodePtr temp;
while (Q->front)
{
temp = Q->front; //temp指向头结点
Q->front = temp->next; //头结点移动至下一结点 //删除temp
delete temp;
}
cout << "—————————————保卫通知便道车辆离开——————————————" << endl;
}
else
cout << "—————————————保卫通知便道车辆离开——————————————" << endl;
} //停车库出来的车辆进入临时停车场——临时栈入栈——在CarPop被调用
void TempPush(Stack* CarPark, Stack* TempCarPark)
{
strcpy(TempCarPark->top->CarNum, CarPark->top->CarNum); //入栈车牌号录入
TempCarPark->top++; //数据记录完后,栈顶向上移动
} //停车栈出栈进入临时栈,并收取出栈费用——在CarPop被调用
void Pop(Stack* CarPark, Stack* TempCarPark)
{
//依然进行检查栈检查
if (CarPark->base != CarPark->top)
{
CarPark->top--; //栈顶指针先减一栈顶指针无数据
//调用TempPush进入临时栈
TempPush(CarPark, TempCarPark);
}
else
cout << "车库内无车!!!" << endl;
} //便道车辆进入停车场并返回一个int型的标志——出队——在CarPop被调用
int DeQuenue(Stack* CarPark, LinkQueue* Q)
{
//队空判断,不为空出队
if (Q->front != Q->rear)
{
//设置临时QNodePtr指针,temp指向队头指针的后一个结点
QNodePtr temp = Q->front->next; //传入CarPark,temp->data
push(CarPark, temp->data); //链接temp后的结点
Q->front->next = temp->next; //如果最后一个结点被删,队尾指针指向头结点并结束
if (Q->rear == temp)
{
Q->rear = Q->front;
return 0;
}
//释放队列temp结点
delete temp;
}
//队为空不出
else
return 0;
} //车辆出库——出栈,同时完成队列入栈工作
void CarPop(Stack* CarPark, Stack* TempCarPark, LinkQueue* Q)
{
cout << "请输入要离开的车辆:";
//定义一个char匹配离开车辆
char LeaveCar[5];
cin >> LeaveCar; //定义一个临时Car指针用于遍历栈,flag为找到LeaveCar的标志
Car* temp = CarPark->top;
int flag = 1; //判断栈是否为空
if (CarPark->base != CarPark->top)
{
//匹配车辆,找到栈底退出或找到退出
while (temp != CarPark->base)
{
//栈顶指针先减一
temp--;
//对比车牌号,找到了退出
if (strcmp(temp->CarNum, LeaveCar) == 0)
{
flag = 1;
break;
} //未找到
flag = 0;
} //找到出库车,让前面的车先出去,
if (flag)
{
//temp此时为栈底指针作用,不等即上上面车辆依次先出栈
while (temp != CarPark->top)
{
//车库出栈,进入临时停车栈,传入停车栈和临时栈地址,调用Pop进行出栈
Pop(CarPark, TempCarPark);
//如果是出车车辆则进行收费
if (temp == CarPark->top)
{
time(&(CarPark->top->LeaveTime)); //取得当前出库时间 //打印车辆出库时间并收费
struct tm* tmTime;
//收费
tmTime = localtime(&(CarPark->top->LeaveTime));
printf("车号:%s 驶出车库! 出库时间: %d:%d:%d\t", CarPark->top->CarNum, (*tmTime).tm_hour, (*tmTime).tm_min, (*tmTime).tm_sec);
printf("收费:%.2lf元\n", ((CarPark->top->LeaveTime) - (CarPark->top->ArriveTime)) * PRICE);
}
} cout << "———————临时车库车辆重新进入车库——————————" << endl;
//临时栈的车辆回去,进入停车栈,栈顶指针先向下移动至出库的车
TempCarPark->top--;
//入栈循环条件为临时栈的栈底和栈顶是否相等
while (TempCarPark->base != TempCarPark->top)
{
//栈顶指针再减一,过滤出库的车
TempCarPark->top--;
//传入数据CarPark,TempCarPark->top
push(CarPark, TempCarPark->top); } cout << "————————便道车辆进入车库————————————" << endl; //入栈检查,当停车栈未满驶入车辆——调用push函数,若满就不再驶入
while (CarPark->top - CarPark->base != CarPark->stackSize)
{
//定义一个标志flag_1,若flag_1=0,便道没有车辆可以驶入,调用DeQuenue(CarPark,Q)进行入栈
int flag_1 = DeQuenue(CarPark, Q);
//退出循环不再进入入栈
if (flag_1 == 0)
{
cout << "————————恭喜,便道车辆已全部驶入————————" << endl;
break;
}
}
}
else
cout << "车库里没有查询的车辆!!!" << endl;
}
else
cout << "车库内无车!!!" << endl; } //保卫下班
void StopWork(Stack * CarPark, Stack * TempCarPark, LinkQueue * Q, Car * car)
{
cout << "————————————保卫下班去查看了车库/便道信息————————————" << endl;
StackTraverse(CarPark);
QueueTraverse(Q); //销毁
DestoryQueue(Q);
delete TempCarPark;
delete CarPark;
delete car;
} #if 1 //屏幕界面显示——主菜单
void Interface(Car * car, Stack * CarPark, Stack * TempCarPark, LinkQueue * Q)
{
char Choice = 'Y';
while (Choice == 'Y')
{
int choice;
cout << "请选择你要进行的操作(1-停车,2-出库,3-车库信息,4-便道信息,5-下班)" << endl;
cin >> choice; switch (choice)
{
case 1:
//记录车辆信息并判断——入栈检查
RecordCar(CarPark, Q, car);
break;
case 2:
//车辆出库——出栈,同时完成队列入栈工作
CarPop(CarPark, TempCarPark, Q);
break;
case 3:
//查看车库信息——遍历栈
StackTraverse(CarPark);
break;
case 4:
//查看便道信息——遍历队
QueueTraverse(Q);
break;
case 5:
//保卫下班
StopWork(CarPark, TempCarPark, Q, car);
break;
default:
cout << "输入错误,请重新输入!!!" << endl;
break;
} //如果下班退出循环
if (choice == 5)
break; cout << endl;
cout << "是否继续Y/N: ";
cin >> Choice;
cout << endl;
}
}
#endif int main()
{
//车辆指针car——生成结构体指针
Car* car = new Car; //停车库指针CarPark——栈初始化
Stack* CarPark = InitStack(); //Stact *CarPark = InitStack(CarPark)原来这样写的时候栈顶指针移动报错,原因是没给CarPark申请空间 //临时停车库指针TempCarPark——栈初始化
Stack* TempCarPark = InitStack(); //便道车辆指针Q——队列初始化
LinkQueue* Q = InitQueue(); //主菜单界面
Interface(car, CarPark, TempCarPark, Q);
return 0;
system("pause");
}
/*
问题: 栈顶指针移动时,出现野指针,解决办法栈和队列初始化时,需要给新生成的结构体指针分配空间;
遍历栈时,设置临时指针,防止栈底栈顶指针改变;
遍历栈时,temp->CarNum打印出现乱码,原因是栈顶指针的car.CarNum是无数据的,先temp--
strcpy(cur->data->CarNum,car->CarNum);语句报错0x00b110a8 处有未经处理的异常: 0xC0000005: 写入位置
0xbaadf00d 时发生访问冲突,百度查明0xC0000005为指针错误大都是没有指向,最后为Car *data申请空间得到解决(指针
要么有所指向,要么new分配,做的时候忽略了);
遍历链队时temp->data->CarNum,由于头指针数据域没有东西,打印报错,修改为QNodePtr temp = Q->front->next;
出库查询车辆时while((temp--)->CarNum != LeaveCar)报错,字符串比较不能用比较运算符,改为while(temp != CarPark->base)
内嵌if(strcmp(temp->CarNum,LeaveCar) == 0)
cin>>choice输入字符进入无限循环,使用c语言输入得到解决;
链对好理解的结构体定义:
typedef char ElemType;
typedef struct qNode
{
ElemType data;
struct qNode *next;
}QNode; //数据结点
typedef struct
{
QNode *front; //队头指针
QNode *rear; //队尾指针
}LinkQueue; //链队结点
测试代码:
cout<<"测试"<<endl;
cout<<"测试"<<endl;
system("pause");
*/
c/c++ 栈与队列实现车库的出入与收费的更多相关文章
- 学习javascript数据结构(一)——栈和队列
前言 只要你不计较得失,人生还有什么不能想法子克服的. 原文地址:学习javascript数据结构(一)--栈和队列 博主博客地址:Damonare的个人博客 几乎所有的编程语言都原生支持数组类型,因 ...
- [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...
- 剑指Offer面试题:6.用两个栈实现队列
一.题目:用两个栈实现队列 题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能. 原文是使用 ...
- C实现栈和队列
这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行.栈和队列不论在面试中还是笔试中都很重要 ...
- JavaScript数组模拟栈和队列
*栈和队列:js中没有真正的栈和队列的类型 一切都是用数组对象模拟的 栈:只能从一端进出的数组,另一端封闭 FILO 何时使用:今后只要仅希望数组只能从一端进 ...
- 用JS描述的数据结构及算法表示——栈和队列(基础版)
前言:找了上课时数据结构的教程来看,但是用的语言是c++,所以具体实现在网上搜大神的博客来看,我看到的大神们的博客都写得特别好,不止讲了最基本的思想和算法实现,更多的是侧重于实例运用,一边看一边在心里 ...
- JavaScript中的算法之美——栈、队列、表
序 最近花了比较多的时间来学习前端的知识,在这个期间也看到了很多的优秀的文章,其中Aaron可能在这个算法方面算是我的启蒙,在此衷心感谢Aaron的付出和奉献,同时自己也会坚定的走前人这种无私奉献的分 ...
- Java数据结构和算法之栈与队列
二.栈与队列 1.栈的定义 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表. (1)通常称插入.删除的这一端为栈顶(Top),另一端称为栈底(Bottom). (2)当表中没有元素时称为 ...
- python数据结构之栈、队列的实现
这个在官网中list支持,有实现. 补充一下栈,队列的特性: 1.栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIF ...
随机推荐
- RePr: Improved Training of Convolutional Filters
关键点: 1.关于filter正交 将一层中的一个$k \times k \times c$的卷积核展开为$k * k * c$的向量,表示为$f$.一层中有$J_{\ell}$个卷积核,$\bold ...
- BUAA_OO第一单元作业总结
BUAA_OO第一单元作业总结 单元任务 第一单元的任务为实现表达式的求导,其中第一次作业是对简单多项式的求导,第二次作业是对包含简单幂函数和简单正余弦函数的多项式的求导,第三次作业是对包含简单幂函数 ...
- 微信小程序开发和h5的区别
1. 开发小程序时,每个页面一定要在app.json文件中注册,页面文件夹和其包含的四个文件的名字要保持一致. 2. 小程序发起的都是HTTPS网络请求,在开发调试的过程中可以不校验协议和TLS版本, ...
- x变成y的最少操作次数(层次遍历)
输入x,y,x为源数字,y为目标值.输出x变成y的最少操作次数. x每次可以执行三种操作:-1 . +1 . x2: 如 x=5,y=8:5-1=4,4x2=8;所以输出结果为2(次操作). 可以发现 ...
- <!--#include virtual='head.html'-->代码复用
js限制input框只能输入数字:<input type="text" onkeyup="value=value.replace(/[^\d]/g,'')" ...
- docker 容器的mysql主从复制
一. 1.首先拉取docker镜像,我们这里使用5.7版本的mysql: docker pull mysql:5.7 2.分别启动主从两个容器: docker run -p 3339:3306 - ...
- 【Python】Scrapy基础
一.Scrapy 架构 Engine(引擎):负责 Spider(爬虫).Item Pipeline(管道).Downloader(下载器).Scheduler(调度器)中的通讯和数据传递. Sche ...
- 【调试基础】Part 4 保护模式
保护模式.虚拟内存.权限
- jieba 库
jieba库是python 一个重要的第三方中文分词函数库,但需要用户自行安装. 一.jieba 库简介 (1) jieba 库的分词原理是利用一个中文词库,将待分词的内容与分词词库进行比对,通过图结 ...
- 怎么在多场景下使用不同的 git 账号 commit
应用场景 我有多个github的账号,不同的账号对应不同的repo,需要push的时候自动区分账号 我有多个git的账号,有的是github的,有的是单位的gitlab的,不同账号对应不同的repo, ...