【10.2】队列-设计循环队列

一、题目

        设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

        循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

二、解题思路

2.1 数组实现

        我们可以通过数组来模拟循环队列,利用数组的索引构建一个虚拟的环形结构。在循环队列中,设置两个指针:队尾 `rear` 和队首 `front`,队列的大小是固定的。结构如下图所示:

        在循环队列中,当队列为空时,`front` 和 `rear` 相等,即 `front == rear`;而当队列的所有空间都被占满时,同样会出现 `front == rear` 的情况。为了区分这两种状态,我们规定队列的数组容量为 `capacity`,但循环队列最多只能存储 `capacity - 1` 个元素。当队列中只剩下一个空闲的存储单元时,就认为队列已满。因此,队列判空的条件是 `front == rear`,而判满的条件是 `front == (rear + 1) % capacity`。

        对于一个固定大小的数组,只要知道队尾 `rear` 和队首 `front`,就可以计算出队列的当前长度:  (rear - front + capacity) mod capacity

循环队列的主要属性如下:

        **`elements`**:一个固定大小的数组,用于存储循环队列的元素。
        **`capacity`**:循环队列的容量,即队列中最多可以容纳的元素数量。
        **`front`**:队首元素在数组中的索引。
        **`rear`**:队尾元素的下一个位置的索引。

循环队列的接口方法如下:

        **`MyCircularQueue(int k)`**:初始化队列,数组的空间大小为 `k + 1`,并将 `front` 和 `rear` 初始化为 0。
        **`enQueue(int value)`**:在队列的尾部插入一个元素,并将 `rear` 更新为 `(rear + 1) % capacity`。
        **`deQueue()`**:从队首取出一个元素,并将 `front` 更新为 `(front + 1) % capacity`。
        **`Front()`**:返回队首的元素,需要先检测队列是否为空。
        **`Rear()`**:返回队尾的元素,需要先检测队列是否为空。
        **`isEmpty()`**:检测队列是否为空,只需判断 `rear` 是否等于 `front`。
        **`isFull()`**:检测队列是否已满,只需判断 `front` 是否等于 `(rear + 1) % capacity`。

        通过这种方式,循环队列能够高效地利用数组空间,同时避免普通队列在空间利用上的不足。

#include <iostream>
#include <vector>
using namespace std;

class MyCircularQueue {
private:
    int front;           // 队首指针
    int rear;            // 队尾指针
    int capacity;        // 队列容量
    vector<int> elements; // 用于存储队列元素的数组

public:
    // 构造函数,初始化队列
    MyCircularQueue(int k) {
        this->capacity = k + 1;          // 容量为 k + 1,多分配一个空间用于区分空和满状态
        this->elements = vector<int>(capacity); // 初始化数组
        rear = front = 0;                // 初始化队首和队尾指针
    }

    // 向循环队列插入一个元素
    bool enQueue(int value) {
        if (isFull()) {
            return false; // 队列已满,插入失败
        }
        elements[rear] = value;         // 将元素插入队尾
        rear = (rear + 1) % capacity;   // 更新队尾指针(循环)
        return true;
    }

    // 从循环队列中删除一个元素
    bool deQueue() {
        if (isEmpty()) {
            return false; // 队列为空,删除失败
        }
        front = (front + 1) % capacity; // 更新队首指针(循环)
        return true;
    }

    // 获取队首元素
    int Front() {
        if (isEmpty()) {
            return -1; // 队列为空,返回 -1
        }
        return elements[front]; // 返回队首元素
    }

    // 获取队尾元素
    int Rear() {
        if (isEmpty()) {
            return -1; // 队列为空,返回 -1
        }
        return elements[(rear - 1 + capacity) % capacity]; // 返回队尾元素(处理循环情况)
    }

    // 检查队列是否为空
    bool isEmpty() {
        return rear == front; // 队首和队尾指针相等时,队列为空
    }

    // 检查队列是否已满
    bool isFull() {
        return ((rear + 1) % capacity) == front; // 队尾的下一个位置是队首时,队列已满
    }
};

int main() {
    // 创建循环队列,容量为 3
    MyCircularQueue circularQueue(3);

    // 测试 enQueue 操作
    cout << "enQueue(1): " << circularQueue.enQueue(1) << endl; // 输出: 1 (true)
    cout << "enQueue(2): " << circularQueue.enQueue(2) << endl; // 输出: 1 (true)
    cout << "enQueue(3): " << circularQueue.enQueue(3) << endl; // 输出: 1 (true)
    cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 0 (false,队列已满)

    // 测试 Rear 操作
    cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 3

    // 测试 isFull 操作
    cout << "isFull(): " << circularQueue.isFull() << endl; // 输出: 1 (true)

    // 测试 deQueue 操作
    cout << "deQueue(): " << circularQueue.deQueue() << endl; // 输出: 1 (true)

    // 测试 enQueue 操作
    cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 1 (true)

    // 测试 Rear 操作
    cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 4

    // 测试 Front 操作
    cout << "Front(): " << circularQueue.Front() << endl; // 输出: 2

    // 测试 isEmpty 操作
    cout << "isEmpty(): " << circularQueue.isEmpty() << endl; // 输出: 0 (false)

    return 0;
}

