diff --git a/README.md b/README.md index e1e9006..daa2886 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ ## 2.1 概要设计 大体分为三大模块: +```cpp (1)客户 void Bank_Simulation(int CloseTime);//银行业务模拟,统计一天内客户在银行逗留的平均时间 @@ -162,13 +163,13 @@ Status QueueEmpty(LinkQueue Q);//判断队列是否为空 void PrintQueue();//打印队列 Status QueueTraverse(LinkQueue Q);//遍历队列Q  - +``` ## 2.2 数据结构设计 采用了链表和链队列 ### (1)链表结构 - +```cpp Status InitList(LinkList& L);//链表初始化 Status ListInsert_L(LinkList& L, int i, ElemType e);//在第i个位置之前插入元素e @@ -184,9 +185,9 @@ ElemType GetCurElem(LNode* p);//已知p指向线性链表中的一个结点, void PrintEventList();//打印事件链表 Status ListTraverse(LinkList& L);//遍历链表  - +``` ### (2)链队列结构 - +```cpp Status InitQueue(LinkQueue& Q);//链队列的初始化 Status EnQueue(LinkQueue& Q, QElemType e);//入队 @@ -202,13 +203,13 @@ Status QueueEmpty(LinkQueue Q);//判断队列是否为空 void PrintQueue();//打印队列 Status QueueTraverse(LinkQueue Q);//遍历队列Q  - +``` ### ## 2.3 算法设计 ### (1)链表初始化算法 - +```cpp 链表初始化 { L = (LinkList)malloc(sizeof(LNode)); @@ -217,9 +218,9 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  L->next = NULL; return OK; } - +``` ### (2)链表判空算法 - +```cpp 判断链表是否为空 { if (L->next) @@ -228,16 +229,16 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  return TRUE; } } - +``` ### (3) 打印事件链表算法 - +```cpp {  printf("Current Eventlist is:\n"); ListTraverse(ev); } - +``` ### (4) 遍历链表算法 - +```cpp { LNode* p = L->next; if (!p) { @@ -251,9 +252,9 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  printf("\n"); return OK; } - +``` ### (5) 链队列初始化算法 - +```cpp { Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); if (!Q.front) @@ -261,9 +262,9 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  Q.front->next = NULL; return OK; } - +``` ### (6) 队列判空算法 - +```cpp { if (Q.front == Q.rear) { @@ -271,9 +272,9 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  } return FALSE; } - +``` ### (7) 打印队列算法 - +```cpp { int i; for (i = 1; i <= 4; i++) { @@ -282,9 +283,9 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  } printf("\n"); } - +``` ### (8) 遍历队列算法 - +```cpp { QNode* p = Q.front->next; if (!p) { @@ -298,11 +299,11 @@ Status QueueTraverse(LinkQueue Q);//遍历队列Q  printf("\n"); return OK; } - +``` # 3. 系统实现 项目采用 C 语言编程实现,在 VS Code 集成开发环境(IDE)中用 GCC 进行编译。系统采用模块化设计,程序结构清晰 - +```cpp void Bank_Simulation(int CloseTime);//银行业务模拟,统计一天内客户在银行逗留的平均时间 int cmp(Event a, Event b);//比较事件发生先后 void OpenForDay();//银行开门 @@ -326,7 +327,7 @@ Status GetHead(LinkQueue Q, QElemType& e);//获取队头元素 注:由于参 Status QueueEmpty(LinkQueue Q);//判断队列是否为空 void PrintQueue();//打印队列 Status QueueTraverse(LinkQueue Q);//遍历队列Q  - +``` ## 3.1 核心数据结构的实现 主要为有序链表和队列两种数据类型 @@ -709,7 +710,12 @@ return OK; 成员3(李聪颖):在参与银行业务模拟系统项目的过程中,我获得了很多经验和收获。首先,是这个项目内容。它让我了解到银行工作内部是如何运行的。每一步都是有代码的支撑。每一个步骤都是承接着的,怎样让他优质且高效的运行是极其重要的。然后,是我的能力,在这个项目中,我的书写代码能力得到有效提升,能够更好把握代码书写规范以及他的运作性能,更好的创建一个代码文件。最后,便是对于完成一个项目最重要的部分,那就是团队合作。相较于之前合作,我感觉我和团队合作比之前更加默契了,更能准确掌握自己的部分,和其他成员有秩序的进行这个项目,效率也大大改善。 -成员4(武杭凯): +成员4(武杭凯):实践项目为我提供了一个将在课堂学到的理论知识应用到实际项目中的机会。这种学习方式让我更加深入地理解了编程技术和软件开发过程,并提高了解决问题的能力。 +团队合作与沟通:在实践项目中,与团队成员的密切合作是至关重要的。通过与他人合作,我学会了有效地分工合作、协调任务、分享资源和沟通协作。这对于项目的成功至关重要。 +解决问题的能力:实践项目中经常会遇到各种难题和挑战。在解决问题的过程中,我学会了分析问题、找出解决方案、进行调试和测试,并最终找到最佳的解决方案。这种解决问题的能力在实际工作中也非常重要。 +时间管理和组织能力:参与实践项目需要合理地安排时间和资源。我学会了制定计划、设定目标、优先排列任务,并在规定的时间内完成工作。这种时间管理和组织能力对于提高效率和保证项目顺利进行至关重要。 +学习与成长:通过实践项目,我不仅在技术上得到了提升,还培养了自主学习和持续学习的能力。我了解到编程和软件开发是一个不断演进和深入学习的领域,因此,我将继续学习和不断提升自己。 +总的来说,参加程序设计实践项目对我来说是一个难得的机会和宝贵的经验。通过这个项目,我不仅学到了技术知识,还培养了团队合作、解决问题、时间管理和自主学习等能力。 # 参考文献 diff --git a/代码 b/代码 index b54281e..7b3b53d 100644 --- a/代码 +++ b/代码 @@ -1,705 +1,386 @@ #define _CRT_SECURE_NO_WARNINGS - #include - #include - #include - #define TRUE 1 - #define FALSE 0 - #define OK 1 - #define ERROR 0 - #define INFEASIBLE -1 - #define OVERFLOW -2 typedef int Status; - - typedef struct - { - -int OccurTime;//事件发生时刻 - -int NType;//事件类型,0表示到达事件,1-4表示四个窗口的离开事件 - + int OccurTime;//事件发生时刻 + int NType;//事件类型,0表示到达事件,1-4表示四个窗口的离开事件 }Event, ElemType; typedef struct LNode - { - -ElemType data; - -struct LNode* next; - + ElemType data; + struct LNode* next; }LNode, * LinkList; typedef LinkList EventList; - - typedef struct - { - -int ArrivalTime;//到达时刻 - -int Duration;//办理事务所需事件 - + int ArrivalTime;//到达时刻 + int Duration;//办理事务所需事件 }QElemType; typedef struct QNode - { - -QElemType data; - -struct QNode* next; - + QElemType data; + struct QNode* next; }QNode, * QueuePtr; typedef struct - { - -QueuePtr front;//队头指针 - -QueuePtr rear;//队尾指针 - + QueuePtr front;//队头指针 + QueuePtr rear;//队尾指针 }LinkQueue; - - EventList ev;//事件表 - Event en;//事件 - LinkQueue q[5];//四个客户队列 - QElemType customer;//客户记录 - int TotalTime, CustomerNum, CloseTime; - - void Bank_Simulation(int CloseTime);//银行业务模拟,统计一天内客户在银行逗留的平均时间 - int cmp(Event a, Event b);//比较事件发生先后 - void OpenForDay();//银行开门 - void OrderInsert(EventList L, Event en, int(*cmp)(Event a, Event b));//插入事件 - void CustomerArrived();//客户进门 - void CustomerDepature();//客户离开 - int Minimum(LinkQueue Q[5]);//求长度最短队列 - - Status InitList(LinkList& L);//链表初始化 - Status ListInsert_L(LinkList& L, int i, ElemType e);//在第i个位置之前插入元素e - Status ListEmpty(LinkList L);//判断链表是否为空 - Status DelFirst(LinkList L, LNode*& q);//删除链表中第一个结点并以q返回 - LNode* GetHead(LinkList L);//返回链表头结点 - ElemType GetCurElem(LNode* p);//已知p指向线性链表中的一个结点,返回p所指结点中元素的值 - void PrintEventList();//打印事件链表 - Status ListTraverse(LinkList& L);//遍历链表  - - -Status InitQueue(LinkQueue& Q);//链队列的初始化 - +Status InitQueue(LinkQueue& Q);//链队列的初始 Status EnQueue(LinkQueue& Q, QElemType e);//入队 - Status DeQueue(LinkQueue& Q, QElemType& e);//出队 - int QueueLength(LinkQueue Q);//返回队列的长度 - Status GetHead(LinkQueue Q, QElemType& e);//获取队头元素 注:由于参数个数不同,发生函数重载 - Status QueueEmpty(LinkQueue Q);//判断队列是否为空 - void PrintQueue();//打印队列 - Status QueueTraverse(LinkQueue Q);//遍历队列Q  int main() - { - -srand((unsigned)time(NULL));//设定随机数种子 - -printf("请输入银行的营业时间(min):"); - -scanf("%d", &CloseTime); - -Bank_Simulation(CloseTime); - -return 0; - + srand((unsigned)time(NULL));//设定随机数种子 + printf("请输入银行的营业时间(min):"); + scanf("%d", &CloseTime); + Bank_Simulation(CloseTime); + return 0; } void Bank_Simulation(int CloseTime)//银行业务模拟,统计一天内客户在银行逗留的平均时间 - -{ - -OpenForDay();//开始营业 - -LNode* p; - -while (!ListEmpty(ev)) - { - -DelFirst(GetHead(ev), p); - -printf("********action********\n"); - -en = GetCurElem(p); - -if (en.NType == 0) - -{ - -CustomerArrived(); - + OpenForDay();//开始营业 + LNode* p; + while (!ListEmpty(ev)) + { + DelFirst(GetHead(ev), p); + printf("********action********\n"); + en = GetCurElem(p); + if (en.NType == 0) + { + CustomerArrived(); + } + else + { + CustomerDepature(); + } + PrintQueue(); + PrintEventList(); + } + printf("The Average Time is %f\n", (float)TotalTime / CustomerNum); } -else - -{ - -CustomerDepature(); - -} - -PrintQueue(); - -PrintEventList(); - -} - -printf("The Average Time is %f\n", (float)TotalTime / CustomerNum); - -} - - int cmp(Event a, Event b)//比较事件发生先后 - { - -if (a.OccurTime > b.OccurTime) return 1; - -if (a.OccurTime = b.OccurTime) return 0; - -if (a.OccurTime < b.OccurTime) return -1; - + if (a.OccurTime > b.OccurTime) return 1; + if (a.OccurTime = b.OccurTime) return 0; + if (a.OccurTime < b.OccurTime) return -1; } - void OpenForDay()//银行开门 - //初始化操作 - -{ - -TotalTime = 0;//初始化累计时间为0 - -CustomerNum = 0;//初始化客户数为0 - -InitList(ev);//初始化事件链表为空表 - -en.OccurTime = 0; - -en.NType = 0;//设定第一个客户到达事件 - -OrderInsert(ev, en, cmp); - -for (int i = 1; i <= 4; i++) - { - -InitQueue(q[i]);//将四个银行窗口队列初始化 - -} - + TotalTime = 0;//初始化累计时间为0 + CustomerNum = 0;//初始化客户数为0 + InitList(ev);//初始化事件链表为空表 + en.OccurTime = 0; + en.NType = 0;//设定第一个客户到达事件 + OrderInsert(ev, en, cmp); + for(int i = 1;i<=4;i++) + { + InitQueue(q[i]);//将四个银行窗口队列初始化 + } } - void OrderInsert(EventList L, Event en, int(*cmp)(Event a, Event b))//插入事件 - //事件插入函数,将不同事件按发生时间递增排序 - { - -LNode* p = L; - -int i = 1; - -while (p->next && cmp(en, p->next->data) > 0)//找到事件发生时间所在事件链表中的位置 - -{ - -p = p->next; - -i++; - -} - -ListInsert_L(ev, i, en);//插入该事件 - + LNode* p = L; + int i = 1; + while (p->next && cmp(en, p->next->data) > 0)//找到事件发生时间所在事件链表中的位置 + { + p = p->next; + i++; + } + ListInsert_L(ev, i, en);//插入该事件 } void CustomerArrived()//客户进门 - -//处理客户到达事件,en.NType=0 - -{ - -CustomerNum++; - -int durtime = rand() % 30 + 1;//客户处理事务时间 - -int intertime = rand() % 8;//下一个客户到达的时间间隔 - -int t = en.OccurTime + intertime;//下一个客户到达的时刻 - -if (t < CloseTime)//如果他在营业时间内进来 - -{ - -printf("一个新客户在银行营业%2dmin后进来,办理业务花费了%2dmin,下一个客户过了%2dmin后进来\n", en.OccurTime, durtime, intertime); - -OrderInsert(ev, { t, 0 }, cmp);//插入客户进门事件,NType=0为到达事件 - +//处理客户到达事件 +{ + CustomerNum++; + int durtime = rand() % 30 + 1;//客户处理事务时间 + int intertime = rand() % 8;//下一个客户到达的时间间隔 + int t = en.OccurTime + intertime;//下一个客户到达的时刻 + if (t < CloseTime)//如果他在营业时间内进来 + { + printf("一个新客户在银行营业%2dmin后进来,办理业务花费了%2dmin,下一个客户过了%2dmin后进来\n", en.OccurTime, durtime, intertime); + OrderInsert(ev, { t, 0 }, cmp);//插入客户进门事件,NType=0为到达事件 + } + int i = Minimum(q);//客户找最短队开始排队 + EnQueue(q[i], { en.OccurTime, durtime }); + if (QueueLength(q[i]) == 1) + { + OrderInsert(ev, { en.OccurTime + durtime,i }, cmp);//队列长度为1时,设定一个离开事件 + } } -int i = Minimum(q);//客户找最短队开始排队 - -EnQueue(q[i], { en.OccurTime, durtime }); - -if (QueueLength(q[i]) == 1) - -{ - -OrderInsert(ev, { en.OccurTime + durtime,i }, cmp);//队列长度为1时,设定一个离开事件 - -} - -} - - void CustomerDepature()//客户离开 - { - -int i = en.NType; - -DeQueue(q[i], customer);//删除第i队列的排头客户 - -TotalTime += en.OccurTime - customer.ArrivalTime;//累计客户逗留时间 - -if (!QueueEmpty(q[i])) { - -GetHead(q[i], customer); - -OrderInsert(ev, { en.OccurTime + customer.Duration, i }, cmp);//插入事件 - + int i = en.NType; + DeQueue(q[i], customer);//删除第i队列的排头客户 + TotalTime += en.OccurTime - customer.ArrivalTime;//累计客户逗留时间 + if (!QueueEmpty(q[i])) + { + GetHead(q[i], customer); + OrderInsert(ev, { en.OccurTime + customer.Duration, i }, cmp);//插入事件 + } } -} - - int Minimum(LinkQueue Q[5])//求长度最短队列 - -{ - -int minLength = QueueLength(Q[1]); - -int i = 1; - -for (int j = 2; j < 5; j++) - { - -if (minLength > QueueLength(Q[j])) - -{ - -minLength = QueueLength(Q[j]); - -i = j; - -} - -} - -return i; - + int minLength = QueueLength(Q[1]); + int i = 1; + for (int j = 2; j < 5; j++) + { + if (minLength > QueueLength(Q[j])) + { + minLength = QueueLength(Q[j]); + i = j; + } + } + return i; } Status InitList(LinkList& L)//链表初始化 - -{ - -L = (LinkList)malloc(sizeof(LNode)); - -if (!L) - { - -exit(OVERFLOW); - -} - -L->next = NULL; - -return OK; - + L = (LinkList)malloc(sizeof(LNode)); + if (!L) + { + exit(OVERFLOW); + } + L->next = NULL; + return OK; } Status ListInsert_L(LinkList& L, int i, ElemType e)//在第i个位置之前插入元素e - { - -LinkList p = L; - -int j = 0; - -while (p && j < i - 1)//注意是i-1,因为要找被插入元素的前一个元素 - -{ - -p = p->next; - -j++; - -} - -if (!p || j > i - 1) - -{ - -return ERROR; - -} - -LinkList s = (LinkList)malloc(sizeof(LNode)); - -if (!s) - -{ - -exit(OVERFLOW); - -} - -s->data = e; - -s->next = p->next; - -p->next = s; - -return OK; - + LinkList p = L; + int j = 0; + while (p && j < i - 1)//注意是i-1,因为要找被插入元素的前一个元素 + { + p = p->next; + j++; + } + if (!p || j > i - 1) + { + return ERROR; + } + LinkList s = (LinkList)malloc(sizeof(LNode)); + if (!s) + { + exit(OVERFLOW); + } + s->data = e; + s->next = p->next; + p->next = s; + return OK; } Status ListEmpty(LinkList L)//判断链表是否为空 - //空表:头指针和头结点仍然存在,但头结点指向NULL - -{ - -if (L->next) - -{ - -return FALSE; - -} - -else - { - -return TRUE; - -} - + if (L->next) + { + return FALSE; + } + else + { + return TRUE; + } } Status DelFirst(LinkList L, LNode*& q)//删除链表中第一个结点并以q返回 - -{ - -if (!L->next) - { - -return ERROR; - -} - -q = L->next; - -L->next = q->next; - -return OK; - + if (!L->next) + { + return ERROR; + } + q = L->next; + L->next = q->next; + return OK; } LNode* GetHead(LinkList L)//返回链表头结点 - { - -return L; - + return L; } ElemType GetCurElem(LNode* p)//已知p指向线性链表中的一个结点,返回p所指结点中元素的值 - { - -return p->data; - + return p->data; } void PrintEventList()//打印事件链表  - {  - -printf("Current Eventlist is:\n"); - -ListTraverse(ev); - + printf("Current Eventlist is:\n"); + ListTraverse(ev); } Status ListTraverse(LinkList& L) //遍历链表   - { - -LNode* p = L->next; - -if (!p) { - -printf("List is empty.\n"); - -return ERROR; - -} - -while (p != NULL) { - -printf("OccurTime:%d,Event Type:%d\n", p->data.OccurTime, p->data.NType); - -p = p->next; - -} - -printf("\n"); - -return OK; - + LNode* p = L->next; + if (!p) { + printf("List is empty.\n"); + return ERROR; + } + while (p != NULL) { + printf("OccurTime:%d,Event Type:%d\n", p->data.OccurTime, p->data.NType); + p = p->next; + } + printf("\n"); + return OK; } Status InitQueue(LinkQueue& Q)//链队列的初始化 - { - -Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); - -if (!Q.front) - -{ - -exit(OVERFLOW); - -} - -Q.front->next = NULL; - -return OK; - + Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); + if (!Q.front) + { + exit(OVERFLOW); + } + Q.front->next = NULL; + return OK; } Status EnQueue(LinkQueue& Q, QElemType e)//入队 - -{ - -QNode* p = (QueuePtr)malloc(sizeof(QNode)); - -if (!p) - { - -exit(OVERFLOW); - -} - -p->data = e; - -p->next = NULL; - -Q.rear->next = p; - -Q.rear = p; - -return OK; - + QNode* p = (QueuePtr)malloc(sizeof(QNode)); + if (!p) + { + exit(OVERFLOW); + } + p->data = e; + p->next = NULL; + Q.rear->next = p; + Q.rear = p; + return OK; } Status DeQueue(LinkQueue& Q, QElemType& e)//出队 - { - -if (Q.front == Q.rear) - -{ - -return ERROR; - -} - -QNode* p = Q.front->next; - -e = p->data; - -Q.front->next = p->next; - -if (Q.rear == p)//注意这里要考虑到,当队列中最后一个元素被删后,队列尾指针也丢失了,因此需对队尾指针重新复制(指向头结点) - -{ - -Q.rear = Q.front; - -} - -free(p); - -return OK; - + if (Q.front == Q.rear) + { + return ERROR; + } + QNode* p = Q.front->next; + e = p->data; + Q.front->next = p->next; + if (Q.rear == p)//注意这里要考虑到,当队列中最后一个元素被删后,队列尾指针也丢失了,因此需对队尾指针重新复制(指向头结点) + { + Q.rear = Q.front; + } + free(p); + return OK; } int QueueLength(LinkQueue Q)//返回队列的长度 - { - -int count = 0; - -QNode* p = Q.front->next; - -while (p) { - -p = p->next; - -count++; - -} - -return count; - + int count = 0; + QNode* p = Q.front->next; + while (p) { + p = p->next; + count++; + } + return count; } Status GetHead(LinkQueue Q, QElemType& e)//获取队头元素 - -{ - -if (Q.front == Q.rear) - { - -return ERROR; - -} - -e = Q.front->next->data; - + if (Q.front == Q.rear) + { + return ERROR; + } + e = Q.front->next->data; } Status QueueEmpty(LinkQueue Q)//判断队列是否为空 - -{ - -if (Q.front == Q.rear) - { - -return TRUE; - -} - -return FALSE; - + if (Q.front == Q.rear) + { + return TRUE; + } + return FALSE; } void PrintQueue()//打印队列 - { - //打印当前队列   - -int i; - -for (i = 1; i <= 4; i++) { - -printf("窗口 %d 有 %d 个客户:", i, QueueLength(q[i])); - -QueueTraverse(q[i]); - -} - -printf("\n"); - + int i; + for (i = 1; i <= 4; i++) + { + printf("窗口 %d 有 %d 个客户:", i, QueueLength(q[i])); + QueueTraverse(q[i]); + + } + printf("\n"); } Status QueueTraverse(LinkQueue Q)//遍历队列Q   - { - -QNode* p = Q.front->next; - -if (!p) { - -printf("--Is empty.\n"); - -return ERROR; - -} - -while (p) { - -printf("(到达时刻 %d min 办理业务需要花费 %d min) ", p->data.ArrivalTime, p->data.Duration); - -p = p->next; - -} - -printf("\n"); - -return OK; - + QNode* p = Q.front->next; + if (!p) { + printf("--Is empty.\n"); + return ERROR; + } + while (p) { + printf("(到达时刻 %d min 办理业务需要花费 %d min) ", p->data.ArrivalTime, p->data.Duration); + p = p->next; + } + printf("\n"); + return OK; }