约瑟夫问题(链表)

约瑟夫问题

问题描述:

约瑟夫(Joseph)问题的一种描述是:编号为1,2,3,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码〈正整数〉,一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。

基本要求:

利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出各人的编号。

实现提示

程序运行后首先要求用户指定初始报数上限值,然后读取各人的密码(小于30)。

选作内容

在顺序存储结构上实现上述问题的操作。

Input

输入包括两行,第一行包括报数上限值m和人数n,第二行为n个人的密码,所有数据之间由空格分隔。

Output
输出一行,共n个整数,表示各编号人的出列顺序。各数之间由空格分隔。

Sample Input

20 7

3 1 7 2 4 8 4

Sample Output

6 1 4 7 2 3 5

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

typedef struct LNode	//结构体定义
{
	int id;
	int data;
	struct LNode *next; 
}LNode,*linklist;

linklist CL(linklist L,int n)//创建结构体
{
	int i=1;
	linklist p,q;
	p=(linklist)malloc(sizeof(LNode));
	L=p;
	q=p;
	p->id=i;
	while(i<=n)
	{
	p=(linklist)malloc(sizeof(LNode));
	scanf("%d",&(p->data)); 
	p->id=i++; 
	
	q->next=p;
	q=q->next; 
	}
	p->next=L;
	return L;
} 

linklist dellist(linklist L,int n,int m)//删除结点
{
	linklist p,q;
	int i=0,j=0,a;
	p=L;
	
	while(p && i<m-1)
		{			
		p=p->next;
		i++;/**/
		
		if(p->next==L)
			{
			i--;	
			continue;	
			}	
		}
	q=p->next;
	p->next=q->next;
	
	if(p->next==L)
	p=p->next;
	
	a=q->data;
	printf("%d ",q->id);
	free(q);	
	
	/**/
	while(j<n-1)
	{i=0;
	while(p && i<a-1)
		{
		p=p->next;
		i++;
			if(p->next==L)
			{
			i--;	
			continue;	
			}
		}
	
	q=p->next;
	p->next=q->next;
	
	
	if(p->next==L)
	p=p->next;
	
	a=q->data;
	printf("%d ",q->id);
	free(q);
	j++;		
	}
	
	return L;
}

void showlist(linklist L)//输出链表内容,用于调试

{
	linklist p;
	int n=0;
	p=L;
	p=p->next;
	while(p)
	{
	printf("|%d ",(p->data));	 
	printf("%d|  ",(p->id));
	if(p->next==L)
	break;
	p=p->next;	
	}	
	
}


int main() 
{	linklist L=NULL;
	int m,n; 
	
	scanf("%d",&m);
	scanf("%d",&n);
	
	L=CL(L,n);	
	
	//showlist(L);
	
	L=dellist(L,n,m);
	
	//showlist(L);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值