求解C++模拟银行排队问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求解C++模拟银行排队问题相关的知识,希望对你有一定的参考价值。

设计一个队列类,使用动态数组设定队列数据存放。要求实现队列的构造函数,析构函数,拷贝构造函数(深度拷贝)。

使用本队列,模拟银行自助取款机。假如某网点有1台取款机,每人的处理时间介于0-m分钟,平均0-n分钟进入一个人。要求模拟一小时的效果

使用随机数发生器

可以扩展成为多个取款机,排队的人看哪一队少,就排到相应的队列

也可以模拟银行柜台的排队方式,所有人排成一个队列,多个窗口采用叫号从同一个队列取客户处理。模拟一个小时

参考技术A //LinkQueue.h文件:

int const ERROR=-99999;
class Node

public:
int data;
Node *link;
Node(int data,Node *link)

this->data=data;
this->link=link;

Node(int data)

this->data=data;
this->link=NULL;

;
class LinkQueue

private:
Node *first;
Node *rare;
int length;
public:
LinkQueue()

first=NULL;
rare=NULL;
length=0;

LinkQueue(LinkQueue & linkq)

first=NULL;
rare=NULL;
length=0;
int len=linkq.getLength(),cnt=0;
int *tempArray=new int[len];
for(Node *p=linkq.first;p!=0;p=p->link)

tempArray[cnt]=p->data;
cnt++;

for(int i=0;i<len;i++)
enQueue(tempArray[i]);

bool isEmpty()

return length==0;

void traverse()

if(isEmpty())
return;
for(Node *p=first;p!=0;p=p->link)

cout<<p->data<<" ";

cout<<endl;

void enQueue(int x)

Node *q=new Node(x);
if(length==0)

rare=first=q;

else

rare->link=q;
rare=rare->link;

length++;

int deQueue()

if(isEmpty())
return ERROR;
int x=first->data;
Node *p=first;
first=first->link;
if(length==1) rare=NULL;
delete p;
length--;
return x;

int getLastElement()

if(!isEmpty())
return first->data;
else return ERROR;

int getLength()

return length;

~LinkQueue()

Node *q=first;
while(first)

first=first->link;
delete q;
q=first;


;

//main.cpp文件:
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
#include"LinkQueue.h"
//开启了x个窗口
void runXLine(int n,int m,int x)

LinkQueue* l=new LinkQueue[x];
srand((unsigned)time(NULL));
int totalTime=60;
int randomTime=0;
int nextTime=rand()%n+1;
int* handleTime=new int[x];
int j,min;
for(;totalTime>0;totalTime--)

//时间到了就来一个人
nextTime--;
if(nextTime==0)

cout<<"time: "<<60-totalTime<<endl;
randomTime=rand()%m+1;
//找到最短的队伍并进入
min=0;
for(int i=1;i<x;i++)
if(l[i].getLength()<l[min].getLength())
min=i;
l[min].enQueue(randomTime);
if(l[min].getLength()==1) handleTime[min]=randomTime;
//输出信息
cout<<"a person added queue "<<min<<"!("<<randomTime<<" miniutes)"<<endl;
for(j=0;j<x;j++)

cout<<"the queue "<<j<<":";
if(l[j].isEmpty()) cout<<endl;else l[j].traverse();

cout<<"------------------"<<endl;
nextTime=rand()%n+1;

//考察每个队伍
for(int k=0;k<x;k++)

//第一个人的处理时间减一,若为0则走人
if(!l[k].isEmpty())

handleTime[k]--;
if(handleTime[k]==0)

l[k].deQueue();
if(!l[k].isEmpty()) handleTime[k]=l[k].getLastElement();
cout<<"time: "<<60-totalTime<<endl;
cout<<"a person of queue "<<k<<" is gone!"<<endl;
for(j=0;j<x;j++)

cout<<"the queue "<<j<<":";
if(l[j].isEmpty()) cout<<endl;else l[j].traverse();

cout<<"------------------"<<endl;





void runOneLine(int n,int m)

LinkQueue l;
srand((unsigned)time(NULL));
int totalTime=60;
int randomTime=0;
int nextTime=rand()%n+1;
int handleTime=0;
for(;totalTime>0;totalTime--)

//时间到了就来一个人
nextTime--;
if(nextTime==0)

cout<<"time: "<<60-totalTime<<endl;
randomTime=rand()%m+1;
l.enQueue(randomTime);
if(l.getLength()==1) handleTime=randomTime;
cout<<"a person added!("<<randomTime<<" miniutes)"<<endl;
cout<<"the queue:";
if(l.isEmpty()) cout<<endl;else l.traverse();
cout<<"------------------"<<endl;
nextTime=rand()%n+1;

if(!l.isEmpty())

//第一个人的处理时间减一,若为0则走人
handleTime--;
if(handleTime==0)

