//问题2-2 #include <iostream> #include <ctime> #include <stdlib.h> #include <time.h> #include <windows.h> using namespace std; #define Status int #define OVERFLOW 2 #define ERROR 1 #define OK 0; typedef int QElemType; int queue_number[10] = { 0 };//queue_number记录队列人数 int i, j = 0;//i用于客户计数,j用于窗口计数 int no = 0;//no用于记录客户序号,其中第一位客户的序号为1 int time_length = 0;//time_length记录模拟程序运行时长 int window_number = 0; typedef struct QNode { int no;//序号 double amount;//总金额 double remain_amount;//未取金额(不计当前轮) struct QNode* next; }QNode, * QueuePtr; typedef struct { QueuePtr front; //队头指针 QueuePtr rear; //队尾指针 }LinkQueue; Status InitQueue(LinkQueue& Q) { Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); if (!Q.front) exit(OVERFLOW); Q.front->next = NULL; return OK; } Status DestroyQueue(LinkQueue& Q) { while (Q.front) { Q.rear = Q.front->next; free(Q.front); Q.front = Q.rear; } return OK; } Status QueueEmpty(LinkQueue Q) { return (Q.front == Q.rear); } Status GetHead(LinkQueue Q, int& e1, double& e2, double& e3) { if (Q.front == Q.rear) return ERROR; e1 = Q.front->next->no; e2 = Q.front->next->amount; e3 = Q.front->next->remain_amount; return OK; } Status EnQueue(LinkQueue& Q, int& e1, double& e2, double& e3) { QueuePtr p; p = (QueuePtr)malloc(sizeof(QNode)); if (!p) exit(OVERFLOW); p->no = e1; p->amount = e2; p->remain_amount = e3; p->next = NULL; Q.rear->next = p; Q.rear = p; return OK; } Status DeQueue(LinkQueue& Q, int& e1, double& e2, double& e3) { if (Q.front == Q.rear) return ERROR; QueuePtr p; p = Q.front->next; e1 = p->no; e2 = p->amount; e3 = p->remain_amount; Q.front->next = p->next; if (Q.rear == p) Q.rear = Q.front; delete p; return OK; } int MinQueue() { int s = 10000, k = 0, temp; for (k = 0;k < window_number;k++) { if (queue_number[k] < s) { temp = k; s = queue_number[k]; } } return temp; } int MaxQueue() { int s = -1, k = 0, temp; for (k = 0;k < window_number;k++) { if (queue_number[k] > s) { temp = k; s = queue_number[k]; } } return temp; } void Remove(LinkQueue& Q)//检查第一个人是否已取完。注意判断队列是否为空。 { if (!QueueEmpty(Q)) { if (Q.front->next->remain_amount <= 1e-8) { int e1 = -1; double e2 = -1, e3 = -1; DeQueue(Q, e1, e2, e3); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);//设置绿色 cout << "第" << (double)i / 10 + 0.1 << "秒时" << j + 1 << "号窗口" << "第" << e1 << "位客户完成业务,取走共" << e2 << "万元。" << endl; queue_number[j]--; } } } void Join(LinkQueue* q) { int a = rand() % 60; //a的值在0-60之间随机分布,只有当a=0到window_number-1时才产生新客户 //平均每6秒产生window_number个客户,与窗口数量对应 if (a < window_number) { no++; double b = double(rand() % 191) / 10 + 1;//b的值在1-20之间随机分布(精度0.1),代表用户取钱的金额数(单位:万元) int m = MinQueue(); EnQueue(q[m], no, b, b); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);//设置红色和绿色相加 cout << "第" << (double)i / 10 + 0.1 << "秒时第" << no << "位客户进入窗口" << m + 1 << "队列,需取" << b << "万元。" << endl; queue_number[m]++; } } void ChangeQuene(LinkQueue* q) { int min = MinQueue(), max = MaxQueue(); while (queue_number[max] - queue_number[min] >= 2) { int e1; double e2, e3; DeQueue(q[max], e1, e2, e3); EnQueue(q[min], e1, e2, e3); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_BLUE);//设置蓝色 cout << "第" << e1 << "位客户从窗口" << max + 1 << "队列调整到窗口" << min + 1 << "队列" << endl; queue_number[min]++; queue_number[max]--; min = MinQueue(); max = MaxQueue(); } } void Withdraw(LinkQueue& Q) { if (!QueueEmpty(Q) && i != time_length) { Q.front->next->remain_amount -= 0.2;//每0.1秒取走0.2万 } } void Undone(LinkQueue& Q) { while (!QueueEmpty(Q)) { int e1 = -1; double e2 = -1, e3 = -1; DeQueue(Q, e1, e2, e3); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);//设置绿色和蓝色相加 cout << "窗口" << j + 1 << "队列第" << e1 << "位客户未完成业务,未取共" << e2 << "万元。" << endl; } } int main() { cout << "请输入模拟程序运行时长(单位:秒)(1-300之间的整数):" << endl; //time_length = 120; cin >> time_length; while (time_length <= 0 || time_length > 300) { cout << "您输入的时间不符合要求,请重新输入:"; cin >> time_length; } cout << "请输入银行窗口数(1-10之间的整数):" << endl; cin >> window_number; while (window_number <= 0 || window_number > 10) { cout << "您输入的窗口数不符合要求,请重新输入:"; cin >> window_number; } LinkQueue* q = (LinkQueue*)malloc(window_number * sizeof(LinkQueue)); //队列初始化 for (j = 0;j < window_number;j++) { InitQueue(q[j]); } srand(time(nullptr));//设置随机数种子 //核心代码 for (i = 0;i <= time_length * 10;i++)//每0.1秒循环一次,直到到达预定时间 { //先检查第一个人是否已取完。注意判断队列是否为空 for (j = 0;j < window_number;j++) { Remove(q[j]); } //再把新客户加到人最少的队伍 Join(q); //再判定是否有客户需要重新选择队列 ChangeQuene(q); //再给当前队伍第一位取钱,注意判断队列是否为空 //注意i=time_length时取钱业务已经停止 for (j = 0;j < window_number;j++) { Withdraw(q[j]); } Sleep(93); //100单位为毫秒,即0.1秒。考虑到程序运行时间,将100改为93 //由于Sleep()函数的精度不高,因此循环间隔不能太小 } //程序结束前,输出未取完钱的人的情况 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);//设置颜色,没有添加颜色,故为原色 cout << endl << "取钱业务结束。" << endl << endl; for (j = 0;j < window_number;j++) { Undone(q[j]); } SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);//设置颜色,没有添加颜色,故为原色 return 0; }