<think>我们参考引用[1]中的医院排队看病模拟系统的功能描述,并结合C语言实现栈和队列的基本操作以及病人信息管理。主要功能包括:1.病人信息录入(病历号唯一性检查)2.病人进入诊室(栈结构,先进后出)和候诊室(队列结构,先进先出)的管理3.病人看完病离开诊室的处理(需要让后续病人先退出,待离开后再按原次序进入,并从候诊室补入一个病人)4.查询功能:查询诊室和候诊室的病人5.排序功能:按姓名排序显示诊室和候诊室的病人我们将使用以下数据结构:-病人信息用结构体表示-诊室(栈)使用顺序栈实现(固定大小)-候诊室(队列)使用循环队列实现(固定大小)注意:由于诊室是栈,当需要让一个病人(比如最早进入的病人,即栈底病人)离开时,需要将栈中该病人之上的所有病人弹出并暂存(比如存到另一个栈),然后弹出目标病人,再将暂存的病人按原顺序压回诊室。同时,从候诊室(队列)中取出一个病人(如果有)压入诊室。接下来,我们分步骤实现:1.定义病人结构体:```ctypedefstruct{charmedical_record[20];//病历号charname[50];chargender;//'M'或'F'intage;}Patient;```2.定义栈(诊室):```c#defineMAX_ROOM_SIZE3typedefstruct{Patientpatients[MAX_ROOM_SIZE];inttop;//栈顶指针}Stack;```3.定义队列(候诊室):```c#defineMAX_WAITING_SIZE4typedefstruct{Patientpatients[MAX_WAITING_SIZE];intfront;//队头intrear;//队尾intcount;//队列中元素个数}Queue;```4.实现栈的基本操作(初始化、入栈、出栈、判断栈空/满等):```cvoidinitStack(Stack*s){s->top=-1;}intisStackFull(Stack*s){returns->top==MAX_ROOM_SIZE-1;}intisStackEmpty(Stack*s){returns->top==-1;}voidpush(Stack*s,Patientp){if(isStackFull(s)){printf("诊室已满,无法进入\n");return;}s->patients[++(s->top)]=p;}Patientpop(Stack*s){if(isStackEmpty(s)){printf("诊室已空\n");//返回一个空病人,实际应用中应避免空栈出栈Patientempty={"","",'',0};returnempty;}returns->patients[(s->top)--];}//查看栈顶元素Patienttop(Stack*s){if(isStackEmpty(s)){Patientempty={"","",'',0};returnempty;}returns->patients[s->top];}```5.实现队列的基本操作(初始化、入队、出队、判断队空/满等):```cvoidinitQueue(Queue*q){q->front=0;q->rear=0;q->count=0;}intisQueueFull(Queue*q){returnq->count==MAX_WAITING_SIZE;}intisQueueEmpty(Queue*q){returnq->count==0;}voidenqueue(Queue*q,Patientp){if(isQueueFull(q)){printf("候诊室已满,无法加入\n");return;}q->patients[q->rear]=p;q->rear=(q->rear+1)%MAX_WAITING_SIZE;q->count++;}Patientdequeue(Queue*q){if(isQueueEmpty(q)){printf("候诊室为空\n");Patientempty={"","",'',0};returnempty;}Patientp=q->patients[q->front];q->front=(q->front+1)%MAX_WAITING_SIZE;q->count--;returnp;}//查看队首元素Patientfront(Queue*q){if(isQueueEmpty(q)){Patientempty={"","",'',0};returnempty;}returnq->patients[q->front];}```6.病人信息录入:我们需要一个函数来录入病人信息,并检查病历号的唯一性。这里我们假设病人信息在录入时不会重复(实际系统可能需要在全局检查,但为简化,我们仅在录入时提醒用户检查,因为模拟系统并不存储所有病人)。注意:引用中要求病历号不能重复,因此我们需要检查即将入栈或入队的病人病历号是否已在诊室或候诊室中。我们可以写一个函数来检查给定的病历号是否在栈或队列中。7.检查病历号唯一性的函数(检查栈和队列):```c//检查栈中是否有该病历号的病人intisMedicalRecordInStack(Stack*s,char*medical_record){for(inti=0;i<=s->top;i++){if(strcmp(s->patients[i].medical_record,medical_record)==0){return1;//存在}}return0;//不存在}//检查队列中是否有该病历号的病人intisMedicalRecordInQueue(Queue*q,char*medical_record){if(isQueueEmpty(q))return0;intindex=q->front;for(inti=0;i< q->count;i++){if(strcmp(q->patients[index].medical_record,medical_record)==0){return1;}index=(index+1)%MAX_WAITING_SIZE;}return0;}```在添加病人时,我们可以用这两个函数检查病历号是否重复。8.病人到达并进入诊室或候诊室:规则:若诊室未满,则进入诊室(压入栈)。若诊室满而候诊室未满,则进入候诊室(入队)。否则,提示位置已满,无法接收。9.病人离开诊室(假设离开的是最先进入的病人,即栈底病人):步骤:a.如果诊室为空,则无法离开。b.创建一个临时栈,将原诊室栈中的病人从栈顶到目标病人(栈底)前的所有病人弹出并压入临时栈(也就是将原栈倒序)。c.弹出目标病人(此时它在原栈的栈底,经过出栈后,原栈变为空或只剩下目标病人之下的病人?不对,我们要取的是栈底病人,所以需要将原栈中位于目标病人之上的所有病人弹出并压入临时栈,然后弹出目标病人)。d.然后将临时栈中的病人再依次压回原诊室栈(这样顺序就恢复了)。e.然后检查候诊室,如果候诊室有病人,则出队一个病人并压入诊室。注意:我们这里假设离开的总是最先进入的病人(即栈底病人)。在实际模拟中,可能需要指定离开的病人(比如通过病历号),但引用中描述为“比如是先进来的病人”,所以我们按栈底处理。但是,我们的栈只能从栈顶操作,所以我们需要弹出栈顶的每一个病人直到遇到栈底(即第0个位置)。我们可以通过将整个栈倒置两次(即用两个栈)来实现:具体步骤:1)创建一个临时栈temp1,将原栈(假设为room)中的元素弹出并压入temp1,这样temp1的栈顶就是原栈的栈底(也就是最先进入的病人)。2)弹出temp1的栈顶(即最先进入的病人)——这就是要离开的病人。3)然后,将temp1中剩下的病人再弹出并压入另一个临时栈temp2(这样,这些病人的顺序就变成了原顺序,因为从temp1弹出时是倒序,而压入temp2后,再从temp2弹出并压回原栈,就又倒了一次,变成正序)。4)最后,将temp2中的病人全部弹出并压回原栈(room)。但是,这样操作后,原栈中病人顺序(从栈底到栈顶)就是原顺序去掉最底下的那个病人。然后,从候诊室取一个病人压入原栈。但是,注意:这样操作会导致原栈中除了离开的病人外,其他病人的相对位置不变(因为我们是按照离开前从栈顶到栈底的顺序压入了temp1,然后离开病人后,我们又把剩下的病人按照同样的顺序(但反向两次)放回去)。实际上,去掉离开的病人后,剩下的病人顺序不变(从栈底到栈顶的顺序),然后我们再把候诊室的第一个病人压入栈顶。然而,上述方法需要两个临时栈,并且需要频繁出栈入栈。另一种方法是直接使用数组来操作,但题目要求模拟栈结构,所以我们还是用栈操作。实现离开栈底病人的函数:```cvoidleaveRoom(Stack*room,Queue*waiting){if(isStackEmpty(room)){printf("诊室为空,没有病人\n");return;}Stacktemp1,temp2;initStack(&temp1);initStack(&temp2);//将room栈中的病人弹出并压入temp1,直到room为空(此时temp1的栈顶是room原来的栈底)while(!isStackEmpty(room)){push(&temp1,pop(room));}//要离开的病人就是temp1的栈顶(原room的栈底)Patientleaving=pop(&temp1);printf("病人%s(%s)离开诊室\n",leaving.name,leaving.medical_record);//将temp1中剩下的病人(也就是原room的栈底之上的病人,现在在temp1中从栈顶到栈底是原room的从栈底向上数第二个到栈顶)弹出并压入temp2,这样temp2的栈顶是原room的栈顶,栈底是原room栈底之上的第二个(即中间部分)while(!isStackEmpty(&temp1)){push(&temp2,pop(&temp1));}//将temp2中的病人再压回room(此时,room中栈底是原room的第二个病人(即离开病人之后进入的),栈顶是原room的栈顶)while(!isStackEmpty(&temp2)){push(room,pop(&temp2));}//此时,诊室room中已经移除了离开的病人,其他病人顺序不变(从栈底到栈顶为:原次栈底到栈顶)//然后检查候诊室,如果有病人,则入诊室if(!isQueueEmpty(waiting)){Patientp=dequeue(waiting);push(room,p);printf("病人%s(%s)从候诊室进入诊室\n",p.name,p.medical_record);}}```但是,这种方法会导致离开一个病人后,诊室中病人的顺序发生变化(不再是原来的顺序)?实际上,我们模拟的诊室是栈结构,原本栈内顺序是:后进入的在栈顶,先进入的在栈底。我们移除了栈底的病人后,原本在栈底之上的病人变成了新的栈底。当我们将这些病人重新压回room时,我们先用temp1倒置了,然后temp1再倒置到temp2,最后从temp2压回room。这样,这些病人在room中的顺序就变成了:从栈底到栈顶,是原栈从栈底向上第二个病人(即原次栈底)到栈顶?不对,我们重新分析:假设原room栈(从栈底到栈顶)为:A,B,C(A最早进入,C最后进入)。我们执行:1.room弹出C,压入temp1->temp1:C2.room弹出B,压入temp1->temp1:B,C(栈顶B)3.room弹出A,压入temp1->temp1:A,B,C(栈顶A)然后弹出temp1栈顶(A)作为离开的病人,剩下的temp1为:B,C(栈顶B)。然后我们将temp1弹栈压入temp2:弹出B压入temp2,弹出C压入temp2,所以temp2为:C,B(栈顶C)。然后再将temp2弹栈压入room:先弹出C压入room,再弹出B压入room。所以room变成了:B(栈底)和C(栈顶)。而原本的顺序是A(栈底),B(中间),C(栈顶)。移除A后,顺序应该是B(最早)和C(后进入),而实际room中B在栈底,C在栈顶,这符合要求吗?从进入时间来看,B比C早,所以B应该成为栈底,C在栈顶。所以顺序正确。10.查询功能:-查询诊室(栈)中的所有病人:我们需要从栈底到栈顶显示(即按进入时间从早到晚)。由于栈只能从栈顶访问,我们可以通过另一个临时栈将原栈倒置,然后显示,再倒回来。或者,为了不破坏栈结构,我们可以按索引遍历,但顺序栈我们可以直接遍历数组(但注意栈可能不是满的,所以从0到room->top,但这样是后进先出)。我们需要按进入时间从早到晚(即栈底到栈顶)的顺序显示,那就需要先显示栈底的元素,再显示栈顶。然而,顺序栈中,数组下标0为栈底,下标room->top为栈顶。所以我们可以直接遍历:for(inti=0;i<=room->top;i++){//显示room->patients[i]}注意:这样显示顺序是从栈底到栈顶(也就是按进入顺序从早到晚)。-查询候诊室(队列)中的病人:按队列顺序显示(从队首到队尾)。由于队列是循环队列,所以我们需要从front开始,计数count个元素。11.排序功能:按姓名排序我们需要将诊室和候诊室的所有病人读到一个数组中,然后进行排序(比如使用快速排序或qsort)。注意,要合并两个数据结构的病人。具体步骤:a.创建一个足够大的数组(诊室最多MAX_ROOM_SIZE,候诊室最多MAX_WAITING_SIZE)。b.将栈中的病人按顺序复制到数组(使用数组索引即可)。c.将队列中的病人复制到数组(按队列顺序)。d.使用标准库的qsort对数组进行排序。但是,栈和队列中的病人信息不能移除,所以只是读取。12.主函数:实现用户交互菜单。由于篇幅限制,这里只给出关键函数和结构定义,主菜单循环和交互可以根据需要实现。下面给出完整代码框架(不包括完整的主函数,但包含所有数据结构定义和关键函数):</think>
### C语言实现医院排队看病模拟系统
下面是一个完整的医院排队看病模拟系统实现方案,包含栈和队列的基本操作、病人信息管理、查询及排序功能。系统遵循诊室(栈结构)和候诊室(队列结构)的管理规则。
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_MEDICAL_RECORD 20 // 最大病历号长度
#define MAX_NAME 50 // 最大姓名长度
#define ROOM_CAPACITY 3 // 诊室容量
#define WAITING_CAPACITY 4 // 候诊室容量
// 病人信息结构
typedef struct {
char medical_record[MAX_MEDICAL_RECORD]; // 病历号
char name[MAX_NAME]; // 姓名
char gender; // 性别:M/F
int age; // 年龄
} Patient;
// 诊室栈结构
typedef struct {
Patient patients[ROOM_CAPACITY]; // 病人数组
int top; // 栈顶指针
} RoomStack;
// 候诊室队列结构
typedef struct {
Patient patients[WAITING_CAPACITY]; // 病人数组
int front; // 队头指针
int rear; // 队尾指针
int count; // 队列中病人计数
} WaitingQueue;
// 初始化诊室栈
void initRoomStack(RoomStack *room) {
room->top = -1;
}
// 初始化候诊室队列
void initWaitingQueue(WaitingQueue *queue) {
queue->front = 0;
queue->rear = -1;
queue->count = 0;
}
// 检查病历号是否重复
bool isRecordUnique(WaitingQueue *queue, RoomStack *room, char *record) {
// 检查诊室
for (int i = 0; i <= room->top; i++) {
if (strcmp(room->patients[i].medical_record, record) == 0) {
return false;
}
}
// 检查候诊室
if (queue->count > 0) {
int current = queue->front;
for (int i = 0; i < queue->count; i++) {
if (strcmp(queue->patients[current].medical_record, record) == 0) {
return false;
}
current = (current + 1) % WAITING_CAPACITY;
}
}
return true;
}
// 录入病人信息
Patient inputPatient(WaitingQueue *queue, RoomStack *room) {
Patient newPatient;
printf("\n--- 录入新病人 ---\n");
// 输入病历号(带冲突检查)
bool isUnique;
do {
printf("输入病历号: ");
scanf("%s", newPatient.medical_record);
isUnique = isRecordUnique(queue, room, newPatient.medical_record);
if (!isUnique) {
printf("病历号重复! 请重新输入\n");
}
} while (!isUnique);
printf("输入姓名: ");
scanf("%s", newPatient.name);
printf("输入性别(M/F): ");
scanf(" %c", &newPatient.gender);
printf("输入年龄: ");
scanf("%d", &newPatient.age);
return newPatient;
}
// 病人加入系统
void addPatient(WaitingQueue *queue, RoomStack *room, Patient patient) {
// 诊室未满,直接进入诊室
if (room->top < ROOM_CAPACITY - 1) {
room->top++;
room->patients[room->top] = patient;
printf("\n%s 进入诊室(栈位置:%d)\n", patient.name, room->top);
}
// 候诊室未满,进入候诊室排队
else if (queue->count < WAITING_CAPACITY) {
queue->rear = (queue->rear + 1) % WAITING_CAPACITY;
queue->patients[queue->rear] = patient;
queue->count++;
printf("\n%s 进入候诊室(等待位置:%d)\n", patient.name, queue->count);
}
// 两个房间都满
else {
printf("\n系统已满! %s 无法加入,请稍后再来\n", patient.name);
}
}
// 病人离开诊室
void leaveRoom(WaitingQueue *queue, RoomStack *room) {
if (room->top == -1) {
printf("\n诊室为空,没有病人可离开\n");
return;
}
// 创建临时诊室
RoomStack tempRoom;
initRoomStack(&tempRoom);
// 移出目标病人(栈底病人)
Patient leavingPatient = room->patients[0];
// 将其他病人临时转移到临时诊室(遵循栈规则)
while (room->top > 0) {
tempRoom.top++;
tempRoom.patients[tempRoom.top] = room->patients[room->top];
room->top--;
}
// 清空主诊室
room->top = -1;
// 将病人从临时诊室移回主诊室
while (tempRoom.top > -1) {
room->top++;
room->patients[room->top] = tempRoom.patients[tempRoom.top];
tempRoom.top--;
}
printf("\n%s 已离开诊室\n", leavingPatient.name);
// 候诊室有病人则补入诊室
if (queue->count > 0) {
Patient nextPatient = queue->patients[queue->front];
queue->front = (queue->front + 1) % WAITING_CAPACITY;
queue->count--;
room->top++;
room->patients[room->top] = nextPatient;
printf("%s 从候诊室进入诊室\n", nextPatient.name);
}
}
// 查询诊室状态
void queryRoomStatus(RoomStack *room) {
printf("\n--- 诊室状态 ---\n");
if (room->top == -1) {
printf("诊室为空\n");
return;
}
for (int i = 0; i <= room->top; i++) {
printf("[栈位%d] %s(%s, %c, %d岁)\n",
i, room->patients[i].name,
room->patients[i].medical_record,
room->patients[i].gender,
room->patients[i].age);
}
}
// 查询候诊室状态
void queryWaitingStatus(WaitingQueue *queue) {
printf("\n--- 候诊室状态 ---\n");
if (queue->count == 0) {
printf("候诊室为空\n");
return;
}
int pos = 1;
int index = queue->front;
for (int i = 0; i < queue->count; i++) {
Patient p = queue->patients[index];
printf("[等待位%d] %s(%s, %c, %d岁)\n",
pos++, p.name, p.medical_record,
p.gender, p.age);
index = (index + 1) % WAITING_CAPACITY;
}
}
// 查询病人位置
void queryPatientLocation(WaitingQueue *queue, RoomStack *room, char *medical_record) {
// 检查诊室
for (int i = 0; i <= room->top; i++) {
if (strcmp(room->patients[i].medical_record, medical_record) == 0) {
printf("\n病人 %s(病历号%s) 在诊室(栈位%d)\n",
room->patients[i].name, medical_record, i);
return;
}
}
// 检查候诊室
if (queue->count > 0) {
int index = queue->front;
for (int i = 0; i < queue->count; i++) {
if (strcmp(queue->patients[index].medical_record, medical_record) == 0) {
printf("\n病人 %s(病历号%s) 在候诊室(等待位%d)\n",
queue->patients[index].name, medical_record, i + 1);
return;
}
index = (index + 1) % WAITING_CAPACITY;
}
}
printf("\n未找到病历号为 %s 的病人\n", medical_record);
}
// 排序函数(按姓名)
int compareByName(const void *a, const void *b) {
Patient *pa = (Patient *)a;
Patient *pb = (Patient *)b;
return strcmp(pa->name, pb->name);
}
// 获取并显示所有病人(按姓名排序)
void displayAllSorted(WaitingQueue *queue, RoomStack *room) {
int totalCount = (room->top + 1) + queue->count;
if (totalCount == 0) {
printf("\n系统中暂无病人\n");
return;
}
// 创建合并列表
Patient allPatients[ROOM_CAPACITY + WAITING_CAPACITY];
int index = 0;
// 添加诊室病人
for (int i = 0; i <= room->top; i++) {
allPatients[index++] = room->patients[i];
}
// 添加候诊室病人
if (queue->count > 0) {
int pos = queue->front;
for (int i = 0; i < queue->count; i++) {
allPatients[index++] = queue->patients[pos];
pos = (pos + 1) % WAITING_CAPACITY;
}
}
// 按姓名排序
qsort(allPatients, totalCount, sizeof(Patient), compareByName);
printf("\n--- 所有病人(按姓名排序) ---\n");
for (int i = 0; i < totalCount; i++) {
printf("%s(%s, %c, %d岁)\n",
allPatients[i].name, allPatients[i].medical_record,
allPatients[i].gender, allPatients[i].age);
}
}
// 显示菜单
void displayMenu() {
printf("\n==== 医院排队看病模拟系统 ====\n");
printf("1. 录入新病人\n");
printf("2. 病人离开诊室\n");
printf("3. 查看诊室状态\n");
printf("4. 查看候诊室状态\n");
printf("5. 查询病人位置\n");
printf("6. 查看所有病人(按姓名排序)\n");
printf("0. 退出系统\n");
printf("请选择操作: ");
}
int main() {
RoomStack consultationRoom;
WaitingQueue waitingRoom;
initRoomStack(&consultationRoom);
initWaitingQueue(&waitingRoom);
int choice;
do {
displayMenu();
scanf("%d", &choice);
char medical_record[MAX_MEDICAL_RECORD];
switch (choice) {
case 1: {
Patient p = inputPatient(&waitingRoom, &consultationRoom);
addPatient(&waitingRoom, &consultationRoom, p);
break;
}
case 2:
leaveRoom(&waitingRoom, &consultationRoom);
break;
case 3:
queryRoomStatus(&consultationRoom);
break;
case 4:
queryWaitingStatus(&waitingRoom);
break;
case 5:
printf("输入要查询的病历号: ");
scanf("%s", medical_record);
queryPatientLocation(&waitingRoom, &consultationRoom, medical_record);
break;
case 6:
displayAllSorted(&waitingRoom, &consultationRoom);
break;
case 0:
printf("系统已退出\n");
break;
default:
printf("无效选择,请重新输入\n");
}
} while (choice != 0);
return 0;
}
```
### 关键功能说明
1. **病人信息录入**
- 使用`Patient`结构体管理病人信息
- 病历号唯一性检查`isRecordUnique()`确保无重复
- 输入验证确保数据有效性
2. **诊室管理(栈结构)**
- `RoomStack`实现诊室的栈操作
- 压栈操作处理病人进入诊室
- 特殊的出栈操作满足系统要求:首位病人离开时,其他病人需通过临时栈转移
- 诊室容量限制:$ROOM\_CAPACITY = 3$
3. **候诊室管理(队列结构)**
- `WaitingQueue`实现循环队列
- `enqueue`操作处理病人排队
- 当诊室有空位时自动补充候诊室首位病人
- 候诊室容量限制:$WAITING\_CAPACITY = 4$
4. **查询功能**
- 诊室状态查询:显示所有就诊病人
- 候诊室状态查询:显示排队顺序
- 病人定位:按病历号查位置
5. **排序功能**
- 使用快速排序`qsort()`
- 支持按姓名字母顺序排序
- 整合诊室和候诊室所有病人统一排序
### 使用示例
1. 编译运行程序:`gcc hospital_system.c -o hospital_system && ./hospital_system`
2. 按菜单提示操作:
- 录入病人:输入病历号(自动检查重复)、姓名、性别和年龄
- 当诊室满员时,新病人自动进入候诊室排队
- 首位病人离开诊室时,后续病人临时转移再复位
- 使用查询功能监控系统状态
- 按姓名排序查看所有病人
此实现严格遵循引用[^1]中描述的医院排队规则,完整实现了栈和队列的数据结构操作,以及病人信息管理系统。
[^1]: 引用来源:《医院排队看病模拟系统功能描述》