数据结构作业 约瑟夫问题

 约瑟夫问题中遇到的一些问题:

      看了很多关于约瑟夫问题的代码,发现一个问题,就是大多数报数就一个人活下来了,实际上当人数小于报数人数时游戏就应该停止,改了几天的代码,最后终于实现了,开始想法是设置链表长度,每次自杀一个人就表长减一,当表长小于报数人数时就停止游戏,但是最后发现输出的胜利编号总是不对,后来发现输出方式有问题,最后输出只能输出一个,然后改了又改最后终于实现了输出全部胜利者的功能。

//约瑟夫问题
//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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lune_one

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值