C语言之装甲车库车辆动态监控辅助记录系统

devtools/2025/1/20 19:27:49/


🌟 嗨,我是LucianaiB!

🌍 总有人间一两风,填我十万八千梦。

🚀 路漫漫其修远兮,吾将上下而求索。


C语言之装甲车库车辆动态监控辅助记录系统

目录

  1. 一、前言
    1.1 (一)问题描述
    1.2 (二)算法输入
  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、损坏程度快速排序
  3. 三、数据结构确定和数据类型ADT定义
  4. 四、主要算法程序框图
  5. 五、测试数据及结果分析(含时间、空间复杂度分析)
    5.1 (一)时间复杂度
    5.2 (二)空间复杂度
  6. 六、设计体会,存在问题及分析
    6.1 (一)存在问题
    6.2 (二)遇到困难
    6.3 (三)修改与完善
  7. 附录代码

一、前言

(一)问题描述

设计一个狭长通道装甲车库车辆动态监控辅助记录系统的管理程序,实现装甲车默认按先后顺序停放,也可以自选位置停放、出场时让装甲车按车牌号离开车库的功能。
在这里插入图片描述
在这里插入图片描述

(二)算法输入

装甲车入场:
用户选择菜单中的“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. 查询装甲车辆装备损坏情况并按损坏程度排序”功能,按照快速排序从损坏程度小到大进行排序并输出。

在这里插入图片描述

二、算法要点描述与实现思想

