1.
问题描述:
设有编号为1,2,…,n 的n(n>0)个人围成一个圈,每个人持有一个密码m。从第一个人开始报数,报到m 时停止报数,报m 的人出圈,再从他的下一个人起重新报数,报到m 时停止报数,报m 的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n 和m 后,设计算法求n 个人出圈的次序。
2.
数据结构设计:
因为约瑟夫环本身具有循环性,所以采用循环链表的存储结构。建立结构体如下:
typedef struct Node
{
DataType data;
struct Node *next;
};
为了统一对结点的操作,循环链表不带头结点,由头指针head指出。
3.
算法设计:
根据约瑟夫环问题的实际性,因包含的算法有:建立结点、创建循环链表、每个人密码相同时的约瑟夫函数、每个人密码不同时的约瑟夫函数。
(1)
建立结点:
采用循环链表的存储结构。如下:
typedef struct Node
{
DataType data;
struct Node *next;
}ListNode;
(2)创建循环链表:
由问题的实际性,创建一个为长度为n的循环链表,代表由n个人构成与瑟夫环。链表没有头结点,由头指针指出,该算法返回一个指向新建循环链表的头指针。
LinkList CreateDCList(int n)
{
LinkList head=NULL;
ListNode *s,*q;
int i;
for(i=1;i<=n;i++)//逐一为环中的人编号
{
s=(ListNode*)malloc(sizeof(ListNode));//申请内存
s->data=i;
s->next=NULL;
if(head==NULL)
{
head=s;
s->next=head;
}
else
{
s->next=q->next;
q->next=s;
}
q=s;
}
return head;//返回头指针
}
(3)约瑟夫函数1(密码相同):
输入密码m,从头指针开始,每数一个数,指针指向下一个结点,数到m时,踢出指针所指的结点。进行下一次循环。直到所有的人都被踢出为止。
void Josephussame(LinkList head,int n,int m)
{
ListNode *p,*q;
int i,j;
p=head;
j=1;
while(p->next!=p)//当环中人数在两人以上时
{
for(i=1;i
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);//最后一个人
}
(4)约瑟夫函数2(密码不同):
输入密码m,从头指针开始,每数一个数,指针指向下一个结点,数到m时,踢出指针所指的结点。进行下一次循环。直到所有的人都被踢出为止。
void Josephusdifferent(LinkList head,int n,int *a)
{
ListNode *p,*q;
int i,m,j;
p=head;
m=a[1];
j=1;
while(p->next!=p)
{
for(i=1;i
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
m=a[p->data];
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);
}
4.
附录(源代码)
#include
#include
#include
typedef int DataType;//循环链表存储结构
typedef struct Node
{
DataType data;
struct Node *next;
}ListNode,*LinkList;
//创建一个新的循环链表
LinkList CreateDCList(int n)
{
LinkList head=NULL;
ListNode *s,*q;
int i;
for(i=1;i<=n;i++)//逐一为环中的人编号
{
s=(ListNode*)malloc(sizeof(ListNode));//申请内存
s->data=i;
s->next=NULL;
if(head==NULL)
{
head=s;
s->next=head;
}
else
{
s->next=q->next;
q->next=s;
}
q=s;
}
return head;//返回头指针
}
//密码相同时的约瑟夫函数
void Josephussame(LinkList head,int n,int m)
{
ListNode *p,*q;
int i,j;
p=head;
j=1;
while(p->next!=p)//当环中人数在两人以上时
{
for(i=1;i
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);//最后一个人
}
//密码不同时的约瑟夫函数
void Josephusdifferent(LinkList head,int n,int *a)
{
ListNode *p,*q;
int i,m,j;
p=head;
m=a[1];
j=1;
while(p->next!=p)
{
for(i=1;i
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
m=a[p->data];
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);
}
int main()
{
LinkList h;
int n;
printf("请输入环中的人数:\n");
scanf("%d",&n);
printf("请选择密码形式:\n单一密码请输入1\n各人不同请输入2\n");
int chose;
chongxin:
scanf("%d",&chose);//选择密码形式
if(chose==1)
{
int m;
printf("请输入密码\n");
scanf("%d",&m);
h=CreateDCList(n);
Josephussame(h,n,m);
}
else if(chose==2)
{
int a[n+1];
printf("请输入各人密码\n");
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
h=CreateDCList(n);
Josephusdifferent(h,n,a);
}
else
{
printf("输入错误,请重新输入:\n");
goto chongxin;//输入错误时,返回到选择密码形式状态
}
return 0;
}