l.deQueue();
if(!l.isEmpty()) handleTime=l.getLastElement();
cout<<"time: "<<60-totalTime<<endl;
cout<<"a person is gone!"<<endl;
cout<<"the queue:";
if(l.isEmpty()) cout<<endl;else l.traverse();
cout<<"------------------"<<endl;




void runCallLine(int n,int m,int x)

LinkQueue l;
srand((unsigned)time(NULL));
int *call=new int[x];
int i,j,k;
//call数组存放每个柜台的客户的剩余处理时间
for(i=0;i<x;i++)
call[i]=0;
int totalTime=60;
int randomTime=0;
int nextTime=rand()%n+1;
for(;totalTime>0;totalTime--)

//时间到了就来一个人
nextTime--;
if(nextTime==0)

cout<<"time: "<<60-totalTime<<endl;
randomTime=rand()%m+1;
l.enQueue(randomTime);
cout<<"a person added!("<<randomTime<<" miniutes)"<<endl;
cout<<"the queue:";
if(l.isEmpty()) cout<<endl;else l.traverse();
for(j=0;j<x;j++)
cout<<"the counter "<<j<<":"<<call[j]<<endl;
cout<<"------------------"<<endl;
nextTime=rand()%n+1;

//每个柜台的剩余时间减一
for(k=0;k<x;k++)

if(call[k]>0)

call[k]--;
if(call[k]==0)

cout<<"time: "<<60-totalTime<<endl;
cout<<"the person at counter "<<k<<" has left!"<<endl;
cout<<"the queue:";
if(l.isEmpty()) cout<<endl;else l.traverse();
for(j=0;j<x;j++)
cout<<"the counter "<<j<<":"<<call[j]<<endl;
cout<<"------------------"<<endl;



//若为0了则走人,下一个人上
for(k=0;k<x;k++)

if(call[k]<=0)

if(!l.isEmpty())

cout<<"time: "<<60-totalTime<<endl;
cout<<"a person goes to the counter "<<k<<"!"<<endl;
call[k]=l.deQueue();
cout<<"the queue:";
if(l.isEmpty()) cout<<endl;else l.traverse();
for(j=0;j<x;j++)
cout<<"the counter "<<j<<":"<<call[j]<<endl;
cout<<"------------------"<<endl;





void main()

runOneLine(5,5);
// runXLine(5,10,2);
// runCallLine(10,20,2);
//这里的数据是推荐测试的数据,过小会导致对话框不够显示。

参考技术B 一个良好的问题必须要包括输入输出格式,输入输出样例

第三章:6.栈和队列 -- 离散事件模拟

前言:

  本节讲述,队列的入队 和 离队行为,由事件决定情况下,是如何实现的。

目录:

  离散事件模拟

正文:

  问题:假设某银行有4个窗口对外接待客户,从早晨银行开门起不断有客户进入银行。由于每个窗口在某个时刻只能接待一个客户,因此在客户人数众多时需在每个窗口前顺次排队,对于刚进入银行的客户,如果某个窗口的业务员正空闲,则可上前办理业务,反之,若4个窗口均有客户所占,他便会排在人数最少的队伍后面。现在需要编制一个程序以模拟银行这种业务活动并计算一天中客户在银行逗留的平均时间。

  解题关键:掌握每个客户到达银行和离开银行这两个时刻,两者相减即为客户逗留时间。将逗留时间累加 除以 客户总数量 即为平均逗留时间。

  设:     在这里,每天银行开门的时间点 为 0 ,数字1代表1分钟,每天八小时 即CloseTime 为480, 客户逗留时间 为30分钟以内。两个客户到达 时间间隔 在5分钟以内。

  事件:  模拟程序中,共分为5种事件,1.客户到达事件,2-5.客户分别从四个窗口的离开时间。

  事件结点:

      typedef struct{
          int OccurTime;    //事件发生时间
          int NType;      //事件类型,0:客户到达,i (1-4):客户离开第 i 个窗口
      }Event

  客户节点:

      typedef struct{    
          int OccurTime;            //到达时间
          int Duration;            //办理事务所需时间
      }CustomerNode;

实现代码:

  由于CloseTime = 480 数据量较大,代码运行选取了CloseTime =30 作为示例。

#include<stdio.h>
#include<stdlib.h>
#include<time.h> 

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态码
typedef int Status;

//=================================  排队队列定义开始================================
typedef struct{    
    int OccurTime;            //到达时间
    int Duration;            //办理事务所需时间
}CustomerNode;

typedef CustomerNode ElemType;

//结点定义
typedef struct QNode{
    ElemType data;                //数据节点;
    struct QNode *next;            //结点的指针域
}QNode;

//队列链定义
typedef struct{
    QNode *front;                //队头指针
    QNode *rare;                //队尾指针
}LinkQueue;

