约瑟夫问题的一种描述是:编号为1,2,……,n点的n个人按顺时针方向围坐一个圈,每人持有一个密码。一开始选一个正整数作为报数上限值m,从第一个人开始从顺时针方向自1开始报数,报到m时停止。报到m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始从新从1报数,如此下去,直达所有人出列。
基本要求:利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各人的编号。
测试数据:m的初始值为20;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>
#include <stdlib.h>
typedef struct node{
int data;
struct node *next;
}LNode;
LNode* Create(int n,int k)
{
int start=k-1;
LNode *s,*p,*L=0,*t;
if (start==0) start=n;
while (n!=0)
{
s=(LNode *)malloc(sizeof(LNode));
if (L==0) p=s;
if (n==start) t=s;
s->data=n;
s->next=L;
L=s;
n--;
}
p->next=L;
return t;
}
LNode* deleteNode(LNode *p)
{
LNode *q;
for (q=p;q->next!=p;q=q->next);
q->next=p->next;
free (p);
return (q);
}
int Print(LNode *p,int m)
{
int i;
while (p->next!=p)
{
for (i=1;i<=m;i++)
p=p->next;
printf ("%d=> ",p->data);
p=deleteNode(p);
}
printf("%d\n",p->data);
return 0;
}
void main()
{
LNode *p;
int n,k,m;
printf ("n:");
scanf ("%d",&n);
printf ("开始人的序号:",n);
scanf ("%d",&k);
printf ("间隔人:");
scanf ("%d",&m);
p=Create(n,k);
Print(p,m);
}
法二:
C语言数组实现
//n为总人数,m为第几个人出去
#include <stdio.h>
int main(){
int i, j, k, a[100000], *p;
int n, m;
printf("n:");
scanf("%d", &n);
for(i = 0, p = a; p <= a + n; i++, p++)
*p = i;
p = a + 1;
for(i=1;i<=n;i++)
a[i]=i;
p=a;
printf("m:");
scanf("%d", &m);
for(i = 0,k = n; k != 1; p++){
if(p > (a + n))
p = a + 1;
if(*p != 0)
i++;
if(i ==m){
*p = 0;
i = 0;
k--;
}
}
for(i = 0; i <= n; i++){
if(a[i] != 0)
printf("%d ", a[i]);
}
return 0;
}