问题描述:约瑟夫环问题是,编号为1,2,3,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码。开始时任选一个正整数作为报数上限值m,从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。
基本要求:利用单链表存储结构模拟此问题,按照出列顺序打印各人的编号。
测试数据:M的初值为20,n=7,7个人的密码依次为3,1,7,2,4,8,4。则首先出列的人是6号,依次正确的出列顺序应该为6,1,4,7,2,3,5。
实现提示:要求用户指定报数上限值,然后读取每人的密码。此问题所用循环链表不需要头结点。
实现思路:构造一个循环链表,通过循环始终将一个指针指向第m个人的直接前驱,更新密码m,修改链表
#include<stdio.h>
#include<malloc.h>
#define LEN sizeof(struct Node)
struct Node
{
int num; //编号
int code; //密码
struct Node *next;
};
//创建长度为n单向循环链表
struct Node *creat(int n)
{
int i=1;
struct Node *p,*q,*head;
p=(struct Node*)malloc(LEN);
for(i=1;i<=n;i++)
{
if(i==1)
head=p; //头指针
else
{
q=(struct Node*)malloc(LEN);
p->next=q;
p=q;
}
p->num=i;
scanf("%d",&p->code); //依次输入密码
}
p->next=head;
return head;
}
//输出出列人的编号
void joseph(struct Node *head,int m)
{
struct Node *p,*q;
q=head;
//head的前驱初始化为 q,
while(q->next!=head)
q=q->next;
p=head; //p指向 head
//链表中超过一个结点
while(p->next!=p)
{
//p指向要出列的人,q的后继指向p
for(int i=1;i<m;i++)
{
p=p->next;
q=q->next;
}
printf("%d ",p->num);
m=p->code;
q->next=p->next;
p=p->next;
}
//链表中只剩余一个结点,输出
if(p->next==p)
printf("%d ",p->num);
}
int main()
{
struct Node *head;
int M,n;
printf("输入链表长度 n 和 M 的初始值:\n");
scanf("%d%d",&n,&M);
printf("依次输入 %d 个人的密码:\n",n);
head=creat(n); //建立链表
printf("出列的人依次为:\n");
joseph(head,M); //依次输出出列人员编号
return 0;
}