复杂度分析

  • 时间复杂度:初始化和每项操作的时间复杂度均为 O(1)。

  • 空间复杂度:O(k),其中 k 为给定的队列元素数目。

 

2.2 链表实现

        我们也可以使用链表来实现队列。与数组相比,链表实现队列更加灵活,因为链表可以在 O(1)时间复杂度内完成元素的插入和删除操作。具体来说,入队操作是将新元素插入到链表的尾部,而出队操作则是返回链表的头节点,并将头节点指向下一个节点。

循环队列的属性如下:

  • head:链表的头节点,表示队列的头部。

  • tail:链表的尾节点,表示队列的尾部。

  • capacity:队列的容量,即队列可以存储的最大元素数量。

  • size:队列当前存储的元素数量。

        通过链表实现循环队列,可以避免数组实现中需要处理索引循环的问题,同时也能高效地完成队列的基本操作。

#include <iostream>
using namespace std;

// 链表节点定义
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class MyCircularQueue {
private:
    ListNode *head;  // 队首指针,指向链表的头节点
    ListNode *tail;  // 队尾指针,指向链表的尾节点
    int capacity;    // 队列的容量
    int size;        // 队列当前的大小

public:
    // 构造函数,初始化队列
    MyCircularQueue(int k) {
        this->capacity = k;  // 设置队列容量
        this->size = 0;      // 初始化队列大小为 0
        this->head = nullptr; // 初始化队首指针为空
        this->tail = nullptr; // 初始化队尾指针为空
    }

    // 向队列尾部插入一个元素
    bool enQueue(int value) {
        if (isFull()) {
            return false; // 队列已满,插入失败
        }
        ListNode *node = new ListNode(value); // 创建新节点
        if (!head) {
            head = tail = node; // 如果队列为空,新节点既是队首也是队尾
        } else {
            tail->next = node; // 将新节点链接到队尾
            tail = node;       // 更新队尾指针
        }
        size++; // 队列大小加 1
        return true;
    }

    // 从队列头部删除一个元素
    bool deQueue() {
        if (isEmpty()) {
            return false; // 队列为空,删除失败
        }
        ListNode *node = head; // 保存队首节点
        head = head->next;     // 更新队首指针
        size--;                // 队列大小减 1
        delete node;           // 释放队首节点的内存
        if (isEmpty()) {
            tail = nullptr; // 如果队列为空,更新队尾指针为空
        }
        return true;
    }

    // 获取队首元素
    int Front() {
        if (isEmpty()) {
            return -1; // 队列为空,返回 -1
        }
        return head->val; // 返回队首节点的值
    }

    // 获取队尾元素
    int Rear() {
        if (isEmpty()) {
            return -1; // 队列为空,返回 -1
        }
        return tail->val; // 返回队尾节点的值
    }

    // 检查队列是否为空
    bool isEmpty() {
        return size == 0; // 队列大小为 0 时为空
    }

    // 检查队列是否已满
    bool isFull() {
        return size == capacity; // 队列大小等于容量时为满
    }
};

int main() {
    // 创建循环队列,容量为 3
    MyCircularQueue circularQueue(3);

    // 测试 enQueue 操作
    cout << "enQueue(1): " << circularQueue.enQueue(1) << endl; // 输出: 1 (true)
    cout << "enQueue(2): " << circularQueue.enQueue(2) << endl; // 输出: 1 (true)
    cout << "enQueue(3): " << circularQueue.enQueue(3) << endl; // 输出: 1 (true)
    cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 0 (false,队列已满)

    // 测试 Rear 操作
    cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 3

    // 测试 isFull 操作
    cout << "isFull(): " << circularQueue.isFull() << endl; // 输出: 1 (true)

    // 测试 deQueue 操作
    cout << "deQueue(): " << circularQueue.deQueue() << endl; // 输出: 1 (true)

    // 测试 enQueue 操作
    cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 1 (true)

    // 测试 Rear 操作
    cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 4

    // 测试 Front 操作
    cout << "Front(): " << circularQueue.Front() << endl; // 输出: 2

    // 测试 isEmpty 操作
    cout << "isEmpty(): " << circularQueue.isEmpty() << endl; // 输出: 0 (false)

    return 0;
}

复杂度分析

  • 时间复杂度:初始化和每项操作的时间复杂度均为 O(1)。

  • 空间复杂度:O(k),其中 k 为给定的队列元素数目。

#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_stats_menu() { printf("\n====== 数据统计菜单 ======\n"); printf("1. 显示所有顾客服务详情\n"); printf("2. 显示平均服务时间\n"); printf("3. 显示平均等待时间\n"); printf("4. 显示窗口利用率\n"); printf("5. 返回主菜单\n"); printf("请选择操作: "); } // 显示所有顾客服务详情 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"); return; } while (true) { display_stats_menu(); if (scanf("%d", &choice) != 1) { // 清除无效输入 while (getchar() != '\n'); printf("错误:请输入有效的数字选项!\n"); continue; } switch (choice) { case 1: display_all_customer_stats(); break; case 2: display_avg_service_time(); break; case 3: display_avg_waiting_time(); break; case 4: display_window_utilization(); break; case 5: return; default: printf("错误:无效的选择!请重新输入。\n"); } } } 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; }取消数据统计窗口,改为直接全部显示
06-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值