1.1 问题描述
设计一个停车场管理系统,管理系统中包括停车场和便道,停车场是一个可停放n辆车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第1辆车停放在车场的最北端),若车场内已经停满了n辆汽车,则后来的汽车只能在门外的便道上候车,一旦有车开走,排在便道上的第一辆车即可进入。当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路(用结构体数组临时存放让路的车),待该辆车开出大门外,其他车辆按原次序进入停车场,然后便道上的车即可开入一辆进入停车场。每辆车停放在车场的车在它离开停车场时必须按照它在停车场停留的时间长短缴纳费用,便道上的车如果还没有进入停车场就离开了则不需要缴纳费用,如果在离开之前进入了停车场,则停车场有车离开的时间就是便道上的车进入停车场的时间,从此刻计时并在离开时计算费用。
以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、车牌号以及到达或离开时间。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车辆离开,则输出汽车在停车场内停留的时间和应缴纳费用。栈以顺序结构实现,队列以链表结构实现。
1.2涉及到的知识点
- 数据结构
- 栈(Stack)
o 定义: 栈是一种“先进后出”(LIFO)的线性数据结构。
o 作用: 用于模拟停车场内的汽车管理。
o 相关操作:
push: 将车辆信息(车牌号)压入栈中,表示车辆进入停车场。
pop: 从栈顶移除车辆信息,表示车辆离开停车场。
peek: 查看栈顶的车辆信息。 - 队列(Queue)
o 定义: 队列是一种“先进先出”(FIFO)的线性数据结构。
o 作用: 用于模拟便道上等待的车辆管理。
o 相关操作:
enqueue: 将车辆信息添加到队尾,表示车辆等待进入停车场。
dequeue: 从队首移除车辆信息,表示车辆从便道进入停车场。 - 时间处理
- 时间表示
o 使用 struct tm 和 time_t 结构存储和计算时间。
o mktime:
将时间结构 struct tm 转换为 time_t(秒数)形式,便于计算时间差。
o difftime:
计算两个 time_t 时间之间的差值(以秒为单位)。 - 跨天时间计算
o 时间差的计算需要考虑日期变化,使用逻辑分段处理跨天的停车费累积。 - 字符串处理
• 使用 char 数组存储车牌号,长度固定为 21 个字符。
• 字符串操作函数:
o strcpy: 拷贝字符串,用于保存车牌号。
o strcmp: 比较字符串,用于匹配车牌号。
• 支持汉字和字母的车牌号存储,符合现实车牌格式。 - 动态内存分配
• 使用 malloc 为栈和队列分配动态内存,程序可灵活支持不同大小的停车场。
• free:
o 清理内存,防止内存泄漏。 - 条件分支与循环
- 条件分支:
o 根据用户输入的操作(到达、离开、结束)分别处理。
o 停车场是否已满、便道是否为空等判断逻辑。 - 循环结构:
o 不断接受用户输入,直到输入结束标志(E)。 - 模拟问题求解
• 将现实中的停车场管理问题抽象为栈和队列的操作流程。
• 结合计费规则,通过分解问题实现完整功能。 - 费用计算
- 免费时长:
o 前两小时停车免费,逻辑判断为 hours <= 2 时收费为 0。 - 收费规则:
o 超出免费时长部分按小时收费,每小时3元。
o 每天停车费用上限为30元。 - 跨天收费逻辑:
o 使用循环处理跨天停车的每日费用累积,保证计算准确。 - 输入与输出
• 输入:
o 支持带格式的用户输入:操作,车牌号,到达/离开时间。
o 时间格式为 YYYY-MM-DD HH:MM,通过解析赋值到 struct tm。
• 输出:
o 打印车辆到达或离开的具体信息,包括车牌号、位置、停留时长和费用。 - 容错性设计
• 判断停车场是否已满或为空,避免非法操作。
• 当车辆离开时检查是否在栈顶,若不在,提示用户操作受限。
代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_PARKING_SLOTS 100
#define DAILY_MAX_FEE 30 // 每天最大收费
#define HOURLY_RATE 3 // 每小时收费
#define FREE_HOURS 2 // 每天免费停车时间(小时)
// 定义栈结构
typedef struct Stack {
int top;
int capacity;
char(*array)[21];
time_t* arrivalTimes; // 对应每辆车的到达时间
} Stack;
// 创建栈
Stack* createStack(int capacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->capacity = capacity;
stack->top = -1;
stack->array = (char(*)[21])malloc(stack->capacity * sizeof(char[21]));
stack->arrivalTimes = (time_t*)malloc(stack->capacity * sizeof(time_t));
return stack;
}
// 栈操作
int isStackEmpty(Stack* stack) {
return stack->top == -1;
}
int isStackFull(Stack* stack) {
return stack->top == stack->capacity - 1;
}
void push(Stack* stack, const char* plateNumber, time_t arrivalTime) {
if (isStackFull(stack)) {
printf("停车场已满\n");
return;
}
strcpy(stack->array[++stack->top], plateNumber);
stack->arrivalTimes[stack->top] = arrivalTime;
}
void pop(Stack* stack, char* plateNumber, time_t* arrivalTime) {
if (isStackEmpty(stack)) {
printf("停车场为空\n");
strcpy(plateNumber, "");
*arrivalTime = 0;
return;
}
strcpy(plateNumber, stack->array[stack->top]);
*arrivalTime = stack->arrivalTimes[stack->top--];
}
void peek(Stack* stack, char* plateNumber, time_t* arrivalTime) {
if (isStackEmpty(stack)) {
printf("停车场为空\n");
strcpy(plateNumber,"");
*arrivalTime = 0;
return;
}
strcpy(plateNumber, stack->array[stack->top]);
*arrivalTime = stack->arrivalTimes[stack->top];
}
// 定义队列节点
typedef struct QueueNode {
char plateNumber[21];
time_t arrivalTime;
struct QueueNode* next;
} QueueNode;
// 定义队列
typedef struct Queue {
QueueNode* front;
QueueNode* rear;
} Queue;
// 创建队列
Queue* createQueue()
{
Queue* queue = (Queue*)malloc(sizeof(Queue));
queue->front = queue->rear = NULL;
return queue;
}
// 队列操作
int isQueueEmpty(Queue* queue) {
return queue->front == NULL;
}
void enqueue(Queue* queue,char* plateNumber, time_t arrivalTime) {
QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
strcpy(newNode->plateNumber, plateNumber);
newNode->arrivalTime = arrivalTime;
newNode->next = NULL;
if (isQueueEmpty(queue)) {
queue->front = queue->rear = newNode;
}
else {
queue->rear->next = newNode;
queue->rear = newNode;
}
}
void dequeue(Queue* queue, char* plateNumber, time_t* arrivalTime) {
if (isQueueEmpty(queue)) {
printf("队列为空\n");
strcpy(plateNumber, "");
*arrivalTime = 0;
return;
}
QueueNode* temp = queue->front;
strcpy(plateNumber, temp->plateNumber);
*arrivalTime = temp->arrivalTime;
queue->front = queue->front->next;
if (queue->front == NULL) {
queue->rear = NULL;
}
free(temp);
}
// 计算停车费用
int calculateParkingFee(time_t arrivalTime, time_t departureTime) {
struct tm arrival = *localtime(&arrivalTime);
struct tm departure = *localtime(&departureTime);
int totalFee = 0;
while (arrival.tm_year < departure.tm_year || arrival.tm_yday < departure.tm_yday) {
struct tm endOfDay = arrival;
endOfDay.tm_hour = 23;
endOfDay.tm_min = 59;
endOfDay.tm_sec = 59;
time_t endOfDayTime = mktime(&endOfDay);
double diffInSeconds = difftime(endOfDayTime, arrivalTime);
int hours = (int)(diffInSeconds / 3600) + 1; // 不满一小时按一小时算
if (hours > FREE_HOURS) {
int dailyFee = (hours - FREE_HOURS) * HOURLY_RATE;
if (dailyFee > DAILY_MAX_FEE) {
dailyFee = DAILY_MAX_FEE;
}
totalFee += dailyFee;
}
arrival.tm_hour = 0;
arrival.tm_min = 0;
arrival.tm_sec = 0;
arrival.tm_mday++;
arrivalTime = mktime(&arrival);
}
// 计算最后一天的费用
double diffInSeconds = difftime(departureTime, arrivalTime);
int hours = (int)(diffInSeconds / 3600) + 1; // 不满一小时按一小时算
if (hours > FREE_HOURS) {
int dailyFee = (hours - FREE_HOURS) * HOURLY_RATE;
if (dailyFee > DAILY_MAX_FEE) {
dailyFee = DAILY_MAX_FEE;
}
totalFee += dailyFee;
}
return totalFee;
}
// 模拟停车场管理
void manageParking() {
int parkingSlots;
printf("请输入停车场的车位数: ");
scanf("%d", &parkingSlots);
Stack* parkingStack = createStack(parkingSlots);
Queue* waitingQueue = createQueue();
char action;
char plateNumber[21];
struct tm timeInfo;
time_t currentTime;
printf("请输入操作(格式: A/D <车牌号> <时间(YYYY-MM-DD HH:MM)>,E 表示结束):\n");
while (1)
{
scanf(" %c", &action);
if (action == 'E') {
break;
}
scanf("%20s %d-%d-%d %d:%d", plateNumber, &timeInfo.tm_year, &timeInfo.tm_mon, &timeInfo.tm_mday, &timeInfo.tm_hour, &timeInfo.tm_min);
timeInfo.tm_year -= 1900;
timeInfo.tm_mon -= 1;
timeInfo.tm_sec = 0;
currentTime = mktime(&timeInfo);
if (action == 'A') {
if (!isStackFull(parkingStack)) {
push(parkingStack, plateNumber, currentTime);
printf("汽车 %s 停入停车场\n", plateNumber);
}
else {
enqueue(waitingQueue, plateNumber, currentTime);
printf("停车场已满,汽车 %s 停在便道上\n", plateNumber);
}
}
else if (action == 'D') {
if (isStackEmpty(parkingStack)) {
printf("停车场为空\n");
continue;
}
char topPlate[21];
time_t arrivalTime;
peek(parkingStack, topPlate, &arrivalTime);
if (strcmp(topPlate, plateNumber) == 0) {
pop(parkingStack, topPlate, &arrivalTime);
int fee = calculateParkingFee(arrivalTime, currentTime);
printf("汽车 %s 停留时间 %.2f 小时,应缴纳费用 %d 元\n", plateNumber, difftime(currentTime, arrivalTime) / 3600.0, fee);
while (!isQueueEmpty(waitingQueue) && !isStackFull(parkingStack)) {
char waitingPlate[21];
time_t waitingTime;
dequeue(waitingQueue, waitingPlate, &waitingTime);
push(parkingStack, waitingPlate, currentTime);
printf("汽车 %s 从便道进入停车场\n", waitingPlate);
}
}
else {
printf("汽车 %s 不在停车场最外部,无法离开\n", plateNumber);
}
}
else {
printf("无效的操作\n");
}
}
free(parkingStack->array);
free(parkingStack->arrivalTimes);
free(parkingStack);
while (!isQueueEmpty(waitingQueue)) {
char temp[21];
time_t tempTime;
dequeue(waitingQueue, temp, &tempTime);
}
free(waitingQueue);
}
int main() {
manageParking();
return 0;
}