标签:Node Queue 结点 int next 问题 队列 报数
数据结构之报数出列问题
报数出列问题
问题描述
已知N个人(以编号1,2,3,…,N分别表示)排成一列。第一轮从编号为1的人开始依次报数,数到2的倍数的人出列;第二轮从头开始依次报数,数到3的倍数的人出列;第三轮再次从头开始依次报数,数到2的倍数的人出列;第四轮从头开始依次报数,数到3的倍数的人出列;依此规律重复下去,直到队列中的人数不超过三个为止。要求输出此时队列中剩下的人在初始队列中的编号。
问题输入
一个正整数N,表示初始人数,N≤5000。
问题输出
输出队列中剩下的人在初始队列中的编号,编号之间有一个空格。
输入样例
20
输出样例
1 7 19
提示
可以使用队列,每次操作时对队列中元素进行判断,不需要舍弃的就重新加入队列。
C语言代码实现
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<malloc.h>
//代表人的结点
typedef struct Node
{
int data;//存放初始编号
struct Node* next;//指向下一个结点的指针
}Node;
//队列
typedef struct Queue
{
Node* front;//队头
Node* rear;//队尾
}Queue;
void InitQueue(Queue*,int);//初始化队列
void EnQueue(Queue*,Node*);//进队
void OutQueue(Queue*);//出队
Node* GetOutQueue(Queue*);//返回出队结点
void RegularOut(Queue*,int,int);//报数出列
int CountQueue(Queue*);//计算队列中的人数
int main()
{
int N,num;
Queue Q;
printf("请输入队列长度:");
scanf("%d",&N);//输入队伍长度
InitQueue(&Q,N);
num = CountQueue(&Q);//记录当前队伍人数
while(true)
{//循环报数出列知道队伍人数不超过三人
RegularOut(&Q,num,2);//2的倍数者,报数出列
num = CountQueue(&Q);
if(num<=3)//判断当前队伍人数是否超过三人
break;
RegularOut(&Q,num,3);//3的倍数者,报数出列
num = CountQueue(&Q);//更新当前队伍人数
if(num<=3)
break;
}
for(int i =1; i<=num; i++)
{//输出队伍剩余的人的初始编号
Node* p = GetOutQueue(&Q);//出队
printf("%d ",p->data);//输出初始编号
free(p);//释放空间
p = NULL;//避免出现野指针
}
return 0;
}
//初始化队列
void InitQueue(Queue* Q,int len)
{
Q->front = Q->rear = (Node*)malloc(sizeof(Node));
//为队头队尾开辟一个存储空间(相当于两个指针指向同一个空结点)
if(Q->front == NULL)
exit(-1);
Q->front->next = Q->rear->next = NULL;
//初始化结点指针域为空
for(int i=1; i<=len; i++)
{//创建链表,赋值初始编码
Node* p = (Node*)malloc(sizeof(Node));
//为新结点开辟存储空间
p->data = i;//初始化编码
p->next = NULL;//指针域初始化为空
Q->rear->next = p;//新结点接在队尾
Q->rear = p;//队尾更新
}
}
//进队
void EnQueue(Queue* Q,Node* p)
{
Q->rear->next = p;
Q->rear = p;
}
//出队
void OutQueue(Queue* Q)
{
Node* p = Q->front->next;
Q->front->next = p->next;
free(p);
p = NULL;
}
//出队并且返回出队结点
Node* GetOutQueue(Queue* Q)
{
Node* p = Q->front->next;
Q->front->next = p->next;
p->next = NULL;
//出队结点指针域更新为空,避免再次入队若作为队尾,遍历队伍时出错
return p;
}
//报数出列
void RegularOut(Queue* Q,int num,int times)
{
int i;
for(i=1; i<=num; i++)
{//遍历队伍中每个结点
if(i%times == 0)//若报数是times的倍数,则出队
OutQueue(Q);
else
{//否则,先出队,再入队
Node* p = GetOutQueue(Q);
EnQueue(Q,p);
}
}
}
//计算队列中结点数
int CountQueue(Queue* Q)
{
int count=0;
Node* p = Q->front;
while(p->next!=NULL)
{//队列中最后一个结点指针与始终为空,为空结束计数循环
p = p->next;
count++;
}
return count;
}
Debug
- 分配空间出错,malloc函数为指针分配内存空间,但如果指针已经指向某一地址,则不需要分配空间。
例如:
//错误示范
Node* p = (Node*)malloc(sizeof(Node));
p = Q->rear;
//编译通过,则在debug过程中出现错误
//正确做法
Node* p = Q->rear;
malloc函数是为了程序员能手动分配内存空间给指针,避免指针在声明而未分配存储空间(指针未指向任何一片区域)的情况下被使用,出现编译无法查找的错误。
- 结点出队时要将指针域清空后再入队。它作为新结点入队时,总是插在队尾,并作为赋值为新队尾,若未清空,则在利用队尾为空条件进行遍历队列时,会出现死循环
标签:Node,Queue,结点,int,next,问题,队列,报数 来源: https://blog.csdn.net/weixin_45918830/article/details/112755940
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。