c语言: 链表法和数组法解决约瑟夫环

题目:

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
输出自杀序号。

方法一:通过数组解决

#include<stdio.h>

void process(int a[],int n,int k)
{
    int pos=0,num=1,h=0;//pos 数组a的下标
    int out=0;
    while(out<n)
    {
        pos=1+pos%n;//控制循环 (我觉得这条语句很重要,是让数组变成“环”的重点)
        if(num==k&&a[pos]==0)//活着并且报k的
        {
            a[pos]=1;//出局
            out++;
            num=1;//重新报数
            h++;
            printf("%2d  ",pos);//自杀
            if(h%10==0) 
            	printf("\n");//h其实没啥用,就是控制换行
        }
        if(a[pos]==0)//活着并且没有报k的
        {
            num++;
        }
    }


}
int main()
{
    int n,k;
    int arr[100]={0};
    printf("请输入总人数:");
    scanf("%d",&n);
    printf("请输入报数:");
    scanf("%d",&k);//为了函数的通用性,这里就输入总人数和报数(放到题中也就是n=41,k=3)
    process(arr,n,k);
    return 0;
}

结果如下图
在这里插入图片描述

方法二:环状链表

#include <stdio.h>
#include <malloc.h>
struct node
{
    int num;
    struct node* next;
};

//之前有些过环状链表如何创建,其实就是创建单向链表,然后头尾相连就好
//如果不太明白可以看看我的上一篇

struct node*create(int n)//创建含有n个节点的环状链表
{
    int i=0;
    struct node*head=NULL;
    struct node*q=NULL;
    head=(struct node*)malloc(sizeof(struct node));
    head->next=NULL;
    head->num=i+1;
    if(head==NULL)
        printf("NULL");
    struct node*tail=head;
    for(i=1;i<n;i++)
    {
        q=(struct node*)malloc(sizeof(struct node));
        q->num=i+1;
        q->next=NULL;
        tail->next=q;
        tail=q;
    }
    tail->next=head;
    return (head);
}

int main()
{
    int n,k,out=0,h=0;
    scanf("%d %d",&n,&k);
    //同样的,为了通用性我们输入n=41,k=3
    struct node* head=create(n),*p=head,*t;
    struct node* q=head;
    int num = 1;

    while(p->next!=p)//如果链表只剩下p这一个节点(也就是p指向p自身)的时候跳出循环
    {
        if (num<k)//如果还没报到k
        {
            q=p;//让q标记p目前的位置
            p=p->next;//让q向后指一个(现在就是q的下一个就是p)
            num++;//没自杀就正常报数咯
        }
        if(num==k)//报到k了,要自杀了TAT
        {
            out++;//自杀人数+1
            num=1;//下一个重新报数
            printf("%2d  ",p->num);//输出可怜人的序号
            h++;//这三行没啥用,是控制换行的,为了让输出好看一点
            if(h%10==0)
                putchar('\n');
            t=p;//现在让t标记住这个p的位置(t、p指向的是同一个节点)
            p=p->next;//p向后指一个
            q->next=t;
            q->next=t->next;
            //所以目前为止的位置关系是:q->t->p(t的位置是要删除的)
            free(t);//去掉t这个节点
        }

    }
    printf("%d ",p->num);//由于循环是在最后还剩下一个节点的时候结束的,所以我们还要输出最后一个节点
    return 0;
}

结果如下:(是一样der)
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值