约瑟夫问题两种实现方式

数组版本

#include<stdio.h>
#include <stdlib.h>


main(){
	
    
    int len;
    int pace;
    int time;
    int start;
    printf("请输入人数:\n");
    scanf("%d",&len);
    if(len<=0)
    {
    	printf("输入错误,程序终止!\n");
    	exit(-1);
	}
    
    
    int *p=(int*)malloc(len*sizeof(int));
     printf("请输入步长:\n");
    scanf("%d",&pace);
   
    if(pace==0)
    {
    	printf("输入错误,重新输入!\n");
    	exit(-1);
	}
    //if(pace==0)

    printf("请输入进行轮数:\n");
    scanf("%d",&time);
    printf("请输入您想从那个元素开始:\n");
    scanf("%d",&start);
    if(start==0)
    {
    	printf("输入错误,请重新输入:\n");
    	exit(-1);
	}
    
    
    	
    for(int i=0;i<len;i++){*(p+i) = 1;}   // 数组初始化,1:表示为活着;0:表示自杀

    int leftCount = len;                // 计数器leftCount:计数剩下的人
    int index = start-1,count = 0;            // 1.数组下标index;2.循环计数器count
    
     
     
    while(leftCount>(len-time))//从规定元素起点开始 
	{                            // 当还剩下n个结束

        if(*(p+index) == 1){ 
            count++; 
            if(pace== count){             // 计数到3,1.自杀;2.循环计数器count重新开始计数;3.计数器leftCount减1
                *(p+index) = 0;
                count = 0;
                leftCount--;
            }
        }
        index++;

        if(index == len){index = 0;}    // 当到数组尾,数组下标index置零,重新开始
    }

    for(int j=0;j<len;j++){             // 输出结果
        if(1 == *(p+j)){ printf("剩下的人为第%d个\n",j+1); }
    }
}

 

 单向循环链表版本

# include <stdio.h>
# include <stdlib.h>
typedef struct circle_list{
	int data;
	struct circle_list *next;
}NODE,*PNODE;//定义节点
PNODE creat_list(int len);//创建循环链表 

void visit_list(PNODE mark,int len,int time);//遍历寻欢链表 
PNODE  kill_list(PNODE head,int pace,int time,int len,int mark);//删除循环链表的一个给定下表的元素 


main()
{
	int pace;//步长 
	int time;//轮数 
	int len;//循环链表的长度 
	int index;//开始游戏的下标 
	PNODE mark=NULL;//访问遍历链表的指针 
	PNODE head=NULL;//创建循环链表的头 
	int i;
	printf("在罗马人占领乔塔帕特后,\n");
	printf("39 个犹太人与Josephus及他的朋友躲到一个洞中,\n");
	printf("39个犹太人决定宁愿死也不要被敌人抓到,\n");
	printf("于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,\n");
	printf("每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。\n");
	printf("现在您就是约瑟夫,为了活下去,您需要预测怎样才能活到最后\n");
	printf("而此时您得到了一个神奇的程序,请借助它,活下去!\n");
    printf("********************************************************************************\n");
	printf("欢迎来到约瑟夫问题,游戏开始!\n");

    printf("请输入总人数:\n");
    scanf("%d",&len);
    if(len==0)
    {
    	printf("输入错误,程序结束\n");
    	exit(-1);
	}
	head=creat_list(len);//创建链表 
	
	
	printf("请输入您想从第几个人开始:\n");
    scanf("%d",&index);
	
	printf("请输入步长(每经过几个人杀一个人:)\n");
	scanf("%d",&pace);
    printf("请输入进行的第几轮:\n");
    scanf("%d",&time);
   
    mark=kill_list(head,pace,time,len,index);//杀人并提供访问遍历链表的下标 
    visit_list(mark, len,time);//遍历链表 
    
    
    
	
	
}

PNODE creat_list(int len)
{
	PNODE head=NULL;
	PNODE  p;
	PNODE q;
	int i;

	p=(PNODE)malloc(sizeof(NODE));
	if(p==NULL)
	{
		printf("内存分配失败!\n");
		exit(-1);
	}
	head=p;
	p->data=1;//创建头结点 并且将它的数据域置为1 
	
	for(i=2;i<=len;i++)//创建其他节点并依次将这些节点挂在尾部 
	{
		q=(PNODE)malloc(sizeof(NODE));
		if(q==NULL)
		{
			printf("内存分配失败!\n");
			exit(-1);
		}
		q->data=i;//依次给节点数据域赋值,作为“人”的序号 
		p->next=q;
		p=q;//让p永远指向链表的尾部 
		
	}
	p->next=head;//首尾相连 
	return head;//返回头结点地址以便访问 
}
void visit_list(PNODE mark,int len,int time)//遍历循环链表 
{
	
	PNODE p=mark;//从标记开始进行循环 
	
	int count=0;
	printf("幸存下来人的序号为:\n");
do
	{
		printf("%d ",p->data);//依次输出未被删除节点的序号 
		p=p->next;
	}
while(p!=mark);//当没有循环够一圈 
	

	 printf("\n");
	
}


PNODE  kill_list(PNODE head,int pace,int time,int len,int index)
{
	int leftcount=len;//活着的人数 
	PNODE p=head;
	PNODE mark=NULL;//留下以便访问的地址 
	PNODE remain=NULL;//作为用来防止内存泄漏的媒介 
	int count=0;//循环次数 
	int count1=0;//从开始游戏的那个人开始循环次数 
	while(leftcount>(len-time))
	{
		count++;
		if(count>=index)//当过了要开始下表才开始杀人 
		{
			count1++;
			if(count1%(pace-1)==0)//当循环到要删除的那个节点的上一个节点才开始删除下一个节点 
			{
				mark=p;//不断刷新下表让它永远是最后留在链表中节点的地址即mark所指向的那个节点删到最后一定要存在 
				remain=p->next;
				p->next=p->next->next;//改变指针指向来删除节点 
				free(remain);
				leftcount--;//人数减少一位 
				
				
			}
		}
		p=p->next;//遍历条件 
	}
	return mark;
}

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值