约瑟夫问题中遇到的一些问题:
看了很多关于约瑟夫问题的代码,发现一个问题,就是大多数报数就一个人活下来了,实际上当人数小于报数人数时游戏就应该停止,改了几天的代码,最后终于实现了,开始想法是设置链表长度,每次自杀一个人就表长减一,当表长小于报数人数时就停止游戏,但是最后发现输出的胜利编号总是不对,后来发现输出方式有问题,最后输出只能输出一个,然后改了又改最后终于实现了输出全部胜利者的功能。
//约瑟夫问题
//1~41人围成一个圈,每次报数,到第3个人去自杀,依次循环
//步骤:1.建立一个循环单链表
//2.往循环链表中插入人数41人
//3.求出41个人中淘汰的人和活下来的人
#include <iostream>
using namespace std;
#define MAX 200//限制最多只能200人加入游戏
//定义单链表存储结构体
struct people
{
int human;//数据域
struct people*next;//头结点指针
};
struct man{
struct people peopleArray[MAX];
int Size;
};
//建立循环链表
people * initlist(int n)
{
people *p,*s;
people *head=new people;//开辟空间
head->human=1;//头结点从1开始
head->next=NULL;
s=head;//定义一个新结点接收头结点
for (int i=2; i<=n; i++)
{
p= new people;//p的后继指向开辟的新空间
p->human= i;
p->next=NULL;
s->next=p;
s=s->next;
}
s->next=head;//首尾相连
return head;
};
//往游戏中增加人数
void addpeople(man*abs)
{
if(abs->Size==MAX)
{
cout<<"人数已满不能再添加了!"<<endl;
}
else
{
cout<<"请输入游戏总人数:";
int n;
cin>>n;
abs->Size=0;//初始化表长
for(int i=0;i<n;i++)
{
abs->peopleArray[i].human=i;
abs-> Size++;
}
}
}
//统计人数并返回人数
int statpeople(man*abs)
{
int s=abs->Size;
return s;
}
//游戏中淘汰的人
void disusepeople(man*abs,people*head,int s,int k)//s是每次的报数到s的人就自杀的人,
{
cout<<"游戏开始"<<endl;
people*l=head;
//找到链表第一个结点的上一个结点,为删除操作做准备
while (l->next!=head)
{
l=l->next;
}
people *f=head;
//找到编号为k的人
while(f->human!=k)
{
l=f;
f=f->next;
}
while (f->next!=f) {
//找到从f报数1开始,报s的人,并且还要知道数s-1的人的位置l,方便做删除操作。
//int i=0;
for (int i = 1; i < s; i++) {
l = f;
f = f->next;
}
abs->Size--;//每次减少一个人表长减一
l->next = f->next;//从链表上将f结点摘下来
cout << "自杀的人的编号为: " << f->human << "号" << endl;
delete(f);//删除自杀人员的数据
f = l->next;//继续使用f指针指向出列编号的下一个编号,游戏继续
if(abs->Size<s)//当表长小于报数的人数时停止循环
{
break;
}
}
//输出停止链表循环时链表还存活的人的编号
for(int j=0;j<abs->Size;j++)
{
f=f->next;
cout<<"游戏幸存者的编号为:"<<f->next->human<<"号"<<endl;
}
}
int main() {
int n;//接收总人数变量
int k=1;//从第1人开始报数变量
int s;//数到第几的人自杀
man abs;
addpeople(&abs);//输入第人数
n=statpeople(&abs);//接收输入的人数
people * head=initlist(n);//建立循环链表
cout<<"请输入报数到第几的人自杀:";
cin>>s;
disusepeople(&abs,head,s,k);//游戏中淘汰的人
return 0;
}