一.问题描述
约瑟夫(Joseph)问题的一种描述是:编号为 1,2,…,n 的 n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个整数作为报数上限 m,从第一人开始按顺时针方向从自 1 开始顺序报数,报到 m 时停止报数。报 m 的人出列,将他的密码作为新的 m 值,从他的顺时针方向上的下一个人开始重新从 1 报数,如此下去,直至所有人全部出列为止,设计一个程序求出出列顺序。
二.要求:
利用单向循环链表存储结构模拟此过程,按照出列的顺序引出个人的编号。并且不需要头结点。
三.测试数据:
n=7,7个人的密码依次是3,1,7,2,4,8,4;m=6,正确的出列顺序为6,1,4,7,2,3,5
四.运行结果如下
五.完整代码如下,详细见注释
#include"stdio.h"
#include"malloc.h"
typedef struct //自定义结构体,
{
int index,password; //index存储每个人的序号,password存储每个人的密码
struct *next;
}Node,*Linklist; //Node定义结点,Linklist定义指针
Linklist p,first,temp; //建立全局变量,方便
void Initlist(int n) //n个元素的链表
{
int i,j,num;;
first=(Node*)malloc(sizeof(Node)); //创建首元结点
if (!first)
return 0;
p=first; //拷贝副本
for( i=1;i<n;i++)
{
temp=(Node*)malloc(sizeof(Node)); //新建结点
if (!temp)
return 0;
p->next=temp; //p一开始在表头,新结点插后
p=temp; //p向前移动
}
p->next=first; //尾部连接表头
temp=first; //让temp做first副本
for( j=1;j<=n;j++)
{
temp->index=j; //j是序号
printf("请输入第%d个人的密码:",j);
scanf("%d",&num);
temp->password=num; //存储密码
temp=temp->next;
}
temp=p; //这时候temp指向最后一个元素
}
void find(int m,int n)
{
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<m;j++)
temp=temp->next; //temp指向第m-1个元素
p=temp->next; //p指向第m个元素
m=p->password; //更新m的值
printf("%d,",p->index); //输出出列人的序号
temp->next=p->next; //删掉p结点
free(p); //释放动态申请的结点空间
}
return 0;
}
void main()
{ int m,n; //m为报数初值,n为初始人数
printf("请输入报数初值m:");
scanf("%d",&m);
printf("请输入初始人数n:");
scanf("%d",&n);
Initlist(n); //初始化循环链表
printf("出队的人依次是:");
find(m,n); //开始淘汰
}