约瑟夫环问题
一、 实验目的
- 熟悉线性表的操作和应用;
- 利用顺序表的存储结构解决约瑟夫环问题。
二、 实验原理
1. 问题描述:设编号为1,2,…,n(n>0)个人按顺时针方向围坐—圈,从第一个人开始报数,当报到第M个人时,该人出圈。然后接着报,L个人出圈或圈里还剩(N-L)个人。
2. 方法实现:利用线性表中循环链表的结构特点,每个节点表示一个人。用一个程序模拟人的报数出圈,1表示人还在圈里,0表示人已经出圈了。当第L个人出圈之后,报数程序结束,输出最后的在圈子里的人的情况。
3. 程序设计思路:
⑴先定义一个链表节点的结构体,结构体中data的值用来表示该节点所表示的人是否出圈,*next指针指向下一节点;
⑵用一个函数初始化一个n个节点的链表,并把最后一节点的*next指针指向头结点,以便形成循环链表。
⑶用一函数将指针所指向的整个循环链打印输出。
⑷用一函数模拟循环报数出圈:函数中采用三重循环,外层循环为报数出圈的人数,即第L个人出圈后停止报数;中层循环为报数的数值,即循环M次直到报到M的人出圈;内层循环用来排除已经出圈了的人,报数时遇到节点data值为0(即已经出圈了的人)则循环,直到节点data值为1(即未出圈的人)后退出本循环继续报数。
三、 实验程序
//========================================================
#include<iostream.h>
/*****************************************************************
函数功能: 定义一个链表的结构体
*****************************************************************/
struct node
{
int data;
node *next;
};
/*****************************************************************
函数功能: 初始化一个n个节点的循环链表,值分别为1
*****************************************************************/
node *Initnode(int n) //
{
node *head,*p;
head=p=new node;
for(int i=1;i<=n-1;i++)
{
p->data=1; //i //将每个节点的值赋为1,表示该节点的人未被提出
p->next=new node; //节点指针指向新创建的节点
p=p->next;
}
p->data=1; //n
p->next=head; //将最后一个节点的指针指向头结点,以便形成循环链表
return head;
}
/*****************************************************************
函数功能: 显示当前人数情况
*****************************************************************/
void Print(node *head,int n) //(节点起始位置,总共要显示人数)
{
node *q;
q=head; //将q节点指向头结点
for(int i=0;i<n;i++)
{
cout<<q->data; //输出当次报数后所剩人的排队情况
q=q->next;
}
cout<<endl;
}
/*****************************************************************
函数功能: 报数踢人
*****************************************************************/
void Done(node *head,int n,int m ,int k)
{ //(节点起始位置,总人数,报数,提出人数)
node *p;
p=head;
for(int j=0;j<k;j++) //该循环为踢出人,共循环k次
{
for(int i=1;i<m;i++) //该循环为报数的次数
{
while(p->data==0) //如果该节点已经被踢出了,则从下一个没被踢出的节点数
{
p=p->next;
}
p=p->next; //每数一次,指针指向下一个节点
}
while(p->data==0) //如果该节点已经被踢出了,则从下一个没被踢出的节点数
{
p=p->next;
}
p->data=0; //将报数为m的人提出
cout<<"第"<<(k+1)<<"次报数结果为:"<<'\t';
Print(head,n); //显示每次报数后的情况
}
}
/*****************************************************************
函数功能: 主函数
*****************************************************************/
void main()
{
node *head;
int a=0;
int m,n,l;
cout<<"请分别输入总人数N,每次报数M,及踢出L个人:";
cin>>n>>m>>l;
head=Initnode(n); //头结点指向初始化好的循环链表
Done(head,n,m,l); //开始报数踢人
}