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


🌟 嗨,我是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 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,保存车库状态并退出系统。
• 系统结束。

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

(一)时间复杂度

时间复杂度分析

  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 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 ,获取最新动态,⚡️ 让信息传递更加迅速。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/956190.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python+django+Nacos实现配置动态更新-集中管理配置(实现mysql配置动态读取及动态更新)

一、docker-compose.yml 部署nacos服务 version: "3" services:mysql:container_name: mysql# 5.7image: mysql:5.7environment:# mysql root用户密码MYSQL_ROOT_PASSWORD: rootTZ: Asia/Shanghai# 初始化数据库(后续的初始化sql会在这个库执行)MYSQL_DATABASE: nac…

OpenEuler学习笔记(一):常见命令

OpenEuler是一个开源操作系统&#xff0c;有许多命令可以用于系统管理、软件安装、文件操作等诸多方面。以下是一些常见的命令&#xff1a; 一、系统信息查看命令 uname 用途&#xff1a;用于打印当前系统相关信息&#xff0c;如内核名称、主机名、内核版本等。示例&#xff…

聊聊如何实现Android 放大镜效果

一、前言 很久没有更新Android 原生技术内容了&#xff0c;前些年一直在做跨端方向开发&#xff0c;最近换工作用重新回到原生技术&#xff0c;又回到了熟悉但有些生疏的环境&#xff0c;真是感慨万分。 近期也是因为准备做地图交互相关的需求&#xff0c;功能非常复杂&#x…

C++,设计模式,【目录篇】

文章目录 1. 简介2. 设计模式的分类2.1 创建型模式&#xff08;Creational Patterns&#xff09;&#xff1a;2.2 结构型模式&#xff08;Structural Patterns&#xff09;&#xff1a;2.3 行为型模式&#xff08;Behavioral Patterns&#xff09;&#xff1a; 3. 使用设计模式…

RabbitMQ集群安装rabbitmq_delayed_message_exchange

1、单节点安装rabbitmq安装延迟队列 安装延迟队列rabbitmq_delayed_message_exchange可以参考这个文章&#xff1a; rabbitmq安装延迟队列-CSDN博客 2、集群安装rabbitmq_delayed_message_exchange 在第二个节点 join_cluster 之后&#xff0c;start_app 就会报错了 (CaseC…

【C++】如何从源代码编译红色警戒2地图编辑器

【C】如何从源代码编译红色警戒2地图编辑器 操作视频视频中的代码不需要下载三方库&#xff0c;已经包含三方库。 一、运行效果&#xff1a;二、源代码来源及编程语言&#xff1a;三、环境搭建&#xff1a;安装红警2安装VS2022下载代码&#xff0c;源代码其实不太多&#xff0c…

下定决心不去读研了。。。

大家好&#xff0c;我是苍何。 之前发表过一篇文章&#xff0c;表达了自己读研的困惑和纠结&#xff0c;得到了大家很多的建议&#xff0c;也引起了很多人的共鸣&#xff0c;在留言区分享了自己的故事&#xff0c;看着这些故事&#xff0c;我觉得都够苍何写一部小说了。 可惜苍…

重温STM32之环境安装

缩写 CMSIS&#xff1a;common microcontroller software interface standard 1&#xff0c;keil mdk安装 链接 Keil Product Downloads 安装好后&#xff0c;开始安装平台软件支持包&#xff08;keil 5后不在默认支持所有的平台软件开发包&#xff0c;需要自行下载&#…

[苍穹外卖] 1-项目介绍及环境搭建

项目介绍 定位&#xff1a;专门为餐饮企业&#xff08;餐厅、饭店&#xff09;定制的一款软件产品 功能架构&#xff1a; 管理端 - 外卖商家使用 用户端 - 点餐用户使用 技术栈&#xff1a; 开发环境的搭建 整体结构&#xff1a; 前端环境 前端工程基于 nginx 运行 - Ngi…

能源物联网数据采集设备 串口服务器功能参数介绍

摘要 ​随着物联网技术的快速发展&#xff0c;各种传统设备的联网需求愈发迫切。串口服务器作为一种桥接传统串口设备与现代网络的关键设备&#xff0c;在工业控制、智能电网、交通运输等域发挥了重要作用。本文以APort100串口服务器为例&#xff0c;探讨串口服务器在现代物联…

