#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_CUSTOMERS 100 // 最大顾客数量
#define MAX_WINDOWS 3 // 最大窗口数量
// 顾客结构体
typedef struct {
int id; // 顾客ID
int arrival_time; // 到达时间
int service_time; // 服务时间
bool is_vip; // 是否是VIP
int start_time; // 服务开始时间
int end_time; // 服务结束时间
int waiting_time; // 等待时间
} Customer;
// 窗口结构体
typedef struct {
int id; // 窗口ID
bool is_open; // 是否开放
int current_customer; // 当前服务的顾客ID
int remaining_time; // 剩余服务时间
int total_service_time; // 总服务时间
int total_customers; // 服务顾客总数
} Window;
// 队列节点
typedef struct QueueNode {
Customer customer; // 顾客数据
struct QueueNode* next; // 指向下一个节点的指针
} QueueNode;
// 队列结构
typedef struct {
QueueNode* front; // 队首指针
QueueNode* rear; // 队尾指针
int size; // 队列大小
} CustomerQueue;
// 全局变量
Window windows[MAX_WINDOWS]; // 窗口数组
int total_customers = 0; // 当前顾客数量
int current_time = 0; // 当前模拟时间
int simulation_end_time = 0; // 模拟结束时间
bool simulation_started = false; // 模拟是否已开始
CustomerQueue normal_queue; // 普通顾客队列
CustomerQueue vip_queue; // VIP顾客队列
Customer served_customers[MAX_CUSTOMERS]; // 已服务顾客列表
int served_count = 0; // 已服务顾客数量
// 初始化队列
void init_queue(CustomerQueue* queue) {
queue->front = NULL;
queue->rear = NULL;
queue->size = 0;
}
// 检查队列是否为空
bool is_queue_empty(CustomerQueue* queue) {
return queue->size == 0;
}
// 入队操作
void enqueue(CustomerQueue* queue, Customer customer) {
QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
if (!newNode) {
printf("内存分配失败!\n");
return;
}
newNode->customer = customer;
newNode->next = NULL;
if (queue->rear == NULL) {
queue->front = queue->rear = newNode;
} else {
queue->rear->next = newNode;
queue->rear = newNode;
}
queue->size++;
}
// 出队操作
Customer dequeue(CustomerQueue* queue) {
if (is_queue_empty(queue)) {
printf("错误:尝试从空队列中出队!\n");
Customer empty;
empty.id = -1;
return empty;
}
QueueNode* temp = queue->front;
Customer customer = temp->customer;
queue->front = queue->front->next;
if (queue->front == NULL) {
queue->rear = NULL;
}
free(temp);
queue->size--;
return customer;
}
// 查看队首元素(不出队)
Customer peek_queue(CustomerQueue* queue) {
if (is_queue_empty(queue)) {
Customer empty;
empty.id = -1;
return empty;
}
return queue->front->customer;
}
// 显示队列内容
void display_queue(CustomerQueue* queue, const char* name) {
if (is_queue_empty(queue)) {
printf("%s队列为空\n", name);
return;
}
printf("%s队列内容:\n", name);
QueueNode* current = queue->front;
while (current != NULL) {
printf(" ID: %d, 到达时间: %d, 服务时间: %d, 类型: %s\n",
current->customer.id,
current->customer.arrival_time,
current->customer.service_time,
current->customer.is_vip ? "VIP" : "普通");
current = current->next;
}
}
// 显示主菜单
void display_main_menu() {
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("8. 退出系统\n");
printf("请选择操作: ");
}
// 手动输入顾客信息
void manual_input_customers() {
if (simulation_started) {
printf("错误:模拟已开始,请先重置系统!\n");
return;
}
printf("\n===== 手动输入顾客信息 =====\n");
// 获取顾客数量
while (true) {
printf("请输入顾客数量(1-%d): ", MAX_CUSTOMERS);
scanf("%d", &total_customers);
if (total_customers >= 1 && total_customers <= MAX_CUSTOMERS) {
break;
}
printf("错误:无效的顾客数量!请重新输入。\n");
}
// 输入每个顾客的信息
for (int i = 0; i < total_customers; i++) {
Customer customer;
printf("\n-- 顾客 %d --\n", i + 1);
// 到达时间
printf("到达时间: ");
scanf("%d", &customer.arrival_time);
// 服务时间
while (true) {
printf("服务时间(1-30分钟): ");
scanf("%d", &customer.service_time);
if (customer.service_time >= 1 && customer.service_time <= 30) {
break;
}
printf("错误:服务时间必须在1-30分钟内!\n");
}
// 是否VIP
char vip_choice;
while (true) {
printf("是否是VIP? (y/n): ");
scanf(" %c", &vip_choice);
if (vip_choice == 'y' || vip_choice == 'Y') {
customer.is_vip = true;
break;
} else if (vip_choice == 'n' || vip_choice == 'N') {
customer.is_vip = false;
break;
}
printf("错误:请输入 y 或 n!\n");
}
// 初始化时间字段
customer.id = i + 1;
customer.start_time = -1;
customer.end_time = -1;
customer.waiting_time = -1;
// 根据类型加入不同队列
if (customer.is_vip) {
enqueue(&vip_queue, customer);
} else {
enqueue(&normal_queue, customer);
}
}
printf("\n成功输入 %d 位顾客信息!\n", total_customers);
}
// 显示当前顾客数据
void display_customer_data() {
if (total_customers == 0) {
printf("当前没有顾客数据!\n");
return;
}
printf("\n===== 当前顾客数据 =====\n");
display_queue(&vip_queue, "VIP");
display_queue(&normal_queue, "普通");
}
// 初始化窗口
void initialize_windows() {
for (int i = 0; i < MAX_WINDOWS; i++) {
windows[i].id = i + 1;
windows[i].is_open = true;
windows[i].current_customer = -1;
windows[i].remaining_time = 0;
windows[i].total_service_time = 0;
windows[i].total_customers = 0;
}
}
// 重置系统
void reset_system() {
total_customers = 0;
current_time = 0;
simulation_end_time = 0;
simulation_started = false;
served_count = 0;
// 清空队列
while (!is_queue_empty(&vip_queue)) {
dequeue(&vip_queue);
}
while (!is_queue_empty(&normal_queue)) {
dequeue(&normal_queue);
}
// 重置窗口
initialize_windows();
printf("\n系统已重置!所有顾客数据和窗口状态已清除。\n");
}
// 显示窗口状态
void display_window_status() {
printf("\n===== 窗口状态 (时间: %d) =====\n", current_time);
printf("%-6s %-8s %-15s %-10s %-15s %-15s\n",
"窗口ID", "状态", "当前顾客", "剩余时间", "服务顾客数", "总服务时间");
printf("--------------------------------------------------------------\n");
for (int i = 0; i < MAX_WINDOWS; i++) {
char customer_display[20];
if (windows[i].current_customer == -1) {
strcpy(customer_display, "无");
} else {
sprintf(customer_display, "%d", windows[i].current_customer);
}
printf("%-6d %-8s %-15s %-10d %-15d %-15d\n",
windows[i].id,
windows[i].is_open ? "开放" : "关闭",
customer_display,
windows[i].remaining_time,
windows[i].total_customers,
windows[i].total_service_time);
}
}
// 查找空闲窗口
int find_free_window() {
for (int i = 0; i < MAX_WINDOWS; i++) {
if (windows[i].is_open && windows[i].current_customer == -1) {
return i;
}
}
return -1;
}
// 模拟一个时间单位
void simulate_time_unit() {
// 更新时间标记
current_time++;
// 1. 更新窗口状态
for (int i = 0; i < MAX_WINDOWS; i++) {
if (windows[i].current_customer != -1) {
// 减少服务时间
windows[i].remaining_time--;
// 顾客服务完成
if (windows[i].remaining_time <= 0) {
int cust_id = windows[i].current_customer;
windows[i].current_customer = -1;
windows[i].remaining_time = 0;
printf("时间 %d: 窗口 %d 完成服务顾客 %d\n",
current_time, windows[i].id, cust_id);
// 记录服务结束时间
for (int j = 0; j < served_count; j++) {
if (served_customers[j].id == cust_id) {
served_customers[j].end_time = current_time;
break;
}
}
}
}
}
// 2. 分配新顾客 (VIP优先)
int free_window;
while ((free_window = find_free_window()) != -1) {
Customer next_customer;
bool customer_found = false;
bool has_vip = false;
bool has_normal = false;
// 检查是否有VIP顾客已到达
if (!is_queue_empty(&vip_queue)) {
Customer vip_customer = peek_queue(&vip_queue);
if (vip_customer.arrival_time <= current_time) {
next_customer = dequeue(&vip_queue);
customer_found = true;
has_vip = true;
}
}
// 如果没有VIP顾客,检查普通顾客
if (!customer_found && !is_queue_empty(&normal_queue)) {
Customer normal_customer = peek_queue(&normal_queue);
if (normal_customer.arrival_time <= current_time) {
next_customer = dequeue(&normal_queue);
customer_found = true;
has_normal = true;
}
}
// 如果有顾客需要服务
if (customer_found) {
// 记录服务开始时间
next_customer.start_time = current_time;
next_customer.waiting_time = current_time - next_customer.arrival_time;
// 添加到已服务顾客列表
if (served_count < MAX_CUSTOMERS) {
served_customers[served_count] = next_customer;
served_count++;
}
// 更新窗口状态
windows[free_window].current_customer = next_customer.id;
windows[free_window].remaining_time = next_customer.service_time;
windows[free_window].total_service_time += next_customer.service_time;
windows[free_window].total_customers++;
printf("时间 %d: 窗口 %d 开始服务顾客 %d (服务时间: %d)\n",
current_time, windows[free_window].id, next_customer.id,
next_customer.service_time);
} else {
break; // 没有需要服务的顾客
}
}
}
// 检查所有顾客是否已服务
bool all_customers_served() {
return is_queue_empty(&vip_queue) && is_queue_empty(&normal_queue);
}
// 开始服务模拟
void start_simulation() {
if (total_customers == 0) {
printf("错误:没有顾客数据,请先输入顾客信息!\n");
return;
}
if (simulation_started) {
printf("错误:模拟已在进行中!\n");
return;
}
simulation_started = true;
initialize_windows();
current_time = 0;
served_count = 0;
printf("\n===== 开始服务模拟 =====\n");
printf("按回车键逐步推进时间,输入q退出模拟\n");
// 清除输入缓冲区
while (getchar() != '\n');
char input;
// 先推进时间到第一个顾客到达
int min_arrival = 10000;
CustomerQueue* queues[] = {&vip_queue, &normal_queue};
for (int i = 0; i < 2; i++) {
QueueNode* current = queues[i]->front;
while (current != NULL) {
if (current->customer.arrival_time < min_arrival) {
min_arrival = current->customer.arrival_time;
}
current = current->next;
}
}
if (min_arrival > 0) {
current_time = min_arrival;
printf("时间推进到 %d: 第一个顾客到达\n", current_time);
}
while (!all_customers_served()) {
printf("\n时间 %d: 模拟状态 (按回车继续)...", current_time);
fflush(stdout);
input = getchar();
if (input == 'q' || input == 'Q') {
printf("\n模拟已终止。\n");
return;
}
simulate_time_unit();
display_window_status();
// 清除后续换行符
if (input != '\n') while (getchar() != '\n');
}
// 检查窗口是否还有服务中的顾客
bool still_serving = false;
for (int i = 0; i < MAX_WINDOWS; i++) {
if (windows[i].current_customer != -1) {
still_serving = true;
break;
}
}
// 等待所有窗口完成服务
while (still_serving) {
printf("\n时间 %d: 等待窗口完成服务 (按回车继续)...", current_time);
fflush(stdout);
input = getchar();
if (input == 'q' || input == 'Q') {
printf("\n模拟已终止。\n");
return;
}
simulate_time_unit();
display_window_status();
// 检查是否还有服务中的顾客
still_serving = false;
for (int i = 0; i < MAX_WINDOWS; i++) {
if (windows[i].current_customer != -1) {
still_serving = true;
break;
}
}
// 清除后续换行符
if (input != '\n') while (getchar() != '\n');
}
simulation_end_time = current_time;
printf("\n模拟完成!所有顾客已服务完毕。\n");
printf("总模拟时间: %d 分钟\n", simulation_end_time);
}
// 显示所有顾客服务详情
void display_all_customer_stats() {
if (served_count == 0) {
printf("没有服务记录!\n");
return;
}
printf("\n===== 顾客服务详情 =====\n");
printf("%-6s %-10s %-10s %-8s %-10s %-10s %-10s %-10s\n",
"ID", "到达时间", "服务时间", "类型", "开始时间", "结束时间", "等待时间", "总时间");
printf("-------------------------------------------------------------------------------\n");
for (int i = 0; i < served_count; i++) {
Customer c = served_customers[i];
int total_time = c.end_time - c.arrival_time;
printf("%-6d %-10d %-10d %-8s %-10d %-10d %-10d %-10d\n",
c.id,
c.arrival_time,
c.service_time,
c.is_vip ? "VIP" : "普通",
c.start_time,
c.end_time,
c.waiting_time,
total_time);
}
}
// 计算并显示平均服务时间
void display_avg_service_time() {
if (served_count == 0) {
printf("没有服务记录!\n");
return;
}
int total_service_time = 0;
for (int i = 0; i < served_count; i++) {
total_service_time += served_customers[i].service_time;
}
float avg = (float)total_service_time / served_count;
printf("\n平均服务时间: %.2f 分钟\n", avg);
}
// 计算并显示平均等待时间
void display_avg_waiting_time() {
if (served_count == 0) {
printf("没有服务记录!\n");
return;
}
int total_waiting_time = 0;
int count = 0;
for (int i = 0; i < served_count; i++) {
if (served_customers[i].waiting_time >= 0) {
total_waiting_time += served_customers[i].waiting_time;
count++;
}
}
if (count == 0) {
printf("\n没有有效的等待时间数据!\n");
return;
}
float avg = (float)total_waiting_time / count;
printf("\n平均等待时间: %.2f 分钟\n", avg);
}
// 计算并显示窗口利用率
void display_window_utilization() {
if (simulation_end_time == 0) {
printf("模拟尚未完成!\n");
return;
}
printf("\n===== 窗口利用率 (总模拟时间: %d 分钟) =====\n", simulation_end_time);
printf("%-6s %-15s %-15s %-10s\n",
"窗口ID", "服务时间(分钟)", "服务顾客数", "利用率(%)");
printf("--------------------------------------------------\n");
for (int i = 0; i < MAX_WINDOWS; i++) {
float utilization = (float)windows[i].total_service_time / simulation_end_time * 100;
printf("%-6d %-15d %-15d %-10.2f\n",
windows[i].id,
windows[i].total_service_time,
windows[i].total_customers,
utilization);
}
}
// 数据统计功能
void data_statistics() {
int choice;
if (!simulation_started || served_count == 0)
printf("请先完成服务模拟!\n");
else{
display_all_customer_stats();
display_avg_service_time();
display_avg_waiting_time();
display_window_utilization();
}
}
int main() {
int choice;
// 初始化队列
init_queue(&vip_queue);
init_queue(&normal_queue);
printf("===== 银行窗口排队系统 =====\n");
initialize_windows(); // 初始化窗口
// 主循环
while (true) {
display_main_menu();
if (scanf("%d", &choice) != 1) {
// 清除无效输入
while (getchar() != '\n');
printf("错误:请输入有效的数字选项!\n");
continue;
}
// 使用switch-case处理用户选择
switch (choice) {
case 1: // 手动输入顾客信息
manual_input_customers();
break;
case 2: // 开始服务模拟
start_simulation();
break;
case 3: // 显示当前顾客数据
display_customer_data();
break;
case 4: // 显示窗口状态
display_window_status();
break;
case 5: // 显示队列状态
display_queue(&vip_queue, "VIP");
display_queue(&normal_queue, "普通");
break;
case 6: // 数据统计
data_statistics();
break;
case 7: // 重置系统
reset_system();
break;
case 8: // 退出系统
printf("\n感谢使用银行服务系统,再见!\n");
// 释放队列内存
while (!is_queue_empty(&vip_queue)) dequeue(&vip_queue);
while (!is_queue_empty(&normal_queue)) dequeue(&normal_queue);
exit(0);
default: // 无效选择
printf("错误:无效的选择!请重新输入。\n");
}
}
return 0;
}取消菜单三四五,但不影响菜单其余功能
最新发布