这个代码实现了一个停车场管理系统,主要功能包括车辆信息的添加、删除、修改、查找、显示所有车辆信息、排序以及计算停车费用。系统使用双向链表来存储车辆数据,并提供了菜单驱动的界面供用户选择不同的操作。
主要功能描述:
-
添加车辆信息:
用户可以选择添加新的车辆信息,包括车牌号、车辆类型、停放时间等。 -
删除车辆信息:
通过输入车牌号,可以从系统中删除相应的车辆记录。 -
修改车辆信息:
用户可以修改指定车牌号的车辆信息,如更新停放时间或车辆类型。 -
查找车辆信息:
根据输入的车牌号,查找并显示该车辆的详细信息。 -
显示所有车辆:
列出当前系统中所有已登记的车辆信息。 -
排序功能:
用户可以选择按停放时间或车辆类型对车辆进行排序,并显示排序后的结果。 -
计算停车费用:
根据车辆的停放时间计算停车费用。 -
数据持久化:
系统能够从文件中加载车辆数据,并在退出时将数据保存到文件中,以实现数据的持久化。
实现方式:
-
数据结构:
使用双向链表(SLIST)来存储车辆数据,便于插入、删除和遍历操作。 -
文件操作:
通过load_cars_from_file
和save_cars_to_file
函数实现数据的读取和保存,使用二进制文件格式。 -
用户交互:
提供菜单选项,用户可以通过输入数字选择相应的操作,界面清晰,操作简便。 -
临时排序:
在排序功能中,创建临时链表复制原始数据进行排序,确保原始数据不被修改,排序后显示结果并释放临时链表。
代码结构:
-
主函数:
初始化链表,加载数据,显示菜单,处理用户选择,执行相应操作,保存数据并释放资源。 -
辅助函数:
包括链表操作(初始化、添加、删除、查找等)、数据输入输出、排序、费用计算等功能,模块化设计,便于维护和扩展。
代码演示:
car.h
功能:用于声明车辆数据结构和计费功能函数。头文件的主要作用是提供数据结构和函数声明,以便在其他源文件中使用这些定义和声明。
// 定义车辆数据结构和计费功能函数声明
#ifndef CAR_H
#define CAR_H#define MAX_STRING_LENGTH 100typedef struct
{char carnumber[MAX_STRING_LENGTH]; // 车牌号char brand[MAX_STRING_LENGTH]; // 品牌char model[MAX_STRING_LENGTH]; // 型号char cartype[MAX_STRING_LENGTH]; // 车辆类型int parktime; // 停车时间
} DATA;float calculate_fee(int parktime);#endif
car.c:计费功能实现
规则:不满1小时不收费,超过1小时按10元每小时收费
// 计费功能实现
#include "car.h"float calculate_fee(int parktime)
{if (parktime <= 1){return 0.0; // 前一个小时免费}else{return (parktime - 1) * 10.0; // 1小时后每小时计费10元}
}
function.h : 进行菜单函数定义和功能函数声明
// 头文件,声明函数原型
#ifndef FUNCTION_H
#define FUNCTION_H#include "slist.h"// 菜单函数
void display_menu();
// 录入车辆数据函数
void input_car_data(DATA *data);
// 显示车辆数据函数
void display_car_data(DATA *data);
// 保存文件数据函数
void save_cars_to_file(const char *filename, SLIST *list);
// 读取文件数据函数
void load_cars_from_file(const char *filename, SLIST *list);
// 停放时间排序函数
void sort_cars_by_parking_time(SLIST *list);
// 车辆类型排序函数
void sort_cars_by_type(SLIST *list);
// 缓存链表创建函数
void copy_list(SLIST *dest, SLIST *src);#endif
function.c:实现主界面显示和文件IO(写入、加载),以及排序算法功能
// 实现主界面显示和文件IO、排序算法
#include "function.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>void display_menu()
{// 设置终端颜色为绿色printf("\033[1;36m");printf(" ______ ______\n");printf(" /|_||_\\`.__ /|_||_\\`.__\n");printf(" ( _ _ _\\ ( _ _ _\\\n");printf(" =`-(_)--(_)-' ______ =`-(_)--(_)-'\n");// 重置终端颜色printf("\033[0m\n");// 设置终端颜色为蓝色printf("\033[1;34m");printf("========================================\n");printf("= =\n");printf("= 停车场车辆管理系统 =\n");printf("= 🚕 🚕 🚕 =\n");printf("========================================\n");// 重置终端颜色printf("\033[0m\n");printf("\n");printf("\033[1;96m ------------------------------\033[0m \n");printf("\033[1;96;5m"); // 5是闪烁效果printf(" /\\_____/\\ -----------------------------\n");printf(" / o o \\ --- | Welcome to Parking System |\n");printf(" ( == ^ == ) -----------------------------\n");printf(" )----O----(\n");printf(" ( )\n");printf(" ( ( ) ( ) )\n");printf(" (__(__)___(__)__) \n");printf("\033[0m"); // 重置样式printf("\033[1;96m ------------------------------\033[0m \n");printf("\n");// 设置终端颜色为黄色printf("\033[1;35m");printf("+--------------------------------------+\n");printf("| 1. 添加车辆信息..................... |\n");printf("| 2. 删除车辆信息..................... |\n");printf("| 3. 修改车辆信息..................... |\n");printf("| 4. 查找车辆信息..................... |\n");printf("| 5. 显示所有车辆..................... |\n");printf("| 6. 排序功能实现..................... |\n");printf("| 7. 计算停车费用..................... |\n");printf("| 0. 退出............................. |\n");printf("+--------------------------------------+\n");// 重置终端颜色printf("\033[0m");
}// 定义输入车辆数据函数
void input_car_data(DATA *data)
{printf("输入车牌号: ");scanf("%s", data->carnumber);printf("输入品牌: ");scanf("%s", data->brand);printf("输入型号: ");scanf("%s", data->model);printf("输入车辆类型: ");scanf("%s", data->cartype);printf("输入停放时间(小时): ");scanf("%d", &data->parktime);
}// 定义显示车辆数据函数
void display_car_data(DATA *data)
{printf("车牌号: %s\n", data->carnumber);printf("品牌: %s\n", data->brand);printf("型号: %s\n", data->model);printf("车辆类型: %s\n", data->cartype);printf("停车时长: %d 小时\n", data->parktime);float fee = calculate_fee(data->parktime);printf("停车费用: %.2f 元\n", fee);printf("------------------------\n");
}// 定义将链表中的数据保存到文件中的函数
void save_cars_to_file(const char *filename, SLIST *list)
{// const char *filename:要保存的文件名。// SLIST *list:要保存数据的链表。FILE *file = fopen(filename, "wb");if (file == NULL){printf("无法打开文件 %s\n", filename);return;}NODE *current = list->head;// 遍历链表,写入数据到链表中while (current != NULL){fwrite(¤t->data, sizeof(DATA), 1, file);current = current->next;}fclose(file);
}// 定义了从指定文件中读取数据并加载到链表中的函数
void load_cars_from_file(const char *filename, SLIST *list)
{// const char *filename:要加载的文件名// SLIST *list :要加载数据到的链表FILE *file = fopen(filename, "rb");if (file == NULL){printf("无法打开文件 %s\n", filename);return;}init_list(list);while (1){DATA data;if (fread(&data, sizeof(DATA), 1, file) != 1){break;}add_car(list, data);}fclose(file);
}// 使用插入排序,对停车时长进行排序
void sort_cars_by_parking_time(SLIST *list)
{if (list->head == NULL || list->head->next == NULL){return; // 空链表或只有一个节点,无需排序}NODE *sorted = NULL;// 创建新的链表sorted,用于存储已排序的节点,初始化为NULLNODE *current = list->head;// 将current指针初始化为链表的头结点while (current != NULL){/*** 在处理当前节点之前,先将next指针指向当前节点的下一个节点,* 避免处理节点数据时丢失对下一个节点的引用*/NODE *next = current->next;/*** 情况1:当前节点为第一个节点或停车时间最小*/if (sorted == NULL || current->data.parktime < sorted->data.parktime)/*** 如果 sorted 为空(即当前节点是第一个节点),或者当前节点的* 停车时间小于排序后链表头结点的停车时间,则将当前节点插入到sorted链表的头部*/{current->next = sorted; // 将当前节点的next指针指向sortedsorted = current; // 更新sorted为当前节点}/*** 情况2:当前节点需要插入到已排序链表的中间或者尾部*/else{NODE *temp = sorted; // 将temp指针指向新创建的sorted链表while (temp->next != NULL && current->data.parktime >= temp->next->data.parktime)/*** 使用 temp 指针从 sorted 链表的头节点开始,依次检查每个节点* 的停车时间,直到找到一个节点的停车时间大于或等于当前节点的停车时间*/{temp = temp->next;}current->next = temp->next;// 将当前节点的next指针指向temp->next,然后将temp->next指向// 当前节点,完成插入排序操作temp->next = current;}current = next;// 将current指针移动到下一个节点(next),继续遍历列表}list->head = sorted; // 将链表的头指针变为sorted,表示排序操作完成
}// 使用插入排序,对同车型的车辆进行排序处理
void sort_cars_by_type(SLIST *list)
{if (list->head == NULL || list->head->next == NULL) // 头结点为空,或者只有一个节点{return; // 空链表或只有一个节点,无需排序,直接返回}NODE *sorted = NULL; // 创建新链表sorted,用于存储排序后的节点NODE *current = list->head;while (current != NULL){NODE *next = current->next;// 将next指针指向当前节点的下一个节点,防止丢失节点引用if (sorted == NULL || strcmp(current->data.cartype, sorted->data.cartype) < 0){// 将当前节点的 next 指针指向 sorted,然后将 sorted 更新为当前节点。current->next = sorted;sorted = current;}else{NODE *temp = sorted;while (temp->next != NULL && strcmp(current->data.cartype, temp->next->data.cartype) >= 0){temp = temp->next;}current->next = temp->next;temp->next = current;}current = next;}list->head = sorted;
}// 创建copy链表函数(深拷贝)
void copy_list(SLIST *dest, SLIST *src)
// SLIST *dest:目标链表,用于存储复制后的节点
// SLIST *src:源链表,需要被复制的链表
{NODE *current = src->head; // 将current指针初始化为源链表(src)的头结点,用于遍历链表while (current != NULL){add_car(dest, current->data);// 调用函数,将当前节点的数据添加到目标链表的尾部。current = current->next;}
}
slist.h:定义了一个单链表数据结构及其相关函数声明,并将其封装在一个头文件 slist.h
中。头文件的主要作用是提供链表的数据结构定义和函数声明,以便在其他源文件中使用这些定义和声明。
// 单链表数据结构和函数声明
#ifndef SLIST_H
#define SLIST_H#include "car.h"typedef struct Node
{DATA data;struct Node *next;
} NODE;typedef struct
{NODE *head;
} SLIST;void init_list(SLIST *list);
void add_car(SLIST *list, DATA data);
void remove_car(SLIST *list, char *carnumber);
void update_car(SLIST *list, char *carnumber, DATA new_data);
void find_car(SLIST *list, char *carnumber);
void display_all_cars(SLIST *list);
void free_list(SLIST *list);
void sort_cars_by_parking_time(SLIST *list);
void sort_cars_by_type(SLIST *list);#endif
slist.c:实现了单链表的基本操作,包括初始化、添加、删除、修改、查询、显示所有节点以及释放链表内存等功能
// 实现单链表的相关操作
#include "slist.h"
#include "function.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>void init_list(SLIST *list)
{list->head = NULL;
}
// 添加车辆信息函数(头插)
void add_car(SLIST *list, DATA data)
// SLIST *list:指向单链表的指针
{NODE *new_node = (NODE *)malloc(sizeof(NODE));// 使用malloc存储NODE结构体if (new_node == NULL) // malloc返回NULL{printf("内存分配失败\n");return;}new_node->data = data;// 将传入的data赋值给新节点的datanew_node->next = list->head;// 将当前链表的头节点赋值给新节点的 next 指针,表示新节点接下来连接原来的头节点。list->head = new_node;// 链表头指针指向新节点
}// 删除车辆信息函数
void remove_car(SLIST *list, char *carnumber)
{NODE *current = list->head;// current:指向当前遍历的节点,初始时指向链表的头节点。NODE *previous = NULL;// previous:指向 current 节点的前驱节点,初始时为 NULL,因为链表的头节点没有前一个节点。while (current != NULL){if (strcmp(current->data.carnumber, carnumber) == 0){if (previous == NULL) // 匹配的节点是链表的头节点{list->head = current->next; // 将链表的头指针指向当前节点的下一个节点}else{previous->next = current->next; // 将前一个节点的next指针指向当前节点的下一个节点}free(current);return;}previous = current; // 将prev指针更新为当前节点current = current->next; // 将当前节点更新为当前节点的下一个节点}printf("未找到车牌号为 %s 的车辆\n", carnumber);
}// 修改车辆信息函数
void update_car(SLIST *list, char *carnumber, DATA new_data)
{NODE *current = list->head;// 将current指针初始化为链表的头结点,开始遍历链表while (current != NULL){if (strcmp(current->data.carnumber, carnumber) == 0){current->data = new_data;return;}current = current->next;}printf("未找到车牌号为 %s 的车辆\n", carnumber);
}// 查询车辆信息函数
void find_car(SLIST *list, char *carnumber)
{NODE *current = list->head;while (current != NULL){if (strcmp(current->data.carnumber, carnumber) == 0){display_car_data(¤t->data);return;}current = current->next;}printf("未找到车牌号为 %s 的车辆\n", carnumber);
}// 显示所有车辆函数
void display_all_cars(SLIST *list)
{NODE *current = list->head;while (current != NULL){display_car_data(¤t->data);// 传入当前节点的数据的地址printf("\n");current = current->next;}
}void free_list(SLIST *list)
{NODE *current = list->head;NODE *next = NULL; // 将next指针初始化为NULL,用于临时保存下一节点的地址。while (current != NULL){// 将next指针指向当前节点的下一个节点next = current->next;free(current);current = next;// 将current指针移动到下一个节点,继续遍历}list->head = NULL; // 表示链表已清空,因为头指针为NULL
}
main.c:main.c是一个基于单链表的车辆管理系统的主程序,提供了用户交互界面,并实现了车辆信息的增删改查、排序、停车费用计算等功能。
#include "function.h"
#include <stdio.h>
#include <stdlib.h>int main()
{SLIST list;init_list(&list);int choice;DATA data;load_cars_from_file("cars.dat", &list);do{display_menu();printf("\033[1;31m");printf("请输入选项: ");scanf("%d", &choice);printf("------------------------\n");switch (choice){case 1: // 添加车辆信息input_car_data(&data);add_car(&list, data);break;case 2: // 删除车辆信息printf("输入要删除的车牌号: ");char carnumber[100];scanf("%s", carnumber);remove_car(&list, carnumber);break;case 3: // 修改车辆信息printf("输入要修改的车牌号: ");scanf("%s", carnumber);printf("输入新的车辆信息:\n");input_car_data(&data);update_car(&list, carnumber, data);break;case 4: // 查找车辆信息printf("输入要查找的车牌号: ");scanf("%s", carnumber);find_car(&list, carnumber);break;case 5: // 显示所有车辆display_all_cars(&list);break;case 6: // 排序功能实现printf("选择排序方式:\n");printf("1. 按停放时间排序\n");printf("2. 按车辆类型排序\n");printf("输入选项: ");int sort_choice;scanf("%d", &sort_choice);SLIST temp_list; // 创建临时链表init_list(&temp_list);copy_list(&temp_list, &list); // 复制原始链表到临时链表if (sort_choice == 1){sort_cars_by_parking_time(&temp_list); // 对临时链表排序}else if (sort_choice == 2){sort_cars_by_type(&temp_list); // 对临时链表排序}else{printf("无效的选项\n");free_list(&temp_list); // 释放临时链表break;}display_all_cars(&temp_list); // 显示排序后的临时链表free_list(&temp_list); // 释放临时链表printf("排序完成!\n");break;case 7: // 计算停车费用printf("输入车牌号: ");scanf("%s", carnumber);find_car(&list, carnumber);break;case 0: // 退出save_cars_to_file("cars.dat", &list);free_list(&list);printf("退出系统\n");break;default:printf("无效的选项\n");}} while (choice != 0);return 0;
}
多文件编译:
gcc -o parking main.c function.c car.c slist.c
执行:
./parking
界面演示:
说明:
可通过输入序号对具体车辆信息进行增添删改操作,也可通过排序功能选择不同的排序算法对车辆进行系统性排序。
总结
该程序通过菜单驱动的方式,提供了对车辆信息的多种管理功能。使用单链表存储数据,确保了数据的动态性。通过文件操作,实现了数据的持久化存储。排序功能通过创建临时链表进行,避免直接修改原始数据。整体结构清晰,功能完善,适合小型车辆管理系统使用。