C语言之装甲车库车辆动态监控辅助记录系统
🌟 嗨,我是LucianaiB!
🌍 总有人间一两风,填我十万八千梦。
🚀 路漫漫其修远兮,吾将上下而求索。
C语言之装甲车库车辆动态监控辅助记录系统
目录
- 一、前言
1.1 (一)问题描述
1.2 (二)算法输入 - 二、算法要点描述与实现思想
2.1 (一)算法要点
2.2 (二)实现思想
2.2.1 1、输入处理模块
2.2.2 2、装甲车库初始化模块
2.2.3 3、主菜单控制模块
2.2.4 4、装甲车入场模块
2.2.5 5、装甲车出场模块
2.2.6 6、装甲车状态显示模块
2.2.7 7、装甲车搜索模块
2.2.8 8、油量冒泡排序
2.2.9 9、损坏程度快速排序 - 三、数据结构确定和数据类型ADT定义
- 四、主要算法程序框图
- 五、测试数据及结果分析(含时间、空间复杂度分析)
5.1 (一)时间复杂度
5.2 (二)空间复杂度 - 六、设计体会,存在问题及分析
6.1 (一)存在问题
6.2 (二)遇到困难
6.3 (三)修改与完善 - 附录代码
一、前言
(一)问题描述
设计一个狭长通道装甲车库车辆动态监控辅助记录系统的管理程序,实现装甲车默认按先后顺序停放,也可以自选位置停放、出场时让装甲车按车牌号离开车库的功能。
(二)算法输入
装甲车入场:
用户选择菜单中的“1. 装甲车辆入场”功能。
输入车牌号 MD521,输入油量百分比:85,输入损坏程度百分比:30,选择停车位 (1-100):4,系统成功将车辆停放在第4个空闲位置。
系统提示“车辆 MU521 已停入主装甲车库,位置:4”,显示车辆成功入场。
装甲车辆出场:
用户选择菜单中的“2. 装甲车辆出场”功能。
输入要移出的车牌号 MU521,系统成功从停车场移除该车辆。
系统提示“装甲车 MU521 离开主装甲车库,停车时长:0.04 小时”,显示车辆成功出场,并输出停车时长。
装甲车库状态显示:
用户选择菜单中的“3. 显示装甲车库状态”功能。
系统打印所有 100 个装甲车库的状态,显示99个装甲车库当前状态为空闲(未停放车辆),一个装甲车,并打印信息。
系统统计装甲车库信息:总容量:100,当前数量:1。位置 4: MU521 (油量: 85%, 损坏: 30%)
搜索装甲车失败:
用户选择菜单中的“4. 按照装甲车牌号查询车辆”功能。
输入车牌号 999,系统未能找到该装甲车库,提示“未找到车牌号为 999 的车辆”。
说明装甲车可能已出场或未入场。
车辆成功搜索:
用户选择菜单中的“4. 搜索车辆”功能,输入车牌号 MU521,系统成功定位车辆,提示“找到装甲车 MU521,位置 4,油量 85%,损坏程度 30%”。
装甲车油量排序:
用户选择菜单中的“5. 查询装甲车辆油量并按油量排序”功能,按照冒泡排序从油量大到小进行排序并输出。
装甲车损坏程度排序:
用户选择菜单中的“6. 查询装甲车辆装备损坏情况并按损坏程度排序”功能,按照快速排序从损坏程度小到大进行排序并输出。
二、算法要点描述与实现思想
(一)算法要点
- 装甲车库创建模块:
o 使用 createGarage 函数初始化装甲车库,分配内存并设置初始状态,包括前驱和后继指针、容量、大小以及占用状态数组。 - 装甲车库状态检查模块:
o isFull 函数检查装甲车库是否已满,即当前数量是否达到最大容量。
o isEmpty 函数检查装甲车库是否为空,即当前数量是否为零。 - 装甲车辆入场模块:
o enterGarage 函数处理装甲车辆的入场,包括用户选择停车位、输入车辆信息,并将其添加到链表中相应的位置。
o 如果主装甲车库未满,将车辆信息添加到主车库的链表中,并更新占用状态。
o 如果主装甲车库已满,将车辆信息添加到临时车库的链表中。 - 装甲车辆出场模块:
o leaveGarage 函数处理装甲车辆的出场,遍历主装甲车库的链表找到对应车辆,并更新链表和占用状态。
o 如果临时车库有车辆,将临时车库中的第一辆车移动到主车库中空出的位置上。 - 装甲车库状态显示模块:
o displayStatus 函数显示主装甲车库和临时车库的当前状态,包括每个车位的车辆信息和空位。 - 装甲车辆搜索模块:
o searchVehicle 函数根据车牌号搜索车辆,遍历主装甲车库的链表,找到对应车辆后显示其信息。 - 装甲车辆油量显示模块:
o displayFuelLevels 函数显示主装甲车库中所有车辆的油量信息,并按油量进行冒泡排序。 - 装甲车辆损坏程度显示模块:
o displayDamageLevels 函数显示主装甲车库中所有车辆的损坏程度信息,并使用快速排序算法按损坏程度排序。 - 数据持久化模块:
o saveState 和 loadState 函数分别用于保存和加载装甲车库的状态,包括车辆信息和占用状态。 - 主控菜单模块:
o 程序通过无限循环显示菜单,接收用户的选择,并根据选择调用相应的功能函数。
(二)实现思想
1、输入处理模块
该模块负责接收用户输入的功能选项和装甲车牌号,并对这些输入数据进行处理。
实现思想:
主菜单通过提示用户输入功能编号,并使用 scanf 获取用户输入。 在处理特定功能时,如装甲车辆入场或出场,处理车牌号的输入并检查其合法性,确保车牌号不超出预设的最大长度 MAX_PLATE_LEN。
printf("请输入您的选择: ");
if (scanf("%d", &choice) != 1) {
printf("输入无效,请输入数字。\n");
// 清除输入缓冲区
while (getchar() != '\n');
continue;
}
printf("请输入装甲车牌号: ");
scanf("%s", licensePlate);
if (strlen(licensePlate) >= MAX_PLATE_LEN) {
printf("车牌号过长,请输入不超过%d个字符的车牌号。\n", MAX_PLATE_LEN - 1);
// 清除输入缓冲区
while (getchar() != '\n');
continue;
}
2、装甲车库初始化模块
该模块负责在程序启动时将装甲车库的所有车位初始化为空闲状态,并清空车牌号信息。
实现思想:
通过循环遍历所有装甲车库,将每个装甲车库的占用状态设置为未占用(0),并将车牌号信息清空。
void initializeParking(ParkingSpot parking[], int numSpots) {
int i;
for (i = 0; i < numSpots; i++) {
parking[i].isOccupied = false; // 设置为未占用
memset(parking[i].licensePlate, 0, sizeof(parking[i].licensePlate));
// 清空车牌号
}
}
3、主菜单控制模块
该模块负责显示主菜单,接收用户输入,并根据用户的选择调用相应的功能函数。
实现思想:
使用 while 循环不断显示主菜单,接受用户的选择。 使用 switch 语句根据用户输入调用具体的功能函数。 提供退出选项(当 choice 等于7时),终止循环并退出程序。
int main() {
int choice;
char plate[MAX_PLATE_LEN];
int fuelLevel, damageLevel, garageCapacity;
mainGarage = createGarage(0);
tempGarage = createGarage(100);
loadState();
if (mainGarage->capacity == 0) {
printf("请输入主装甲车库容量:");
scanf("%d", &garageCapacity);
mainGarage->capacity = garageCapacity;
}
while (1) {
displayMenu();
scanf("%d", &choice);
switch (choice) {
case 1:
printf("请输入车牌号:");
scanf("%s", plate);
printf("请输入油量百分比:");
scanf("%d", &fuelLevel);
printf("请输入损坏程度百分比:");
scanf("%d", &damageLevel);
enterGarage(plate, fuelLevel, damageLevel);
break;
case 2:
printf("请输入车牌号:");
scanf("%s", plate);
leaveGarage(plate);
break;
case 3:
displayStatus();
break;
case 4:
printf("请输入要查找的车牌号:");
scanf("%s", plate);
searchVehicle(plate);
break;
case 5:
displayFuelLevels();
break;
case 6:
displayDamageLevels();
break;
case 7:
saveState();
printf("系统已保存,感谢使用!\n");
free(mainGarage);
free(tempGarage);
return 0;
default:
printf("无效选择,请重试\n");
}
}
return 0;
}
4、装甲车入场模块
该模块负责将新入场的装甲车停放在第一个可用的停车位上,并更新停车位的状态。
实现思想:
遍历装甲车库的停车位数组,找到第一个未被占用的停车位。 将用户输入的装甲车牌号存储到该停车位,并将其状态设置为已占用。 如果装甲车库已满,即没有找到空闲停车位,提示用户无法停放车辆。
void enterGarage(char* plate, int fuelLevel, int damageLevel) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
perror("Memory allocation failed");
return;
}
strcpy(newNode->vehicle.plate, plate);
newNode->vehicle.arriveTime = time(NULL);
newNode->vehicle.fuelLevel = fuelLevel;
newNode->vehicle.damageLevel = damageLevel;
newNode->next = NULL;
if (!isFull(mainGarage)) {
int position;
printf("请选择停装甲车位 (1-%d): ", mainGarage->capacity);
scanf("%d", &position);
// Input validation and error handling
while (position < 1 || position > mainGarage->capacity || mainGarage->occupied[position - 1]) {
printf("无效的装甲车位选择,该位置已被占用或超出范围。请重新选择 (1-%d): ", mainGarage->capacity);
scanf("%d", &position);
}
mainGarage->occupied[position - 1] = true;
// Corrected linked list insertion
Node* current = mainGarage->front;
Node* prev = NULL;
int i = 1;
while (current != NULL && i < position) {
prev = current;
current = current->next;
i++;
}
newNode->next = current;
if (prev == NULL) {
mainGarage->front = newNode;
} else {
prev->next = newNode;
}
if (current == NULL) {
mainGarage->rear = newNode;
}
mainGarage->size++;
printf("装甲车 %s 已停入主装甲车库,位置:%d\n", plate, position);
} else {
printf("主装甲车库已满,无法停放更多装甲车。\n");
}
}
5、装甲车出场模块
该模块负责根据用户输入的车牌号找到对应的装甲车,将其从停车位上移除,并将停车位状态设置为空闲。
实现思想:
遍历装甲车库的停车位数组,找到车牌号匹配的停车位。 将匹配到的停车位状态设置为未占用,并清空车牌号。 如果未找到匹配的车牌号,提示用户车辆未找到。
void leaveGarage(char* plate) {
Node* current = mainGarage->front;
Node* prev = NULL;
while (current != NULL) {
if (strcmp(current->vehicle.plate, plate) == 0) {
if (prev == NULL) {
mainGarage->front = current->next;
if (mainGarage->front == NULL) {
mainGarage->rear = NULL;
}
} else {
prev->next = current->next;
if (current->next == NULL) {
mainGarage->rear = prev;
}
}
printf("装甲车 %s 离开主装甲车库,停车时长:%.2f 小时\n", plate, difftime(time(NULL), current->vehicle.arriveTime) / 3600.0);
free(current);
mainGarage->size--;
// Check if there are any vehicles in the tempGarage to move to mainGarage
if (!isEmpty(tempGarage)) {
Node* tempCar = tempGarage->front;
tempGarage->front = tempGarage->front->next;
tempGarage->size--;
tempCar->next = NULL;
if (isEmpty(mainGarage)) {
mainGarage->front = mainGarage->rear = tempCar;
} else {
mainGarage->rear->next = tempCar;
mainGarage->rear = tempCar;
}
mainGarage->size++;
printf("便道第一辆装甲车 %s 已进入主装甲车库\n", tempCar->vehicle.plate);
}
return;
}
prev = current;
current = current->next;
}
printf("未找到装甲车牌号为 %s 的装甲车。\n", plate);
}
6、装甲车状态显示模块
该模块负责显示装甲车库中每个停车位的状态,包括是否被占用以及对应的车牌号,并统计显示占用和空闲的停车位数量。 实现思想:
遍历装甲车库的停车位数组,检查每个停车位的状态。 对于每个停车位,输出其位置编号、是否被占用以及车牌号信息。 同时统计已占用和空闲的停车位数量,并在最后显示这些统计信息。
void displayStatus() {
printf("\n=== 主装甲车库状态 ===\n");
printf("总容量:%d,当前数量:%d\n", mainGarage->capacity, mainGarage->size);
Node* current = mainGarage->front; // Start at the beginning of the linked list
int vehicleIndex = 0; // Index to track the current vehicle in the list
for (int i = 0; i < mainGarage->capacity; ++i) {
if (mainGarage->occupied[i]) {
if (vehicleIndex < mainGarage->size) { // Check if there's a vehicle to display
printf("位置 %d: %s (油量: %d%%, 损坏: %d%%)\n", i + 1, current->vehicle.plate, current->vehicle.fuelLevel, current->vehicle.damageLevel);
current = current->next; // Move to the next vehicle in the list
vehicleIndex++;
}
} else {
printf("位置 %d: 空\n", i + 1);
}
}
printf("\n=== 临时便道状态 ===\n");
printf("当前等待数量:%d\n", tempGarage->size);
current = tempGarage->front;
int position = 1;
while (current != NULL) {
printf("等待位置 %d: %s\n", position++, current->vehicle.plate);
current = current->next;
}
}
7、装甲车搜索模块
该模块负责根据用户输入的车牌号在装甲车库中搜索对应的车辆,并返回车辆所在的位置或者提示车辆未找到。 实现思想:
遍历装甲车库的停车位数组,查找与输入车牌号匹配的停车位。 如果找到匹配的车牌号,返回该车辆的停车位编号。 如果遍历完成后未找到匹配的车牌号,提示用户车辆未找到。
void searchVehicle(char* plate) {
Node* current = mainGarage->front;
int position = 0;
while (current != NULL) {
position++;
if (strcmp(current->vehicle.plate, plate) == 0) {
// Find the actual parking spot using occupied array
int parkingSpot = 0;
for (int i = 0; i < mainGarage->capacity; ++i) {
if (mainGarage->occupied[i]) {
parkingSpot++;
if (parkingSpot == position) {
printf("找到装甲车 %s,位置 %d,油量 %d%%,损坏程度 %d%%\n", plate, i + 1, current->vehicle.fuelLevel, current->vehicle.damageLevel);
return;
}
}
}
return; //Should not reach here, but added for safety
}
current = current->next;
}
printf("未找到装甲车牌号为 %s 的装甲车。\n", plate);
}
8、油量冒泡排序
该模块负责显示主装甲车库中所有装甲车的油量,并按油量从低到高进行冒泡排序。
实现思想:
遍历主装甲车库的链表,收集所有装甲车的油量信息。 使用排序算法(冒泡排序)对油量信息进行排序。 显示排序后的油量信息及对应装甲车的车牌号和位置。
void displayFuelLevels() {
Node* current = mainGarage->front;
int numVehicles = mainGarage->size; // Directly use the size of the garage
if (numVehicles == 0) {
printf("装甲车为空\n");
return;
}
// 创建一个数组来存储车辆节点指针和它们的位置
Node* vehicles[numVehicles];
int positions[numVehicles];
int i = 0;
// 遍历链表填充数组
while (current != NULL) {
vehicles[i] = current;
// 找到车辆在占用数组中的位置
int pos = 0;
for (int j = 0; j < mainGarage->capacity; j++) {
if (mainGarage->occupied[j]) {
pos++;
if (pos == i + 1) {
positions[i] = j + 1;
break;
}
}
}
current = current->next;
i++;
}
// 冒泡排序,根据油量排序
for (int i = 0; i < numVehicles - 1; i++) {
for (int j = 0; j < numVehicles - i - 1; j++) {
if (vehicles[j]->vehicle.fuelLevel > vehicles[j + 1]->vehicle.fuelLevel) {
// 交换节点
Node* temp = vehicles[j];
vehicles[j] = vehicles[j + 1];
vehicles[j + 1] = temp;
// 交换位置
int tempPos = positions[j];
positions[j] = positions[j + 1];
positions[j + 1] = tempPos;
}
}
}
// 显示排序结果
printf("\n=== 按油量排序(冒泡排序) ===\n");
for (int i = 0; i < numVehicles; i++) {
printf("装甲车 %s: 油量 %d%%, 停车位 %d\n", vehicles[i]->vehicle.plate, vehicles[i]->vehicle.fuelLevel, positions[i]);
}
}
9、损坏程度快速排序
该模块负责显示主装甲车库中所有装甲车的损坏程度,并按损坏程度从低到高进行排序。
实现思想:
遍历主装甲车库的链表,收集所有装甲车的损坏程度信息。 使用排序算法(快速排序)对损坏程度信息进行排序。 显示排序后的损坏程度信息及对应装甲车的车牌号和位置。
void displayDamageLevels() {
Node* current = mainGarage->front;
int numVehicles = mainGarage->size;
if (numVehicles == 0) {
printf("装甲车库为空\n");
return;
}
// 创建一个数组来存储车辆节点指针和它们的位置
Node* vehicles[numVehicles];
int positions[numVehicles];
int i = 0;
// 遍历链表填充数组
while (current != NULL) {
vehicles[i] = current;
int pos = 0;
for (int j = 0; j < mainGarage->capacity; j++) {
if (mainGarage->occupied[j]) {
pos++;
if (pos == i + 1) {
positions[i] = j + 1;
break;
}
}
}
current = current->next;
i++;
}
// 快速排序,根据损坏程度排序
quickSort(vehicles, positions, 0, numVehicles - 1);
// 显示排序结果
printf("\n=== 按损坏程度排序(快速排序) ===\n");
for (int i = 0; i < numVehicles; i++) {
printf("装甲车 %s: 损坏程度 %d%%, 停车位 %d\n", vehicles[i]->vehicle.plate, vehicles[i]->vehicle.damageLevel, positions[i]);
}
}
// 快速排序的分区函数
int partition(Node* vehicles[], int positions[], int low, int high) {
int pivot = vehicles[high]->vehicle.damageLevel;
int i = low - 1;
for (int j = low; j <= high - 1; j++) {
if (vehicles[j]->vehicle.damageLevel <= pivot) {
i++;
Node* temp = vehicles[i];
vehicles[i] = vehicles[j];
vehicles[j] = temp;
int tempPos = positions[i];
positions[i] = positions[j];
positions[j] = tempPos;
}
}
Node* temp = vehicles[i + 1];
vehicles[i + 1] = vehicles[high];
vehicles[high] = temp;
int tempPos = positions[i + 1];
positions[i + 1] = positions[high];
positions[high] = tempPos;
return i + 1;
}
// 快速排序函数
void quickSort(Node* vehicles[], int positions[], int low, int high) {
if (low < high) {
int pivotIndex = partition(vehicles, positions, low, high);
quickSort(vehicles, positions, low, pivotIndex - 1);
quickSort(vehicles, positions, pivotIndex + 1, high);
}
}
三、数据结构确定和数据类型ADT定义
本程序采用了结构体和数组的数据结构,用于管理装甲车库状态和装甲车信息。具体地,定义了以下数据类型:
// Vehicle 结构体: 用于存储单个装甲车的车辆信息。
typedef struct {
char plate[MAX_PLATE_LEN]; // 车牌号
time_t arriveTime; // 到达时间
int fuelLevel; // 油量百分比
int damageLevel; // 损坏程度百分比
} Vehicle;
// Node 结构体: 用于创建链表节点,表示装甲车库中的每个停车位。
typedef struct Node {
Vehicle vehicle; // 装甲车信息
struct Node* next; // 指向下一个节点的指针
} Node;
// Garage 结构体:用于管理整个装甲车库,包括链表头节点、尾节点、容量、当前装甲车数量以及停车位占用状态数组。
typedef struct {
Node* front; // 链表头节点
Node* rear; // 链表尾节点
int capacity; // 最大容量
int size; // 当前装甲车数量
bool* occupied; // 停车位占用状态数组
} Garage;
四、主要算法程序框图
程序流程图如下图
• 开始后,系统显示主菜单。
• 用户根据菜单选择不同的操作:
o 选择1,输入装甲车的车牌号、油量和损坏程度,将装甲车停入主车库。
o 选择2,输入车牌号,从主车库移除装甲车。
o 选择3,显示车库的当前状态。
o 选择4,输入要查找的车牌号,搜索装甲车。
o 选择5,按油量排序显示装甲车信息。
o 选择6,按损坏程度排序显示装甲车信息。
o 选择7,保存车库状态并退出系统。
• 系统结束。
五、测试数据及结果分析(含时间、空间复杂度分析)
(一)时间复杂度
时间复杂度分析
- 主函数 main()
时间复杂度:O(k),其中 k 为用户选择功能的次数。
说明:主函数中的 while 循环会根据用户的选择执行不同的操作,每次操作的时间复杂度取决于具体的函数实现,但整体复杂度与用户操作次数成正比。 - 初始化车库 createGarage()
时间复杂度:O(1)。
说明:该函数执行固定数量的操作来初始化车库,与车库的大小无关。 - 检查车库状态
isFull() 和 isEmpty()
时间复杂度:O(1)。
说明:这两个函数仅涉及简单的比较操作,时间复杂度为常数。 - 装甲车入场 enterGarage()
时间复杂度:O(n),其中 n 为车库容量。
说明:在最坏情况下,可能需要遍历整个车库来找到空闲位置或验证用户选择的位置。 - 装甲车出场 leaveGarage()
时间复杂度:O(n),其中 n 为车库容量。
说明:在最坏情况下,需要遍历整个车库链表来找到并移除指定的装甲车。 - 显示车库状态 displayStatus()
时间复杂度:O(n),其中 n 为车库容量。
说明:该函数需要遍历车库中的每个停车位来显示其状态。 - 搜索车辆 searchVehicle()
时间复杂度:O(n),其中 n 为车库容量。
说明:在最坏情况下,需要遍历整个车库链表来查找指定的装甲车。 - 显示油量和损坏程度排序
displayFuelLevels() 和 displayDamageLevels()
时间复杂度:O(n^2),其中 n 为车库容量。
说明:这两个函数需要对所有装甲车进行排序,使用了冒泡排序或快速排序算法。快速排序的平均时间复杂度为 O(n log n),但在最坏情况下为 O(n^2)。 - 数据持久化
saveState() 和 loadState()
时间复杂度:O(n),其中 n 为车库容量。
说明:这两个函数需要遍历车库中的每个装甲车来保存或加载状态。
(二)空间复杂度
空间复杂度分析
- 初始化车库 createGarage()
空间复杂度:O(n),其中 n 为车库容量。
说明:需要为 occupied 数组分配空间,其大小与车库容量成正比。 - 装甲车入场 enterGarage() 和 装甲车出场 leaveGarage()
空间复杂度:O(1)。
说明:除了输入参数外,不需要额外的空间与车库大小成比例。 - 显示车库状态 displayStatus()、搜索车辆 searchVehicle()、显示油量排序 displayFuelLevels() 和 显示损坏程度排序 displayDamageLevels()
空间复杂度:O(n),其中 n 为车库容量。
说明:这些函数可能需要额外的数组来存储装甲车信息或进行排序,其大小与车库容量成正比。 - 数据持久化 saveState() 和 loadState()
空间复杂度:O(n),其中 n 为车库容量。
说明:需要为保存或加载的装甲车信息分配空间。
六、设计体会,存在问题及分析
(一)存在问题
车库容量的动态调整问题: 当前系统通过宏定义固定车库容量,缺乏灵活性。在实际应用中,可能需要根据实际情况动态调整车库容量。
数据持久化缺失: 系统关闭后,所有装甲车信息丢失,无法恢复。这对于需要长期运行的管理系统来说是一大缺陷。
搜索效率问题: 在大规模车库中,线性搜索效率低下,影响系统性能。
输入处理机制不足: 系统对用户输入的错误处理较为简单,缺乏智能纠错机制。
(二)遇到困难
功能模块逻辑设计: 设计车辆入场、出场和搜索功能时,需要确保逻辑的一致性和准确性,避免车位的重复分配或错误释放。
输入合法性验证: 处理用户输入时,需要确保输入的合法性,防止非法输入导致程序崩溃。
状态显示布局: 在有限的屏幕空间中清晰地展示大量停车位信息是一个设计挑战。
时间复杂度优化: 平衡代码的简单性和性能优化是一个难点,尤其是在大规模数据集上。
(三)修改与完善
动态调整车库容量: 可以考虑使用动态数据结构,如动态数组或链表,来管理停车位,以便根据需要调整车库容量。
实现数据持久化: 通过文件系统或数据库来保存装甲车信息,即使系统关闭也能恢复数据。
优化搜索算法: 引入更高效的搜索算法,如哈希表或二分搜索,以提高大规模数据集的搜索效率。
增强输入处理: 实现更智能的输入验证和错误处理机制,提供用户友好的反馈和纠错建议。
附录代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_PLATE_LEN 20
#define SAVE_FILE "garage_state.txt"
// 车辆信息结构体
typedef struct {
char plate[MAX_PLATE_LEN]; // 车牌号
time_t arriveTime; // 到达时间
int fuelLevel; // 油量百分比
int damageLevel; // 损坏程度百分比
} Vehicle;
// 装甲车库节点结构体
typedef struct Node {
Vehicle vehicle;
struct Node* next;
} Node;
// 装甲车库队列结构体
typedef struct {
Node* front;
Node* rear;
int capacity; // 最大容量
int size; // 当前数量
bool* occupied; // 停车位占用状态数组
} Garage;
Garage* mainGarage;
Garage* tempGarage;
Garage* createGarage(int capacity);
int isFull(Garage* garage);
int isEmpty(Garage* garage);
void enterGarage(char* plate, int fuelLevel, int damageLevel);
void leaveGarage(char* plate);
void displayStatus();
void searchVehicle(char* plate);
void displayFuelLevels();
void displayDamageLevels();
void displayMenu();
void saveState();
void loadState();
Garage* createGarage(int capacity) {
Garage* garage = (Garage*)malloc(sizeof(Garage));
if (garage == NULL) {
perror("Memory allocation failed for garage");
exit(1); // Exit with an error code
}
garage->front = garage->rear = NULL;
garage->capacity = capacity;
garage->size = 0;
garage->occupied = (bool*)calloc(capacity, sizeof(bool)); // Allocate memory for occupied array
if (garage->occupied == NULL) {
perror("Memory allocation failed for occupied array");
free(garage); // Free the garage memory since allocation failed
exit(1); // Exit with an error code
}
return garage;
}
int isFull(Garage* garage) {
return garage->size >= garage->capacity;
}
int isEmpty(Garage* garage) {
return garage->size == 0;
}
void enterGarage(char* plate, int fuelLevel, int damageLevel) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
perror("Memory allocation failed");
return;
}
strcpy(newNode->vehicle.plate, plate);
newNode->vehicle.arriveTime = time(NULL);
newNode->vehicle.fuelLevel = fuelLevel;
newNode->vehicle.damageLevel = damageLevel;
newNode->next = NULL;
if (!isFull(mainGarage)) {
int position;
printf("请选择停装甲车位 (1-%d): ", mainGarage->capacity);
scanf("%d", &position);
// Input validation and error handling
while (position < 1 || position > mainGarage->capacity || mainGarage->occupied[position - 1]) {
printf("无效的装甲车位选择,该位置已被占用或超出范围。请重新选择 (1-%d): ", mainGarage->capacity);
scanf("%d", &position);
}
mainGarage->occupied[position - 1] = true;
// Corrected linked list insertion
Node* current = mainGarage->front;
Node* prev = NULL;
int i = 1;
while (current != NULL && i < position) {
prev = current;
current = current->next;
i++;
}
newNode->next = current;
if (prev == NULL) {
mainGarage->front = newNode;
} else {
prev->next = newNode;
}
if (current == NULL) {
mainGarage->rear = newNode;
}
mainGarage->size++;
printf("装甲车 %s 已停入主装甲车库,位置:%d\n", plate, position);
} else {
// 临时车位处理
if (isEmpty(tempGarage)) {
tempGarage->front = tempGarage->rear = newNode;
} else {
tempGarage->rear->next = newNode;
tempGarage->rear = newNode;
}
tempGarage->size++;
printf("主装甲车库已满,装甲车车辆 %s 已停入临时便道,位置:%d\n", plate, tempGarage->size);
}
}
void leaveGarage(char* plate) {
Node* current = mainGarage->front;
Node* prev = NULL;
while (current != NULL) {
if (strcmp(current->vehicle.plate, plate) == 0) {
if (prev == NULL) {
mainGarage->front = current->next;
if (mainGarage->front == NULL) {
mainGarage->rear = NULL;
}
} else {
prev->next = current->next;
if (current->next == NULL) {
mainGarage->rear = prev;
}
}
printf("装甲车 %s 离开主装甲车库,停车时长:%.2f 小时\n", plate, difftime(time(NULL), current->vehicle.arriveTime) / 3600.0);
free(current);
mainGarage->size--;
if (!isEmpty(tempGarage)) {
Node* tempCar = tempGarage->front;
tempGarage->front = tempGarage->front->next;
tempGarage->size--;
tempCar->next = NULL;
if (isEmpty(mainGarage)) {
mainGarage->front = mainGarage->rear = tempCar;
} else {
mainGarage->rear->next = tempCar;
mainGarage->rear = tempCar;
}
mainGarage->size++;
printf("便道第一辆装甲车 %s 已进入主装甲车库\n", tempCar->vehicle.plate);
}
return;
}
prev = current;
current = current->next;
}
printf("未找到装甲车 %s\n", plate);
}
void displayFuelLevels() {
Node* current = mainGarage->front;
int numVehicles = mainGarage->size; // Directly use the size of the garage
if (numVehicles == 0) {
printf("装甲车为空\n");
return;
}
Node* vehicles[numVehicles];
int positions[numVehicles];
int i = 0;
// Correctly iterate through the linked list to populate the arrays
while (current != NULL) {
vehicles[i] = current;
// Find the position of the vehicle in the occupied array
int pos = 0;
for (int j = 0; j < mainGarage->capacity; j++) {
if (mainGarage->occupied[j]) {
pos++;
if (pos == i + 1) {
positions[i] = j + 1;
break;
}
}
}
current = current->next;
i++;
}
// 冒泡排序
for (int i = 0; i < numVehicles - 1; i++) {
for (int j = 0; j < numVehicles - i - 1; j++) {
if (vehicles[j]->vehicle.fuelLevel < vehicles[j + 1]->vehicle.fuelLevel) {
Node* temp = vehicles[j];
vehicles[j] = vehicles[j + 1];
vehicles[j + 1] = temp;
int tempPos = positions[j];
positions[j] = positions[j + 1];
positions[j + 1] = tempPos;
}
}
}
printf("\n=== 按油量排序(冒泡排序) ===\n");
for (int i = 0; i < numVehicles; i++) {
printf("装甲车 %s: 油量 %d%%, 停车位 %d\n", vehicles[i]->vehicle.plate, vehicles[i]->vehicle.fuelLevel, positions[i]);
}
}
// 快速排序
int partition(Node* vehicles[], int positions[], int low, int high) {
int pivot = vehicles[high]->vehicle.damageLevel;
int i = low - 1;
for (int j = low; j <= high - 1; j++) {
if (vehicles[j]->vehicle.damageLevel <= pivot) {
i++;
Node* temp = vehicles[i];
vehicles[i] = vehicles[j];
vehicles[j] = temp;
int tempPos = positions[i];
positions[i] = positions[j];
positions[j] = tempPos;
}
}
Node* temp = vehicles[i + 1];
vehicles[i + 1] = vehicles[high];
vehicles[high] = temp;
int tempPos = positions[i + 1];
positions[i + 1] = positions[high];
positions[high] = tempPos;
return i + 1;
}
void quickSort(Node* vehicles[], int positions[], int low, int high) {
if (low < high) {
int pivotIndex = partition(vehicles, positions, low, high);
quickSort(vehicles, positions, low, pivotIndex - 1);
quickSort(vehicles, positions, pivotIndex + 1, high);
}
}
void displayDamageLevels() {
Node* current = mainGarage->front;
int numVehicles = mainGarage->size;
if (numVehicles == 0) {
printf("装甲车库为空\n");
return;
}
Node* vehicles[numVehicles];
int positions[numVehicles];
int i = 0;
while (current != NULL) {
vehicles[i] = current;
int pos = 0;
for (int j = 0; j < mainGarage->capacity; j++) {
if (mainGarage->occupied[j]) {
pos++;
if (pos == i + 1) {
positions[i] = j + 1;
break;
}
}
}
current = current->next;
i++;
}
quickSort(vehicles, positions, 0, numVehicles - 1);
printf("\n=== 按损坏程度排序(快速排序) ===\n");
for (int i = 0; i < numVehicles; i++) {
printf("装甲车 %s: 损坏程度 %d%%, 停车位 %d\n", vehicles[i]->vehicle.plate, vehicles[i]->vehicle.damageLevel, positions[i]);
}
}
void displayStatus() {
printf("\n=== 主装甲车库状态 ===\n");
printf("总容量:%d,当前数量:%d\n", mainGarage->capacity, mainGarage->size);
Node* current = mainGarage->front; // Start at the beginning of the linked list
int vehicleIndex = 0; // Index to track the current vehicle in the list
for (int i = 0; i < mainGarage->capacity; ++i) {
if (mainGarage->occupied[i]) {
if (vehicleIndex < mainGarage->size) { // Check if there's a vehicle to display
printf("位置 %d: %s (油量: %d%%, 损坏: %d%%)\n", i + 1, current->vehicle.plate, current->vehicle.fuelLevel, current->vehicle.damageLevel);
current = current->next; // Move to the next vehicle in the list
vehicleIndex++;
}
} else {
printf("位置 %d: 空\n", i + 1);
}
}
printf("\n=== 临时便道状态 ===\n");
printf("当前等待数量:%d\n", tempGarage->size);
current = tempGarage->front;
int position = 1;
while (current != NULL) {
printf("等待位置 %d: %s\n", position++, current->vehicle.plate);
current = current->next;
}
}
void loadState() {
FILE* file = fopen(SAVE_FILE, "r");
if (!file) {
printf("未找到保存文件,将初始化系统。\n");
return;
}
fscanf(file, "%d", &mainGarage->capacity);
mainGarage->size = 0;
mainGarage->front = mainGarage->rear = NULL;
char plate[MAX_PLATE_LEN];
int fuelLevel, damageLevel;
time_t arriveTime;
while (fscanf(file, "%s %ld %d %d", plate, &arriveTime, &fuelLevel, &damageLevel) == 4) {
enterGarage(plate, fuelLevel, damageLevel);
}
fclose(file);
printf("系统状态已加载。\n");
}
void saveState() {
FILE* file = fopen(SAVE_FILE, "w");
if (!file) {
printf("保存失败。\n");
return;
}
fprintf(file, "%d\n", mainGarage->capacity);
Node* current = mainGarage->front;
while (current) {
fprintf(file, "%s %ld %d %d\n", current->vehicle.plate, current->vehicle.arriveTime,
current->vehicle.fuelLevel, current->vehicle.damageLevel);
current = current->next;
}
fclose(file);
printf("系统状态已保存。\n");
}
void searchVehicle(char* plate) {
Node* current = mainGarage->front;
int position = 0;
while (current != NULL) {
position++;
if (strcmp(current->vehicle.plate, plate) == 0) {
// Find the actual parking spot using occupied array
int parkingSpot = 0;
for (int i = 0; i < mainGarage->capacity; ++i) {
if (mainGarage->occupied[i]) {
parkingSpot++;
if (parkingSpot == position) {
printf("找到装甲车 %s,位置 %d,油量 %d%%,损坏程度 %d%%\n", plate, i + 1, current->vehicle.fuelLevel, current->vehicle.damageLevel);
return;
}
}
}
return; //Should not reach here, but added for safety
}
current = current->next;
}
printf("未找到装甲车牌号为 %s 的装甲车。\n", plate);
}
void displayMenu() {
printf("\n=== 装甲车库车辆动态监控辅助记录系统 ===\n");
printf("1. 装甲车辆入场\n");
printf("2. 装甲车辆出场\n");
printf("3. 显示装甲车库状态\n");
printf("4. 按照装甲车牌号查询车辆\n");
printf("5. 查询装甲车辆油量并按油量排序\n");
printf("6. 查询装甲车辆装备损坏情况并按损坏程度排序\n");
printf("7. 保存并退出系统\n");
printf("请选择操作 (1-7): ");
}
int main() {
int choice;
char plate[MAX_PLATE_LEN];
int fuelLevel, damageLevel, garageCapacity;
mainGarage = createGarage(0);
tempGarage = createGarage(100);
loadState();
if (mainGarage->capacity == 0) {
printf("请输入主装甲车库容量:");
scanf("%d", &garageCapacity);
mainGarage->capacity = garageCapacity;
}
while (1) {
displayMenu();
scanf("%d", &choice);
switch (choice) {
case 1:
printf("请输入车牌号:");
scanf("%s", plate);
printf("请输入油量百分比:");
scanf("%d", &fuelLevel);
printf("请输入损坏程度百分比:");
scanf("%d", &damageLevel);
enterGarage(plate, fuelLevel, damageLevel);
break;
case 2:
printf("请输入车牌号:");
scanf("%s", plate);
leaveGarage(plate);
break;
case 3:
displayStatus();
break;
case 4:
printf("请输入要查找的车牌号:");
scanf("%s", plate);
searchVehicle(plate);
break;
case 5:
displayFuelLevels();
break;
case 6:
displayDamageLevels();
break;
case 7:
saveState();
printf("系统已保存,感谢使用!\n");
free(mainGarage);
free(tempGarage);
return 0;
default:
printf("无效选择,请重试\n");
}
}
return 0;
}
嗨,我是LucianaiB。如果你觉得我的分享有价值,不妨通过以下方式表达你的支持:👍 点赞来表达你的喜爱,📁 关注以获取我的最新消息,💬 评论与我交流你的见解。我会继续努力,为你带来更多精彩和实用的内容。
点击这里👉LucianaiB ,获取最新动态,⚡️ 让信息传递更加迅速。