约瑟夫(Joseph)问题的一种描述是:编号为1,2,3,…,n的n个人按顺时针方向围坐一圈。每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,令其出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新报数,如此下去,直到所有人全部出列为止。试设计一个程序求出出列顺序。
按照出列的顺序打印出各人的编号。
测试数据:
m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4,首先m值为6(正确的出列顺序应为6,1,4,7,2,3,5)
C语言写的代码,因为要用到引用,所以建立的是C++
#include <iostream>
#include<malloc.h>
typedef struct lnode{
int n;//个人编号
int pwd;//手持密码
int length; //链表长度
struct lnode *next;
}lnode,*linklist;//定义节点和链表
linklist listcreat(linklist &l){//创建循环链表
l=(linklist)malloc(sizeof(lnode));
int n,j=1;
l->length=0;//记录链表长度
lnode *p=l;
int pw;
printf("输入人数n:\n");
scanf("%d",&n);
printf("依次输入每个人所持密码数字:\n");
while(j<=n)//建立j个节点
{
lnode *s=(lnode*)malloc(sizeof(lnode));
s->n=j;//申请S节点
scanf("%d",&pw);
s->pwd=pw;
p->next=s;
p=s;
j++;
l->length++;//链表长度
}
p->next=l->next;//链表循环实现
return l;
}
linklist test(linklist &l){
lnode *p=l;//p寻找目标节点前驱
lnode *q;//q指向删除目标节点
int a=l->length;
int temp1,temp2;//1序号,2密码
int j=0;
int m;
printf("输入m初始值:\n");
scanf("%d",&m);
while(a>=1)//直到链表长度变成1
{
while(j<m-1)//寻找删除节点前驱
{
p=p->next;//执行后p指目标前驱
j++;
}
q=p->next;//q指向要删除的节点
temp1=q->n;
temp2=q->pwd;//提取q中数据
printf("依次删除序号为%d 所持密码为%d\n",q->n,q->pwd);
p->next=q->next;//P指向q后链表
a--;//长度减一
m=q->pwd%a;//除余后,m为新的寻找位序
free(q);//释放q节点
j=0;//寻找新的要删除密码数重置寻找变量为0
}
}
int main(int argc, char** argv) {
linklist l;
listcreat(l);//尾插法创建循环链表l
test(l);//解决问题功能
return 0;
}