(一)算法要点

  1. 装甲车库创建模块:
    o 使用 createGarage 函数初始化装甲车库,分配内存并设置初始状态,包括前驱和后继指针、容量、大小以及占用状态数组。
  2. 装甲车库状态检查模块:
    o isFull 函数检查装甲车库是否已满,即当前数量是否达到最大容量。
    o isEmpty 函数检查装甲车库是否为空,即当前数量是否为零。
  3. 装甲车辆入场模块:
    o enterGarage 函数处理装甲车辆的入场,包括用户选择停车位、输入车辆信息,并将其添加到链表中相应的位置。
    o 如果主装甲车库未满,将车辆信息添加到主车库的链表中,并更新占用状态。
    o 如果主装甲车库已满,将车辆信息添加到临时车库的链表中。
  4. 装甲车辆出场模块:
    o leaveGarage 函数处理装甲车辆的出场,遍历主装甲车库的链表找到对应车辆,并更新链表和占用状态。
    o 如果临时车库有车辆,将临时车库中的第一辆车移动到主车库中空出的位置上。
  5. 装甲车库状态显示模块:
    o displayStatus 函数显示主装甲车库和临时车库的当前状态,包括每个车位的车辆信息和空位。
  6. 装甲车辆搜索模块:
    o searchVehicle 函数根据车牌号搜索车辆,遍历主装甲车库的链表,找到对应车辆后显示其信息。
  7. 装甲车辆油量显示模块:
    o displayFuelLevels 函数显示主装甲车库中所有车辆的油量信息,并按油量进行冒泡排序。
  8. 装甲车辆损坏程度显示模块:
    o displayDamageLevels 函数显示主装甲车库中所有车辆的损坏程度信息,并使用快速排序算法按损坏程度排序。
  9. 数据持久化模块:
    o saveState 和 loadState 函数分别用于保存和加载装甲车库的状态,包括车辆信息和占用状态。
  10. 主控菜单模块:
    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 handlingwhile (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 insertionNode* 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 mainGarageif (!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 listint vehicleIndex = 0;             // Index to track the current vehicle in the listfor (int i = 0; i < mainGarage->capacity; ++i) {if (mainGarage->occupied[i]) {if (vehicleIndex < mainGarage->size) { // Check if there's a vehicle to displayprintf("位置 %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 listvehicleIndex++;}} 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 arrayint 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 garageif (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,保存车库状态并退出系统。
• 系统结束。

五、测试数据及结果分析(含时间、空间复杂度分析)

(一)时间复杂度

时间复杂度分析

  1. 主函数 main()
    时间复杂度:O(k),其中 k 为用户选择功能的次数。
    说明:主函数中的 while 循环会根据用户的选择执行不同的操作,每次操作的时间复杂度取决于具体的函数实现,但整体复杂度与用户操作次数成正比。
  2. 初始化车库 createGarage()
    时间复杂度:O(1)。
    说明:该函数执行固定数量的操作来初始化车库,与车库的大小无关。
  3. 检查车库状态
    isFull() 和 isEmpty()
    时间复杂度:O(1)。
    说明:这两个函数仅涉及简单的比较操作,时间复杂度为常数。
  4. 装甲车入场 enterGarage()
    时间复杂度:O(n),其中 n 为车库容量。
    说明:在最坏情况下,可能需要遍历整个车库来找到空闲位置或验证用户选择的位置。
  5. 装甲车出场 leaveGarage()
    时间复杂度:O(n),其中 n 为车库容量。
    说明:在最坏情况下,需要遍历整个车库链表来找到并移除指定的装甲车。
  6. 显示车库状态 displayStatus()
    时间复杂度:O(n),其中 n 为车库容量。
    说明:该函数需要遍历车库中的每个停车位来显示其状态。
  7. 搜索车辆 searchVehicle()
    时间复杂度:O(n),其中 n 为车库容量。
    说明:在最坏情况下,需要遍历整个车库链表来查找指定的装甲车。
  8. 显示油量和损坏程度排序
    displayFuelLevels() 和 displayDamageLevels()
    时间复杂度:O(n^2),其中 n 为车库容量。
    说明:这两个函数需要对所有装甲车进行排序,使用了冒泡排序或快速排序算法。快速排序的平均时间复杂度为 O(n log n),但在最坏情况下为 O(n^2)。
  9. 数据持久化
    saveState() 和 loadState()
    时间复杂度:O(n),其中 n 为车库容量。
    说明:这两个函数需要遍历车库中的每个装甲车来保存或加载状态。

(二)空间复杂度

空间复杂度分析

  1. 初始化车库 createGarage()
    空间复杂度:O(n),其中 n 为车库容量。
    说明:需要为 occupied 数组分配空间,其大小与车库容量成正比。
  2. 装甲车入场 enterGarage() 和 装甲车出场 leaveGarage()
    空间复杂度:O(1)。
    说明:除了输入参数外,不需要额外的空间与车库大小成比例。
  3. 显示车库状态 displayStatus()、搜索车辆 searchVehicle()、显示油量排序 displayFuelLevels() 和 显示损坏程度排序 displayDamageLevels()
    空间复杂度:O(n),其中 n 为车库容量。
    说明:这些函数可能需要额外的数组来存储装甲车信息或进行排序,其大小与车库容量成正比。
  4. 数据持久化 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 arrayif (garage->occupied == NULL) {perror("Memory allocation failed for occupied array");free(garage); // Free the garage memory since allocation failedexit(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 handlingwhile (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 insertionNode* 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 garageif (numVehicles == 0) {printf("装甲车为空\n");return;}Node* vehicles[numVehicles];int positions[numVehicles];int i = 0;// Correctly iterate through the linked list to populate the arrayswhile (current != NULL) {vehicles[i] = current;// Find the position of the vehicle in the occupied arrayint 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 listint vehicleIndex = 0;             // Index to track the current vehicle in the listfor (int i = 0; i < mainGarage->capacity; ++i) {if (mainGarage->occupied[i]) {if (vehicleIndex < mainGarage->size) { // Check if there's a vehicle to displayprintf("位置 %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 listvehicleIndex++;}} 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 arrayint 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 ,获取最新动态,⚡️ 让信息传递更加迅速。


http://www.ppmy.cn/devtools/152168.html

相关文章

03.选择排序

一、题目思路 选择排序是一种简单直观的排序算法。它的工作原理是&#xff1a;首先在未排序序列中找到最小&#xff08;或最大&#xff09;元素&#xff0c;存放到排序序列的起始位置&#xff0c;然后&#xff0c;再从剩余未排序元素中继续寻找最小&#xff08;或最大&#xff…

计算机毕业设计Python+卷积神经网络租房推荐系统 租房大屏可视化 租房爬虫 hadoop spark 58同城租房爬虫 房源推荐系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

C#如何获取电脑中的端口号和硬件信息

我们经常在使用一个串口软件的时候&#xff0c;发现软件中的端口号并不是普通的COM1&#xff0c;而是带有硬件信息的。 那么如果我们使用C#编写软件时候&#xff0c;如何获取到串口的硬件信息呢&#xff1f; 思路就是通过读取设备管理器里的条目来实现&#xff0c;我这里给大家…

HTML5+Canvas实现的鼠标跟随自定义发光线条源码

源码介绍 HTML5Canvas实现的鼠标跟随自定义发光线条特效源码非常炫酷&#xff0c;在黑色的背景中&#xff0c;鼠标滑过即产生彩色变换的发光线条效果&#xff0c;且线条周围散发出火花飞射四溅的粒子光点特效。 效果预览 源码如下 <!DOCTYPE html PUBLIC "-//W3C//D…

Spring Web MVC综合案例

承接上篇文章——Spring Web MVC探秘&#xff0c;在了解Spring Web MVC背后的工作机制之后&#xff0c;我们接下来通过三个实战项目&#xff0c;来进一步巩固一下前面的知识。 一、计算器 效果展示&#xff1a;访问路径&#xff1a;http://127.0.0.1:8080/calc.html 前端代码&a…

Reactor 模式在 Edis、Nginx 和 Netty 中的应用与高性能网络模式解析

文章目录 参考文章Reactor 模式在 Edis、Nginx 和 Netty 中的应用与高性能网络模式解析一、Reactor 模式二、Redis 中的 Reactor 模式三、Nginx 中的 Reactor 模式四、Netty 中的 Reactor 模式五、Reactor 模式的优势六、总结 参考文章 redis&#xff0c;nginx&#xff0c;net…

掌握AutoGen:轻松控制多Agent框架中的代理对话退出(28/30)

一、AutoGen 框架初相识 在人工智能的蓬勃发展进程中&#xff0c;多智能体系统已然成为研究与应用的焦点领域。而 AutoGen 框架&#xff0c;作为多智能体对话领域的璀璨新星&#xff0c;正以其独特的魅力与强大的功能&#xff0c;引领着这一领域的创新潮流。它为开发者们搭建了…

【Redis】win10安装Redis

如果需要&#xff0c;先卸载 WIN10如何卸载redis_mob64ca12f831ae的技术博客_51CTO博客 下载 Releases tporadowski/redis (github.com) 我这里选择压缩包&#xff0c;需要手动解压、初始化、配置和安装服务 解压 启动 进入安装目录&#xff0c;这个cmd关闭即停止redis服…