//初始化一个空队列
Status InitQueue(LinkQueue &Q){
    Q.front=Q.rare=(QNode *)malloc(sizeof(QNode));
    if(!Q.front) exit(OVERFLOW);
    Q.front->next=NULL;
    return OK;
}

//判断是否为空队列
Status QueueEmpty(LinkQueue &Q){
    if(Q.front==Q.rare)
        return TRUE;
    return FALSE;
}
 
//判断长度
Status QueueLength(LinkQueue &Q){
    if(Q.front==Q.rare)
        return 0;
    int i=0;
    QNode *q=Q.front;
    while(q->next){
        q=q->next;
        i++;
    }
    return i;
}


//向队列尾部插入元素e
Status EnQueue(LinkQueue &Q,ElemType e){
    //生成 结点
    QNode *q;                        //指向新生成的结点
    q=(QNode *)malloc(sizeof(QNode));
    if(!q) exit(OVERFLOW);
    q->data=e;
    q->next=NULL;

    Q.rare->next=q;
    Q.rare=q;
    return OK;
}

//删除队列头部元素并返回
Status DeQueue(LinkQueue &Q,ElemType &e){
    if(Q.front==Q.rare) return ERROR;
    QNode *q=Q.front->next;
    e=Q.front->next->data;
    Q.front->next=Q.front->next->next;
    if(!Q.front->next)
        Q.rare=Q.front;
    free(q);
    return OK;
}

void printV(LinkQueue &Q){
    if(Q.front==Q.rare) 
        printf("%s\\n","空队列");
    QNode *q=Q.front;
    while(q->next){
        printf("地址:%p",q->next);
        printf("值:%d\\n",q->next->data);
        q=q->next;
    }
}

//=================================  排队队列定义结束 ================================




//=================================  事件链表定义开始 ================================

typedef struct{
    int OccurTime;
    int NType;
    int dur;
}Event,EvElemType;

typedef struct LNode{
    EvElemType data;                //单链表中结点的数据域
    struct LNode *next;                //结点的指针域
}LNode,*LinkList;

typedef LinkList EventList;


void InitList(LinkList &L){
    L=(LinkList)malloc(sizeof(LNode));    //生成新节点    
    if(!L) exit(OVERFLOW);
    L->next=NULL;
}

//在单链表中,取得第i个位置的值必须从头开始找起,因为每个结点元素的位置信息只能通过其直接前继结点确定
//获取L 中第i个元素的值,并用 e 返回。
Status GetElem_L(LinkList &L,int i,EvElemType &e){
    //此处L为带有头结点的单链表
    LNode * q;
    q=L->next;                    //p指向第一个结点
    int j=1;
    while(q&&j<i){
        //移动指针的错误写法:q++; 因为在链式存储结构中存储地址不一定是连续的
        q=q->next;
        j++;
    }    
    if(j!=i)
        return ERROR;
    e=q->data;
    return OK;
}//时间复杂度为 O(n)


//插入元素,在L中第i个位置之前插入数据 e
Status ListInsert_L(LinkList &L,int i,EvElemType e){
    //1.找到指向 第 i-1 处元素的指针
    LNode * q;
    q=L;                                //    q指向头结点
    int j=0;
    while(q&&j<(i-1)){
        q=q->next;                        //后移结点
        j++;
    }
    
    //正确j的可能值:0,(i-1),  
    if(!q||i<1)                        //1.q为NULL(i大于表长+1)  2.i不能小于1
        return ERROR;
    LNode * s;
    s=(LinkList)malloc(sizeof(LNode));    //生成新节点        
    s->data=e;                            //新结点数据域inti
    s->next=q->next; q->next=s;            //插入新结点    
    return OK;
}//时间复杂度为 O(n)

//按照事件发生的时间点顺序,将事件结点插入事件链表 时间点从小到大排序
Status OrderInsert(LinkList &L,EvElemType e){
    LNode * q;
    q=L;                                //    q指向头结点
    if(!q->next){
        ListInsert_L(L,1,e);
    }else{
        while(q->next&&e.OccurTime>=q->next->data.OccurTime){
            q=q->next;                        //后移指针
        }

        LNode * s;
        s=(LinkList)malloc(sizeof(LNode));    //生成新节点        
        s->data=e;                            //新结点数据域inti
        s->next=q->next; q->next=s;            //插入新结点            
    }    
    return OK;
}


//删除元素,在L中删除位置为i的元素,并用将返回值存储在e中。
Status ListDelete_L(LinkList &L,int i,EvElemType &e){
    //1.找到指向 第 i-1 处元素的指针
    LNode * q;
    q=L;                                //    q指向头结点
    int j=0;
    while(q&&j<(i-1)){
        q=q->next;                        //后移指针
        j++;
    }
    if(!(q->next)||i<1)                        //1.q->next不能为NULL(i位置不存在)  2.i不能小于1
        return ERROR;
    e=q->next->data;                    //将被删除的值保存在e中
    LNode * tem=q->next;                //保存 将被删除元素的坐在位置
    q->next=q->next->next;                //删除元素
    free(tem);                            //释放被删除元素占用的内存空间
    return OK;
}//时间复杂度为 O(n)


