舞伴问题(数据结构队列,c语言版)

一、实验题目

假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题。

1.案例分析

对千舞伴配对问题,先入队的男士或女士先出队配成舞伴,因此设置两个队列分别存放男士和女士入队者。假设男士和女士的记录存放在一个数组中作为输入,然后依次扫描该数组的各元素,并根据性别来决定是进入男队还是女队。 当这两个队列构造完成之后,依次将两队当前的队头元素出队来配成舞伴,直至某队列变空为止。 此时,若某队仍有等待配对者,则输出此队列中排在队头的等待者的姓名,此人将是下一轮舞曲开始时第一个可获得舞伴的人。

2.案例实现

算法中有关数据结构的定义如下:

//----- 跳舞者个人信息--- -
typedef struct {
char name [20]; //姓名
char sex; //性别,'F'表示女性,'M'表示男性
}Person; 
// ----- 队列的顺序存储结构--- - -
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef struct { 
Person *base; //队列中数据元素类型为Person
int front; //头指针
int rear;  //尾指针
} SqQueue; 
SqQueue Mdancers,Fdancers; 

3.算法步骤

1.初始化 Mdancers 队列和 Fdancers 队列。
2.反复循环,依次将跳舞者根据其性别插入 Mdancers 队列或 Fdancers 队列。
3.当 Mdancers 队列和 Fdancers 队列均为非空时, 反复循环, 依次输出男女舞伴的姓名。
4.如果 Mdancers 队列为空而 Fdancers 队列非空, 则输出 Fdancers 队列的队头女士的姓名。
5.如果 Fdancers 队列为空而 Mdancers 队列非空, 则输出 Mdancers 队列的队头男士的姓名。

4.算法描述

void DancePartner(Person dancer[],int num)//结构数组dancer中存放跳舞的男女,num是跳舞的人数。
	InitQueue(Mdancers); //男士队列初始化
	InitQueue(Fdancers); //女士队列初始化
	for(i=0;i<num;i++) //依次将跳舞者根据其性别人队
	{
		p=dancer[i]; 
		if (p.sex=='F') EnQueue(Fdancers, p); / /插入女队
		else EnQueue(Mdancers,p); //插人男队
	}
	cout<<"The dancing partners are:\n"; 
	while(!QueueEmpty(Fdancers)&&!QueueEmpty(Mdancers))//依次输出男女舞伴的姓名
		DeQueue(Fdancers,p); //女士出队
		cout<<p. name<<" "; //输出出队女士姓名
		DeQueue(Mdancers,p); //男士出队
		cout<<p.name<<endl; //输出出队男士姓名
	}
	if (! QueueEmpty (Fdancers)) //女士队列非空,输出队头女士的姓名
	{
		p=GetHead(Fdancers); //取女士队头
		cout<<"The first woman to get a partner is: "<< p.name<<endl; 
	}
	else if (!QueueEmpty (Mdancers)) //男士队列非空,输出队头男士的姓名
	{
		p=GetHead(Mdancers); //取男士队头
		cout<<"The first man to get a partner is: "<< p.name<<endl; 
	}
}

二、工具环境

Window10操作系统,Microsoft Visual C++2010学习版 集成开发环境,C语言

三、实验代码

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

#define MAXSIZE 100    //队列可能达到的最大长度
#define OK  1
#define ERROR  0
#define OVERFLOW -2

typedef int  Status;

typedef struct{
	char name [20]; //姓名
	char sex; //性别,'F'表示女性,'M'表示男性
}Person; 

typedef struct{ 
	Person *base; //队列中数据元素类型为Person
	int front; //头指针
	int rear;  //尾指针
}SqQueue; 

Status InitQueue (SqQueue *Q);//构造一个空队列Q
Status EnQueue(SqQueue *Q, Person e);//插入元素e为Q的新的队尾元素
Status DeQueue(SqQueue *Q, Person *e);//删除Q的队头元素,用e返回其值
Person GetHead(SqQueue Q);//返回Q的队头元素,不修改队头指针
Status QueueEmpty(SqQueue Q);//判断队列是否为空,空则返回1
void DancePartner(Person dancer[],int num);//舞伴问题匹配算法

int main()
{
	Person dancer[MAXSIZE];int i,num;
	printf("请输入跳舞总人数:");
	scanf("%d",&num);
	printf("请输入各个跳舞人的姓名和性别('F'表示女性,'M'表示男性):\n");
	for(i=0;i<num;i++)
	{
		printf("请输入第%d个跳舞人的姓名和性别(用空格隔开):",i+1);
		scanf("%s %c",&dancer[i].name,&dancer[i].sex);
	}
	DancePartner(dancer,num);
	return 0;
}

Status InitQueue (SqQueue *Q) 
{//构造一个空队列Q
	Q->base=(Person *)malloc(MAXSIZE*sizeof(Person));//为队列分配一个最大容量为MAXSIZE的数组空间
	if(!Q->base) exit(OVERFLOW);//存储分配失败
	Q->front=Q->rear=0;//头指针和尾指针置为零、队列为空
	return OK;
}

Status EnQueue(SqQueue *Q, Person e) 
{//插入元素e为Q的新的队尾元素
	if ((Q->rear+1)%MAXSIZE==Q->front)//尾指针在循环意义上加1后等于头指针,表明队满
	return ERROR; 
	Q->base[Q->rear]=e;//新元素插入队尾
	Q->rear=(Q->rear+1)%MAXSIZE;//队尾指针加1
	return OK; 
}

Status DeQueue(SqQueue *Q, Person *e) 
{//删除Q的队头元素,用e返回其值
	if(Q->front==Q->rear) return ERROR; //队空
	*e=Q->base[Q->front]; //保存队头元素
	Q->front=(Q->front+1)%MAXSIZE; //队头指针加1
	return OK;
}

