循环队列(顺序)的实现:舞伴问题
一、问题引入#
舞伴配对问题:
假设在周末舞会上, 男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题
先入队的男士或女士应先出队配成舞伴, 因此该问题具有典型的先进先出特性,可用队列作为算法的数据结构
二、解决过程#
-
由用户输入舞者人数以及舞者的姓名和性别,男性舞者到男队排队,女性舞者到女队排队。
-
男队和女队分别出一个舞者进行配对,直到男队或女队为空才结束配对
-
输出男队和女队剩余人数
2-1 队列定义#
#define MAX_Q_SIZE 100 // 队列空间最大长度
#define ERROR -1
#define OK 0
#define OVERFLOW 1
typedef struct
{
char name[10];
char sex;
}Person_T;
typedef Person_T QElemType;
typedef struct
{
QElemType *base; // 存储空间的基地址
int front; // 头指针
int rear; // 尾指针
}SqQueue_T;
2-2 队列操作#
- 队列初始化
int queue_init(SqQueue_T *sq_queue_pt)
{
sq_queue_pt->base = (QElemType *)malloc(MAX_Q_SIZE * sizeof(QElemType));
if (NULL == sq_queue_pt->base)
exit(OVERFLOW);
memset(sq_queue_pt->base, 0, MAX_Q_SIZE * sizeof(QElemType));
sq_queue_pt->front = 0;
sq_queue_pt->rear = 0;
return OK;
}
- 队列销毁
int queue_destory(SqQueue_T *sq_queue_pt)
{
if (NULL != sq_queue_pt->base)
free(sq_queue_pt->base);
sq_queue_pt->base = NULL;
sq_queue_pt->front = 0;
sq_queue_pt->rear = 0;
return OK;
}
- 求队列长度
int queue_length(SqQueue_T *sq_queue_pt)
{
return (sq_queue_pt->rear - sq_queue_pt->front + MAX_Q_SIZE) % MAX_Q_SIZE;
}
- 入队
int queue_push(SqQueue_T *sq_queue_pt, QElemType elem)
{
// 判断是否队满(循环队列),若队列为满,则报错
if ((sq_queue_pt->rear + 1) % MAX_Q_SIZE == sq_queue_pt->front)
return ERROR;
sq_queue_pt->base[sq_queue_pt->rear] = elem;
sq_queue_pt->rear = (sq_queue_pt->rear + 1) % MAX_Q_SIZE;
return OK;
}
- 出队
int queue_pop(SqQueue_T *sq_queue_pt, QElemType *elem)
{
// 判断是否对空,若队列为空,则报错
if (sq_queue_pt->front == sq_queue_pt->rear)
return ERROR;
*elem = sq_queue_pt->base[sq_queue_pt->front];
sq_queue_pt->front = (sq_queue_pt->front + 1) % MAX_Q_SIZE;
return OK;
}
- 取队头元素
QElemType * queue_head_elem_get(SqQueue_T *sq_queue_pt)
{
//若队列为空,则返回空指针NULL
QElemType *p_elem;
if (sq_queue_pt->front == sq_queue_pt->rear)
p_elem = NULL;
else
p_elem = &sq_queue_pt->base[sq_queue_pt->front];
return p_elem;
}
- 判断队列是否为空
int queue_empty(SqQueue_T *sq_queue_pt)
{
// 若队列为空,则返回值为非0值
return !((sq_queue_pt->rear - sq_queue_pt->front + MAX_Q_SIZE) % MAX_Q_SIZE);
}
2-3 main()#
💡 基于循序结构的循环队列实现
-
队空条件:
Q.front == Q.rear
-
队满条件:
(Q.rear+1+MAX_Q_SIZE)%MAX_Q_SIZE == Q.front
#include <stdio.h>
#include "sq_queue.h"
int dancer_match(SqQueue_T *m_dancer_pt, SqQueue_T *f_dancer_pt)
{
while (!queue_empty(m_dancer_pt) && !queue_empty(f_dancer_pt))
{
QElemType m_elem, f_elem;
queue_pop(m_dancer_pt, &m_elem);
queue_pop(f_dancer_pt, &f_elem);
printf("%s(M) %s(F)\n", m_elem.name, f_elem.name);
}
return OK;
}
int main()
{
SqQueue_T m_dancer_t; //定义男性舞者队列
SqQueue_T f_dancer_t; //定义女性舞者队列
Person_T person_t[MAX_Q_SIZE]; // 定义舞者数组
int num_of_person;
queue_init(&m_dancer_t);
queue_init(&f_dancer_t);
printf("请输入舞者人数:");
scanf("%d", &num_of_person);
printf("\n");
for (int i = 0; i < num_of_person; i++)
{
printf("请输入第%d个舞者的姓名和性别(M or F):", i + 1);
scanf("%s %c", person_t[i].name, &person_t[i].sex);
}
for (int i = 0; i < num_of_person; i++)
{
if (person_t[i].sex == 'M')
queue_push(&m_dancer_t, person_t[i]);
else
queue_push(&f_dancer_t, person_t[i]);
}
printf("\n");
dancer_match(&m_dancer_t, &f_dancer_t);
printf("舞者配对后,剩余男性舞者人数:%d\n", queue_length(&m_dancer_t));
printf("舞者配对后,剩余女性舞者人数:%d\n", queue_length(&f_dancer_t));
queue_destory(&m_dancer_t);
queue_destory(&f_dancer_t);
return 0;
}
- 运行结果
三、反思总结#
生活中队列问题很常见,如何利用队列结构解决现实中的问题就很重要
使用队列一定要从队列的定义考虑:
队列(queue)是一种先进先出(First In First Out, FIFO)的线性表。
它只允许在表的一端进行插入,而在另一端删除元素。这和日常生活中的排队是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一端称为队尾(rear), 允许删除的一端则称为队头(front)。
四、参考引用#
数据结构第二版:C语言版 【严蔚敏】 第三章 栈和队列
作者:caojun97
出处:https://www.cnblogs.com/caojun97/p/17265827.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
Data Structure
标签:
队列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通