一、实验题目:
约瑟夫环问题。
二、实验内容:
设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码。
开始时任选一个正整数做为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m是停止报数,报m 的人出列,将他的密码作为新的m值,从他的下一个人开始重新从1报数。
如此下去,直到所有人全部出列为止。
令n最大值取30。
要求设计一个程序模拟此过程,求出出列编号序列。
实现:用一个不带头结点的单向循环链表表示上述约瑟夫环,结点结构可定义为:
typedef struct node{ Array int pos;//位置
int code;//密码
struct node *next;
}JosephNode,* JosephList;;
三、程序源代码:
# include <stdio.h>
# include <stdlib.h>
# define ERROR 0
# define OK 1
Typedef struct node{
int pos,code;
struct node *next;
}JosephNode,* JosephList;
int InitList_Joseph(JosephList &h,int n)
//初始Joseph环。
//为什么就&h,而不是h??
{ JosephNode *newp,*p;
h=NULL;
for(int i=1;i<=n;i++)
{ newp=(JosephList)malloc(sizeof(JosephNode));
if(!newp)
return ERROR;
newp->pos=i;
printf("Please input the %dth one's code\n ",i);
scanf("%d",&newp->code);
if(h==NULL)
{h=newp;p=newp;}
else
{p->next=newp;
p=newp;
}
}
p->next=h;return OK;
}
int length(JosephList &h)
//求Joseph环的长度。
{ int len=0;JosephList ph=h;
if(h==NULL) return (len=0);
if(ph->next==ph) return (len=1);
while(ph->next !=h)
{len++;ph=ph->next;}
len++;
return len;
}
//////
void print(JosephList h)
//输出Joseph环。
{ JosephList ph=h;
system("CLS");
printf("The length of Joseph Circle is %d!\n",length(h));
if(ph==NULL){printf("This Joseph circle is empty!\n");return;}
do
{ printf("%dth one's code is %d\n",ph->pos,ph->code);
ph=ph->next;
}while(ph!=h);
}
//////
void Push_Joseph(JosephList h,int m)
//用递归方法求其出圈顺序。
{ JosephList p,first,pf;
static int cnt=0;
if(m==0){printf("\n\nCODE ERROR(0 inluded)\n\n");return;}//若code为0则出错,退出!
if(length(h)<=1)//当长度为1时,最后一个节点出圈。
结束函数。
{printf("\nThe last one is %d\n",h->pos); return;}
else
{ p=h;pf=p;
if(m==1)////若m==1则出圈的是其自己.
{ while(p->next!=h)
p=p->next; //找到其前驱。
printf("\nthe %dth one is %d",++cnt,h->pos);
p->next=h->next;
m=h->code;
free(h);
first=p->next;//将其后继当作头节点,
Push_Joseph(p,m);//递归调用Push_Joseph.
}
else//若m>1则,依次报数。
{for(int i=1;i<m;i++)//找到其后继。
{ pf=p;p=p->next;}
printf("\nThe %dth one is %d",++cnt,p->pos);//让其出圈。
pf->next=p->next;
m=p->code;
first=p->next; //将其后继当作头节点,
free(p);
Push_Joseph(first,m);//递归调用Push_Joseph.
}
}
}
void main()
{ int n,m;
JosephList h=NULL;
printf("Please input the number of people.\n");
scanf("%d",&n);
printf("h=%d\n",h);
if(!InitList_Joseph(h,n))//判断初始环是否成功。
{printf("Creating Joseph circle fails\n");exit(0);}
print(h);//输出Joseph圈。
printf("Please input the first number!\n");
scanf("%d",&m);
Push_Joseph(h,m);//出圈函数。
}
四、测试结果:
五、小结(包括收获、心得体会、存在的问题及解决问题的方法、建议等)
通过这次解决约瑟夫环问题的实验让我对数据结构这门课程有了一个初步的、简单的认识,通过自己的思考和与同学的讨论使我对数据结构中的链表,特别是环链表有了深刻的认识和理解,同时我还体会到了数据结构在编程中的重要性,加深了我对学习这门课程的兴趣;
在这次试验中我还是遇到了不少的问题,比如本次试验中的指针指向性的问题,在报数的时候应该把指针指向表尾,使得每次都能从第一个人开始报数,开始的时候我没有想到这些,结果老是不对,通过仔细的思考和与同学的讨论最终解决了这个问题;通过这次实验使我对数据结构产生了浓厚的兴趣,我发现自己还有许多要学习的自己还要继续努力。