• 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
    ", 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	", CarPark->top->CarNum, (*tmTime).tm_hour, (*tmTime).tm_min, (*tmTime).tm_sec);
    					printf("收费:%.2lf元
    ", ((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");
    */

  • 相关阅读:
    数据库事务查看
    在SQL中删除重复记录(多种方法)
    OO设计原则
    NHibernate开源框架Cuyahoga学习之权限映射
    链队列的实现
    二叉树的实现
    NHibernate.cfg.xml文件配置
    HQL查询实例
    对象枚举遍历实现二
    NHibernate开源框架Cuyahoga学习之数据访问泛型约束的实现
  • 原文地址:https://www.cnblogs.com/huxiaobai/p/10629543.html
Copyright © 2020-2023  润新知