数据结构课设,银行业务模拟。
注意,在此检查过程中,一旦银行资金总额少于或等于刚才第一个队列中最后一个客户(第二种业务)被接待之前的数额,或者本次已将第二个队列检查或处理了一遍,就停止检查(因为此时已不可能还有能满足者)转而继续接待第一个队列的客户。其他模拟参量自定,注意测定两种极端的情况:一是两个到达事件之间的间隔时间很短,而客户的交易时间很长,另一个恰好相反,设置两个到达事件的间隔时间很长,而客户的交易时间很短。注意弄清应
【问题描述】客户业务分为两种。第一种是申请从银行得到一笔资金,即取款或借款。第二种是向银行投入一笔资金,即存款或还款。银行有两个服务窗口,相应地有两个队列。客户到达银行后先排第一个队。处理每个客户业务时,如果属于第一种,且申请额超出银行现存资金总额而得不到满足,则立刻排入第二个队等候,直至满足时才离开银行;否则业务处理完后立刻离开银行。每接待完一个第二种业务的客户,则顺序检查和处理(如果可能)第二个队列中的客户,对能满足的申请者予以满足,不能满足者重新排到第二个队列的队尾。注意,在此检查过程中,一旦银行资金总额少于或等于刚才第一个队列中最后一个客户(第二种业务)被接待之前的数额,或者本次已将第二个队列检查或处理了一遍,就停止检查(因为此时已不可能还有能满足者)转而继续接待第一个队列的客户。任何时刻都只开一个窗口。假设检查不需要时间。营业时间结束时所有客户立即离开银行。写一个上述银行业务的事件驱动模拟系统,通过模拟方法求出客户在银行内逗留的平均时间。
【基本要求】利用动态存储结构实现模拟。
【测试数据】一天营业开始时银行拥有的款额为10000(元),营业时间为600(分钟)。其他模拟参量自定,注意测定两种极端的情况:一是两个到达事件之间的间隔时间很短,而客户的交易时间很长,另一个恰好相反,设置两个到达事件的间隔时间很长,而客户的交易时间很短。
【实现提示】事件有两类:到达银行和离开银行。初始时银行现存资金总额为total。开始营业后的第一件事件是客户到达,营业时间从0到closetime。到达事件发生时随机地设置此客户的交易时间和距下一到达事件之间的时间间隔。每个客户要办理的款额也是随机确定的,用负值和正值分别表示第一类和第二类业务。变量total、closetime以及上述两个随机量的上下界均交互地从终端读入,作为模拟参数。
两个队列和一个事件表均要用动态存储结构实现。注意弄清应该在什么条件下设置离开事件,以及第二个队列用怎样的存储结构实现时可以获得较高的效率。注意:事件表是按时间顺序有序的。
【选作内容】
自己实现动态数据类型。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
typedef int Status;
#define OK 1
#define ERROR -1
typedef struct client_event
{
// 定义客户信息
int handel_time; // 事件处理时间
int money; // 需要处理的钱数目(负数表示取钱,正数表示存钱)
int No; // 客户的序号
} client;
typedef struct event
{
/*定义事件类型*/
int index; /*标志变量,1代表到达事件,其余代表离开事件*/
int time; /*事件发生时间*/
int No; /*触发该事件的客户序号*/
} event;
typedef struct LNode
{ /*定义链表节点*/
event data;
struct LNode *next;
} LNode, *Link;
typedef struct
{ /*定义链表*/
Link head, tail;
int len;
} List, *LinkList;
LinkList InitLink()
{ /*初始化链表操作*/
LinkList L = (LinkList)malloc(sizeof(List));
if (L == NULL)
return NULL;
L->head = NULL;
L->tail = NULL;
L->len = 0;
printf("链表初始化成功!!");
return L;
}
Status ClearLink(LinkList L)
{ /*链表的清空操作*/
if (L == NULL)
return ERROR;
Link p = L->head;
Link k = L->head->next;
while (p != L->tail)
{
free(p);
p = k;
if (k != L->tail)
k = k->next;
}
free(p);
L->head = NULL;
L->tail = NULL;
L->len = 0;
printf("链表已经清空!!");
return OK;
}
Status DestoryLink(LinkList L)
{ /*链表的销毁操作*/
if (L == NULL)
return ERROR;
ClearLink(L);
free(L);
printf("链表销毁完毕!!");
return OK;
}
Status InsertLink(LinkList L, event e)
{ /*链表的尾部插入操作*/
if (L == NULL)
return ERROR;
Link p = (Link)malloc(sizeof(LNode));
if (p == NULL)
return ERROR;
p->data = e;
p->next = NULL;
if (L->head == NULL)
{
L->head = p;
L->tail = p;
L->len = 1;
}
else
{
L->tail->next = p;
L->tail = p;
L->len++;
}
// printf("节点插入成功!!");
return OK;
}
Status LinkTraverse(LinkList L)
{ /*链表的遍历操作*/
if (L == NULL)
return ERROR;
Link p = L->head;
printf("\n遍历结果 :\n");
printf(" 客户序号: 事件触发时间: 事件类型: ");
printf("\n------------------------------------------------------------");
while (p != NULL)
{
printf("\n %d %d", p->data.No, p->data.time);
if (p->data.index == 1)
{
printf(" 到达");
printf("\n--------------------------------------------------------------");
}
else
{
printf(" 离开");
printf("\n-------------------------------------------------------------");
}
p = p->next;
}
return OK;
}
typedef struct LQNode
{ /*定义队列的节点*/
client *data;
struct LQNode *next;
} LQNode, *QueuePtr;
typedef struct
{ /*定义队列*/
QueuePtr front;
QueuePtr rear;
int len;
} *LQueue;
LQueue InitQueue()
{ /*初始化队列*/
LQueue Q = (LQueue)malloc(sizeof(LQueue));
if (Q == NULL)
return NULL;
Q->front = NULL;
Q->rear = NULL;
Q->len = 0;
return Q;
}
Status EnQueue(LQueue Q, client *e)
{ // 在队列的队尾插入e
QueuePtr p;
p = (QueuePtr)malloc(sizeof(LQNode));
if (p == NULL)
return ERROR;
p->data = e;
p->next = NULL;
if (Q->front == NULL)
{
Q->front = p;
Q->rear = p;
Q->len = 1;
}
else
{
Q->rear->next = p;
Q->rear = p;
Q->len++;
}
return OK;
}
Status DeQueue(LQueue Q, client *e)
{
// 队列Q的队头出队并且返回到e
QueuePtr p;
if (Q->front == NULL)
return ERROR;
p = Q->front;
*e = *(p->data);
Q->front = p->next;
if (Q->rear == p)
Q->rear = NULL;
free(p);
Q->len--;
return OK;
}
Status DestoryQueue(LQueue Q)
{
Status myfree(QueuePtr e);
/*队列的销毁操作*/
if (Q == NULL)
return ERROR;
QueuePtr p = NULL, q = NULL;
p = Q->front;
while (p != Q->rear)
{
q = p->next;
myfree(p);
p = q;
}
free(Q->rear);
free(Q);
return OK;
}
Status InsertQueue(LQueue Q, LQueue E)
{
/*将E队列插入到Q队列的前面,并将Q队列作为新的队列释放E*/
if (E == NULL || E->front == NULL || E->rear == NULL)
return ERROR;
if (Q == NULL)
return ERROR;
if (Q->front == NULL || Q->rear == NULL)
{
Q->front = E->front;
Q->rear = E->rear;
}
else
{
E->rear->next = Q->front;
Q->front = E->front;
}
free(E);
return OK;
}
int total; /*一天营业开始时银行拥有的款额为10000(元)*/
int max_money;
LQueue handel_queue = NULL; /*定义第一个队列用于处理业务*/
LQueue wait_queue = NULL; /* 定义第二个队列用于存储等候的客户*/
LinkList event_link = NULL; /*定义一个事件表*/
int nextTime = 0; /*定义一个变量作为下一个客户的随机到达时间*/
int nexthandelTime = 0; /*定义一个变量作为正在排队的下一个客户处理时间*/
int kehu_NO = 1; /*客户的服务序号*/
client *leave_kehu = NULL; /*定义一个办理完业务要离开的客户变量,用于记录*/
client *search_kehu = NULL; /*定义一个用来存储待处理业务的客户变量*/
client *mymalloc(int max_timejiaoyi)
{
/*动态申请客户节点*/
client *e;
e = (client *)malloc(sizeof(client));
if (e == NULL)
return NULL;
e->handel_time = (rand() % max_timejiaoyi) + 1;
e->money = (rand() % (2 * max_money)) - max_money;
e->No = kehu_NO;
kehu_NO++;
return e;
}
Status myfree(QueuePtr e)
{
/*动态释放客户节点*/
if (e == NULL)
return ERROR;
free(e);
return OK;
}
client *Arrive_event(int i, int max_timejiange, int max_timejiaoyi)
{
/*用来处理新客户到达事件*/
if (nextTime == i)
{
printf("当前时间是:%d\n", i);
nextTime = nextTime + (rand() % max_timejiange) + 1; // 随机生成下一名客户到达时间,这里可以设置客户到达时间间隔的大小
client *p = NULL;
p = mymalloc(max_timejiaoyi); // 到达前面设置的到达时间时,随机生成刚到达用户的信息,包括客户编号,业务处理时间,业务操作钱的数目
event *e = (event *)malloc(sizeof(event)); // 生成该到达事件的信息节点
e->index = 1;
e->No = p->No;
e->time = i;
InsertLink(event_link, *e); // 将该到达事件的信息节点加入事件链表
if (nexthandelTime < i)
{ // 如果当前时间已经超过了下一个用户操作时间,则将当前时间和该到达用户处理业务的时间相加作为下一个用户操作时间
if (-(p->money) <= total)
{
nexthandelTime = p->handel_time + i;
total = total + p->money;
EnQueue(handel_queue, p);
}
else
{
EnQueue(wait_queue, p);
}
}
else
{
if (nexthandelTime == 0)
{ // 第一个进入操作的用户情况
if (-(p->money) <= total)
{
nexthandelTime = p->handel_time + i;
total = total + p->money;
EnQueue(handel_queue, p);
}
else
{
EnQueue(wait_queue, p);
}
}
else
EnQueue(handel_queue, p);
}
printf("\n 客户编号:%d 客户操作需要时间:%d 客户需要处理的钱:%d 银行余额:%d\n\n\n", p->No, p->handel_time, p->money, total);
return p;
}
}
Status handel_event(int i)
{
/*处理队列事件*/
if (nexthandelTime == i)
{ /*到达下一个客户操作时间时*/
Status Leave_event(client * e, int i);
DeQueue(handel_queue, leave_kehu); // 将处理完的客户出队,并将客户信息存储在leave_kehu变量中
int last_money = total - leave_kehu->money; // 获取刚离开的客户操作前银行的钱数目
Leave_event(leave_kehu, i); // 将离开事件的用户信息存入事件列表中
if (((leave_kehu->money) > 0) && wait_queue->front != NULL)
{
/*如果刚刚离开的用户是存钱或者还钱,并且 等待队列 不为空*/
int len = wait_queue->len;
int index = 0; // 设置标记变量,用以标记等待队列已经查看的客户数目
LQueue e = InitQueue(); // 创造出一个可以被满足需求的等待用户组成的队列
int linshi_total = total; // 设置一个临时金额存储空间
while (linshi_total > last_money && wait_queue->front != NULL)
{ // 如果当前银行拥有的款额比之前多,进入循环
DeQueue(wait_queue, search_kehu); // 将等待队列的队头用户出队
if (-(search_kehu->money) <= linshi_total)
{
/*如果等待用户的需求可以得到满足*/
EnQueue(e, search_kehu); // 将可满足用户加入等待用户队列
linshi_total = linshi_total + search_kehu->money;
}
else
{
EnQueue(wait_queue, search_kehu);
}
index++;
if (index >= len)
break;
}
InsertQueue(handel_queue, e); // 将可以满足要求的等待队列并入前面
if (handel_queue->front != NULL)
{
/*如果操作队列不为空*/
while (handel_queue->front != NULL && -(handel_queue->front->data->money) > total)
/*如果无法满足要求*/
{
DeQueue(handel_queue, leave_kehu);
EnQueue(wait_queue, leave_kehu);
}
if (handel_queue->front != NULL)
{
nexthandelTime = handel_queue->front->data->handel_time + nexthandelTime; // 下一位操作客户时间更新
total = total + handel_queue->front->data->money; // 银行金钱总额更新
}
}
}
else
{
/*刚刚离开的用户是取钱或者借钱,或者 等待队列 为空*/
if (handel_queue->front != NULL)
{
while (handel_queue->front != NULL && -(handel_queue->front->data->money) > total)
{
/*无法满足的用户进入等待队列*/
DeQueue(handel_queue, leave_kehu);
EnQueue(wait_queue, leave_kehu);
}
if (handel_queue->front != NULL)
{
/*处理队列不为空*/
nexthandelTime = handel_queue->front->data->handel_time + nexthandelTime;
total = total + handel_queue->front->data->money;
}
}
}
}
}
Status Leave_event(client *e, int i)
{
/*用来处理客户离开事件*/
event *p = (event *)malloc(sizeof(event));
p->index = 0;
p->No = e->No;
p->time = i;
InsertLink(event_link, *p);
return OK;
}
double average_StayTime(LinkList e, double final)
{
/*通过事件列表来计算用户平均逗留时间*/
double sum = 0, a, b;
int shumu = 0;
LNode *p = e->head;
for (int i = 1; i <= e->len; i++)
{
while (p != NULL)
{
if (p->data.No == i)
{
if (p->data.index == 1)
{
a = p->data.time;
shumu = shumu + 1;
}
if (p->data.index == 0)
b = p->data.time;
}
p = p->next;
}
p = e->head;
if (b == -1.0)
b = final;
sum = sum + b - a;
b = -1.0;
}
printf("全部用户数: %d \n总共消耗时间: %f \n", shumu, sum);
printf("客户平均逗留时间: %f 分", sum / shumu);
return sum / shumu;
}
int main()
{
LQueue InitQueue();
client *Arrive_event(int i, int max_timejiange, int max_timejiaoyi);
Status handel_event(int i);
Status LinkTraverse(LinkList L);
double average_StayTime(LinkList e, double final);
Status DestoryQueue(LQueue Q);
Status ClearLink(LinkList L);
Status myfree(QueuePtr e);
leave_kehu = (client *)malloc(sizeof(client));
search_kehu = (client *)malloc(sizeof(client));
handel_queue = InitQueue();
wait_queue = InitQueue();
event_link = InitLink();
srand((unsigned int)time(NULL));
int MAXTIME, MAX_TIMEJIANGE, MAX_TIMEJIAOYI;
printf("请输入银行的运营时间(单位:分钟):");
scanf_s("%d", &MAXTIME);
printf("请输入银行的运营金额(单位:元):");
scanf_s("%d", &total);
printf("请输入用户最大交易金额(单位:元):");
scanf_s("%d", &max_money);
printf("请输入俩个到达事件的最大时间间隔:(单位:分钟):");
scanf_s("%d", &MAX_TIMEJIANGE);
printf("请输入用户最大交易时间:(单位:分钟):");
scanf_s("%d", &MAX_TIMEJIAOYI);
for (int i = 0; i < MAXTIME; i++)
{
Arrive_event(i, MAX_TIMEJIANGE, MAX_TIMEJIAOYI);
handel_event(i);
Sleep(50);
}
LinkTraverse(event_link);
printf("\n");
average_StayTime(event_link, MAXTIME - 1);
DestoryQueue(handel_queue);
DestoryQueue(wait_queue);
return 1;
}

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)