题目:
排队管理模拟
用程序实现模拟人的排队方式的一个的管理模型。适合于比如买餐,买票,或者是防疫出入校门和公共场所等场景的排队问题。
设计任务要求:
1)可以随时随机输入任意人名,比如Tom, Jerray, Jack, Sam等。有输入的人名,按回车键,则会立刻被程序安排进入排队机排队。并且显示出当前排队剩余多少人。
2)队首排队的人轮候结束需要出队时。当任意时候输入“出队”(或者Dequeue),立刻从队首取出一个人名输出到屏幕上,并且显示出当前还剩余有多少人在排队。
3)队列有容量限制,如果队列满(OVERFLOW),比如最多允许100人等候。则需要提示“当前排队人数已满”或“队列溢出”。
题目的要求我稍微做了修改,没有完全符合题目的逻辑,只实现其中的功能。
下边是代码,可以拿走跑一下。
问题就是插入第一次是可以插到最后的,但是再次插入就会覆盖掉刚才的值。
懵了,求解。。。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<malloc.h>
#define LEN sizeof(struct name) //将LEN定义结构体类型长度
/*
项目设计3:排队管理系统(模拟程序):
*/
typedef struct name{ //声明一个结构体,用来存放排队者的姓名
char username[30]; //排队者姓名类型是字符串,长度30
struct name *next; // *next指针变量指向下一个节点
}Name,*NAME;
int n=0; //正儿八经全局变量,本文件中各个函数均可使用,代表排队的人数
/*初始化排队者(函数)*/
struct name *creat(void){ //这个函数返回一个指向链表头的指针 ,实际上就是返回creat的值,就是链表中第一个节点的起始地址
struct name *head,*p1,*p2; //创建头指针和分别用于开辟和绑定新节点的p1 p2
char check[30];
p1=p2=(struct name * ) malloc(LEN); //开辟新的节点,实际上是开辟一个长度为LEN(自定义结构体)的内存区
printf("请在下方输入排队者的姓名:\n\n");
gets(check);
if(strcmp(check,"ok")!=0){ //如果输入的不是"ok"
strcpy(p1->username,check); //让p1指向新的节点值
head=NULL; //先使头指针值为空,表示链表中没有节点 (节点还没有被纳入链表),纳入链表工作在下边的循环体
while(1){ //开始循环
n+=1; //n的值从0变为 1,象征链表出现第一个节点 ;n的值增加,代表排队的人数
if(n==1){
head=p1; //将p1的值赋给头指针,象征新节点被纳入链表 (这个新节点的值可以是"ok",但是这个节点肯定不会被纳入链表--->)
}
else{ //这个情况是下边出现紧跟排队者情况的处理
p2->next=p1; /*此时的p1是下边的情况,已经指向了第二个节点值,让p1把自己指向的地址给此时还在指向第一个节点的p2的
next成员*/
p2=p1; //再让p2也去指向p1指向的第二个节点,就完成了一二节点的绑定,链表形成了
}
//printf("请在下方输入排队者的姓名:\n\n");
gets(check);
if(strcmp(check,"ok")==0){
break; //如果输入的是"ok"则跳出循环,录入工作完成 --->
}else{
p1=(struct name *)malloc(LEN); //如果还不是ok,开辟第二个的节点
strcpy(p1->username,check); //让p1指向第二个节点值
}
}p2->next=NULL; //<---(承接第34行注释)所以p2就不用指向这个新节点,链表收尾
return(head); //对应第22行代码意义 返回链表中第一个节点的起始地址
}else{
return 0; //如果没有任何的新节点加入,返回空值
}
}
/*打印排队者人数和姓名(函数)*/
void print(struct name *head){ //函数参数为结构体头指针
struct name *p;
if(head!=NULL){ //头指针不为空
p=head; //让指针p跟随头指针找到第一个节点
printf("\n\n\t当前队列人数:%d\n\n",n);
do{
printf("%s\t",p->username); //输出指针指向的节点的值(姓名)
p=p->next; //指针移动 指向下一个节点
}while(p!=NULL);{ //当指针p为空时,就是移动指向了 链表初始化结束最后一个节点后边的那个p1指向的无意义的节点
printf("\n\n\n---------------------\n\n\n");
}
}else printf("\n\t队列空闲无人\n"); //如果头指针是空的,说明根本不存在链表,象征不存在的队列
}
/*队首排队者出队(函数)*/
struct name *del(struct name *head){
struct name *p; //创建p指针
if(head==NULL){
printf("\n\t队列空闲无人\n");
return(head);
}
p=head; //让p指针指向头指针指向的第一个节点
head=head->next; //头指针原本指向的节点里的next指针成员将自己指向的下一个节点的地址告诉自己,然后指他去了
free(p); //第一个节点现在只被p指针指着了,free(p),释放掉他
printf("==此人已被移除队列==\n");
return(head);
}
/*退出模拟系统(函数)*/
//这个函数用来清空链表,并对应主函数switch中的语句结束整个程序
struct name *exit(struct name *head){
struct name *p0; //和上一个队首者出队原理一样
while(head!=NULL){
p0=head;
head=head->next;
free(p0); //这三个语句,头指针去找下一个,p0指针释放原来的节点,释放完了再去跟头指针,最终释放全部的链表节点
}return(head);
}
/*新的排队者加入队列(函数) 就是在链表最后再加入一个节点 */
struct name *add(struct name *head,struct name *insert){ //参数有头指针和用于指向主函数用来接收新节点值的指针
struct name *p0,*p1,*p2; //在基础上新增额外的p0指针用于指引新加入的节点
p0=(struct name *)malloc(LEN); //给p0开辟长度为LEN(就是自定义结构体的长度)的内存区
p1=head; //头指针传值给p1指针,让p1指向头节点
p0=insert; //p0指向主函数里键入的新节点的值
if(head==NULL){ //如果头指针为空,说明链表为空,不存在
head=p0; //p0指向的新节点赋给头指针
p0->next=NULL; //让p0指针指向的节点的next成员的值为空,不在链入新的节点,链表收尾
}else{ //头指针不为空的话,说明链表存在
while(p1->next!=NULL){
p2=p1;
p1=p1->next;
}
p1->next=p0;
p0->next=NULL;
}
n+=1;
return (head);
}
/*主函数*/
int main(void){
struct name *head=NULL,message;
char a[10];
head=creat();
printf("\n\n");
while(1){
printf("\n\n\n\n");
printf("================================\n\n");
printf(" 录入新的排队者-------------- 1 \n");
printf(" 查看队列人数和信息---------- 2 \n");
printf(" 队首者出队------------------ 3 \n");
printf(" 退出------------------------ 4 \n\n");
printf("================================\n");
printf(" 请输入一个序号来进行以上操作:");
gets(a);
switch(*a){
case '1':{
printf("要进入的人:");
gets(message.username);
//scanf("%s",&message.username);
head=add(head,&message);
break;
}
case '2':{
print(head);
break;
}
case '3':{
head=del(head);
n=n-1; //出队一个,排队中人数-1
break;
}
case '4':{
head=exit(head);
break;
}
default: printf("参数错误!请重新选择功能");break;
}if(strcmp(a,"4")==0) break;
}
}