Status ListEmpty(LinkList &L){
    if(!L->next)
        return OK;
    return ERROR;
}

void printAllValues(LinkList &L){
    if(!L->next)
        printf("%s\\n","此表为空但链表");
    LNode *q;
    q=L;
    while(q->next){
        q=q->next;                        //指针后移
        printf("地址:%p,",q);
        printf("OccurTime:%d,",q->data.OccurTime);
        printf("NType:%d\\n",q->data.NType);
    }
}//时间复杂度为 O(n)


//=================================  事件链表定义结束 ================================



//=================================  银行排队业务模拟程序定义开始 ================================
EventList ev;                                //事件链表
Event en;                                    //事件结点

CustomerNode cn;                                //客户节点
LinkQueue q[5];                                //客户队列
int CloseTime;                                //银行结束时间

int TotalTime,CustomerNum;                    //累计逗留时间 ,累计客户数量

void OpenDay(){
    TotalTime=0;
    CustomerNum=0;

    InitList(ev);                            //初始化事件链表
    en.OccurTime=0;                            //设置第一个客户到达事件
    en.NType=0;

    //插入事件
    OrderInsert(ev,en);    

    int i=1;
    //初始化任务队列
    for(i=1;i<5;i++){
        InitQueue(q[i]);
    }    
}


//寻找队伍人数最少的队列。
int MinQueue(){
    int len=QueueLength(q[1]);
    int cur=1;
    for(int i=2;i<5;i++){
        if(len>QueueLength(q[i])){
            len=QueueLength(q[i]);
            cur=i;
        }
    }
    return cur;
}

//客户到达
void CustomerArrived(){
    ++CustomerNum;                                //增加客户数量

    int durTime=rand()%31;                        //产生0-30 间的随机整数,为到达客户等待的时间。

    int interTime=rand()%6;                        //产生0-5 间的随机整数,为与下一客户到达时间的时间间隔。
    
    int depT=en.OccurTime+durTime;
    int arrT=en.OccurTime+interTime;
    
    //开始排队,找到最短队伍,并加入队伍。
    int i=MinQueue();
    cn.OccurTime=en.OccurTime;
    cn.Duration=durTime;    
    EnQueue(q[i],cn);

    //把当前客户离开事件,加入事件列表
    en.OccurTime=depT;
    en.NType=i;
    en.dur=durTime;
    OrderInsert(ev,en);

    //下一客户到达事件,加入事件列表。
    en.OccurTime=arrT;
    en.NType=0;
    en.dur=0;
    if(en.OccurTime<CloseTime)
        OrderInsert(ev,en);        
}

//客户离开
void CustomerDepature(){    
    int i=en.NType;
    CustomerNode c;
    DeQueue(q[i],c);                                //删除队列元素(客户离开)
    TotalTime+=c.Duration;                            //累加客户业务等待时间
}

//计算平均逗留时间
void CloseDay(){
    printf("\\n总时间:%d\\n",TotalTime);
    printf("客户总数量:%d\\n",CustomerNum);
    printf("平均逗留时间:%d\\n",TotalTime/CustomerNum);
}                                            

//银行排队模拟程序
void Bank_Simulation(int CloseTime){
    OpenDay();
    
    while(!ListEmpty(ev)){        
        ListDelete_L(ev,1,en);                

        if(en.NType==0){
            printf("时间点:%d,客户到达\\n",en.OccurTime);    
            CustomerArrived();                    //客户到来
        }else{
            printf("时间点:%d,客户离开,",en.OccurTime);    
            printf("窗口:%d,",en.NType);    
            printf("等待时间:%d\\n",en.dur);
            CustomerDepature();                    //客户离开
        }
        
    }
    CloseDay();                                            //计算平均逗留时间
}


//=================================  银行排队业务模拟程序定义结束 ================================



void main(){
    CloseTime=30;
    srand((int)time(NULL));
    Bank_Simulation(CloseTime);    
}

运行结果:

   

 

以上是关于求解C++模拟银行排队问题的主要内容,如果未能解决你的问题,请参考以下文章

银行排队模拟(生产者-消费者模拟)

PTA 银行排队问题之单队列多窗口加VIP服务 队列+模拟

银行排队问题平均等到时间计算java?

3-9-模拟银行排队过程-栈和队列-第3章-《数据结构》课本源码-严蔚敏吴伟民版

c++队列银行业务模拟

C语言模拟排队编程,急求完整答案