Person GetHead(SqQueue Q) 
{//返回Q的队头元素,不修改队头指针
	if(Q.front!=Q.rear) //队列非空
	return Q.base[Q.front]; //返回队头元素的值,队头指针不变
}

Status QueueEmpty(SqQueue Q)
{//判断队列是否为空
	if(Q.front==Q.rear) return OK;//队列空,返回1
	else return ERROR;//队列不空,返回0
}

void DancePartner(Person dancer[],int num) 
{//结构数组dancer中存放跳舞的男女,num是跳舞的人数。
	SqQueue Mdancers,Fdancers;
	Person p;
	int i;
	InitQueue(&Mdancers); //男士队列初始化
	InitQueue(&Fdancers); //女士队列初始化
	for(i=0;i<num;i++) //依次将跳舞者根据其性别人队
	{
		p=dancer[i]; 
		if (p.sex=='F') EnQueue(&Fdancers,p); //插入女队
		else EnQueue(&Mdancers,p); //插人男队
	}
	printf("The dancing partners are:\n"); 
	while(!QueueEmpty(Fdancers)&&!QueueEmpty(Mdancers)) 
	{//依次输出男女舞伴的姓名
		DeQueue(&Fdancers,&p); //女士出队
		printf("%s ",p.name);; //输出出队女士姓名
		DeQueue(&Mdancers,&p); //男士出队
		printf("%s\n",p.name); //输出出队男士姓名
	}
	if (!QueueEmpty(Fdancers)) //女士队列非空,输出队头女士的姓名
	{
		p=GetHead(Fdancers); //取女士队头
		printf("The first woman to get a partner is: %s\n", p.name);
	}
	else if (!QueueEmpty (Mdancers)) //男士队列非空,输出队头男士的姓名
	{
		p=GetHead(Mdancers); //取男士队头
		printf("The first man to get a partner is: %s\n", p.name); 
	}
}

四、实验总结

栈和队列的比较
栈(stack)和队列(queue)是操作受到限制的线性表:
1.栈是限定仅在表尾进行插入或删除操作的线性表。 因此,对栈来说,表尾端有其特殊含义, 称为栈顶 (top), 相应地, 表头端称为栈底 (bottom)。不含元素的空表称为空栈。栈的修改是按后进先出的原则进行的,因此,栈又称为后进先出 (Last In First Out, LIFO) 的线性表。
2.队列和栈相反,队列是一种先进先出 (First In First Out, FIFO)的线性表。它只允许在表的一端进行插入,而在另一端删除元素。


舞伴问题,又称为约瑟夫环问题,是一道经典的问题。在舞会上,男女同学各自排成一列,男生和女生两列人数可能不同。在舞会上,男生和女生要轮流跳舞,每次一个男生和一个女生跳舞,假设男生先发出邀请,女生随后决定是否接受邀请。当一男一女配成一对跳舞时,他们就离开队列去跳舞。当跳完之后,男生重新排队等待下一轮的邀请,女生则仍留在原地等待邀请。如此往复进行,直到所有男生和女生都跳过舞为止。 在这个问题中,我们需要设计一种数据结构来解决舞伴问题。一种简单的实现方式是使用循环链表。我们可以将男生和女生分别存储在两个循环链表中,每次找到男生链表中的第一个男生,然后向女生链表中寻找第一个未匹配的女生。如果找到了,则将这对男女从各自的链表中删除,并将他们加入到一个新的链表中。如果没有找到未匹配的女生,则将这个男生移到男生链表的末尾。 以下是使用C语言实现舞伴问题数据结构的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义节点结构体 typedef struct Node { int value; struct Node *next; } Node; // 定义链表结构体 typedef struct List { Node *head; Node *tail; int size; } List; // 初始化链表 void initList(List *list) { list->head = NULL; list->tail = NULL; list->size = 0; } // 添加节点 void addNode(List *list, int value) { Node *node = (Node*)malloc(sizeof(Node)); node->value = value; node->next = NULL; if (list->head == NULL) { list->head = node; list->tail = node; } else { list->tail->next = node; list->tail = node; } list->size++; } // 删除节点 void removeNode(List *list, Node *node) { if (node == list->head) { list->head = node->next; } else { Node *prev = list->head; while (prev->next != node) { prev = prev->next; } prev->next = node->next; } if (node == list->tail) { list->tail = prev; } free(node); list->size--; } // 舞伴问题求解 void solveDancingProblem(int m, int n) { List maleList, femaleList, matchList; initList(&maleList); initList(&femaleList); initList(&matchList); // 初始化男女链表 for (int i = 1; i <= m; i++) { addNode(&maleList, i); } for (int i = 1; i <= n; i++) { addNode(&femaleList, i); } // 模拟舞伴匹配过程 while (maleList.size > 0 && femaleList.size > 0) { Node *maleNode = maleList.head; Node *femaleNode = femaleList.head; // 找到第一个未匹配的女生 while (femaleNode != NULL && femaleNode->value % maleNode->value != 0) { femaleNode = femaleNode->next; } if (femaleNode != NULL) { // 匹配成功,将这对男女加入到matchList中 addNode(&matchList, maleNode->value); addNode(&matchList, femaleNode->value); // 从maleList和femaleList中删除已匹配的节点 removeNode(&maleList, maleNode); removeNode(&femaleList, femaleNode); } else { // 将第一个男生移到maleList末尾 removeNode(&maleList, maleNode); addNode(&maleList, maleNode->value); } } // 输出匹配结果 printf("Matched pairs: "); Node *node = matchList.head; while (node != NULL) { printf("(%d,%d) ", node->value, node->next->value); node = node->next->next; } } int main() { solveDancingProblem(5, 7); return 0; } ```
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值