20250118拿掉荣品pro-rk3566开发板上Android13下在uboot和kernel启动阶段的Rockchip这个LOGO标识

20250118拿掉荣品pro-rk3566开发板上Android13下在uboot和kernel启动阶段的Rockchip这个LOGO标识 2025/1/18 15:12 缘起&#xff1a;做飞凌OK3588-C开发板/核心板【Linux R4】的时候&#xff0c;测试/生产要求没有开机LOGO【飞凌/Rockchip】 要求&#xff1a;黑屏或者中性界面。…

【STM32-学习笔记-4-】PWM、输入捕获(PWMI)

文章目录 1、PWMPWM配置 2、输入捕获配置3、编码器 1、PWM PWM配置 配置时基单元配置输出比较单元配置输出PWM波的端口 #include "stm32f10x.h" // Device headervoid PWM_Init(void) { //**配置输出PWM波的端口**********************************…

RocketMQ源码之消息刷盘分析

前言 刷盘是将内存中的消息写入磁盘,分为同步刷盘和异步刷盘。同步刷盘指一条消息写入磁盘才返回成功,异步刷盘指写入内存就返回成功,稍后异步线程刷盘。 在创建CommitLog对象的时候,会初始化刷盘服务: //代码位置:org.apache.rocketmq.store.CommitLog public CommitL…

navicat 折线图或面积图

折线图或面积图将信息显示为以直线段连接的一系列数据点。 折线图 面积图 堆积面积图 图表属性 选择图表类型后&#xff0c;可以更改其属性来自定义图表&#xff1a; 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框…

【数模学习笔记】插值算法和拟合算法

声明&#xff1a;以下笔记中的图片以及内容 均整理自“数学建模学习交流”清风老师的课程资料&#xff0c;仅用作学习交流使用 文章目录 插值算法定义三个类型插值举例插值多项式分段插值三角插值 一般插值多项式原理拉格朗日插值法龙格现象分段线性插值 牛顿插值法 Hermite埃尔…

机器学习皮马印第安人糖尿病数据集预测报告

目录 1.项目选题与设计方案 1.1项目选题 1.2设计方案 2.功能实现 2.1 主要功能介绍 2.2 开发环境及平台介绍 2.3 实现过程 2.3.1数据分析 2.3.2算法设计 2.3.3 python代码 3.个人心得体会 1.项目选题与设计方案 1.1项目选题 我国的糖尿病患者初诊时约&#xff18;&a…

STM32 FreeRTOS任务通知

目录 任务通知的简介 任务通知相关API函数介绍 任务通知的简介 任务通知是 FreeRTOS 中一种用于任务间通信的机制&#xff0c;它允许一个任务向其他任务发送简单的通知或信号&#xff0c;以实现任务间的同步和协作。任务通知通常用于替代二值信号量或事件标志组&#xff0c;提…

提示词的艺术----AI Prompt撰写指南(个人用)

提示词的艺术 写在前面 制定提示词就像是和朋友聊天一样&#xff0c;要求我们能够清楚地表达问题。通过这个过程&#xff0c;一方面要不断练习提高自己地表达能力&#xff0c;另一方面还要锻炼自己使用更准确精炼的语言提出问题的能力。 什么样的提示词有用&#xff1f; 有…

微服务网关,如何选择?

什么是API网关 API网关&#xff08;API Gateway&#xff09;是微服务架构中的一个关键组件&#xff0c;它充当了客户端与后端服务之间的中间层。其主要功能包括请求路由、协议转换、负载均衡、安全认证、限流熔断等。通过API网关&#xff0c;客户端无需直接与多个微服务交互&a…

PortSwigger靶场练习---第二关-查找和利用未使用的 API 端点

第二关&#xff1a;Finding and exploiting an unused API endpoint 实验&#xff1a;查找和利用未使用的 API 端点 PortSwigger靶场地址&#xff1a; Dashboard | Web Security Academy - PortSwigger 题目&#xff1a; 官方提示&#xff1a; 在 Burp 的浏览器中&#xff0c…