约瑟夫环

问题描述:

已知n个人围坐在一张圆桌周围,从编号为1的人开始报数,数到m的那个人出列。下一个人从1开始报数,数到m的人继续出列,以此类推直至全部人出列。求出列顺序?


解决方案:

1、最简单明了的办法就是用循环链表存储这n个人。数到m的人出列,只需将该结点从链表里剔除即可,然后继续往后报数,直到链表只剩下一个结点时结束。

具体代码如下:

typedef struct People
{
	int number;
	People *next;
}people;//结点的存储结构

void List_kind(People* L,int n,int m)
{/L为n个人构成的链表,报数报到m的人出列
	People *q,*p=L;///p指向当前结点,q指向p的前驱
	while(p->next != p)///当链表只剩下一个结点,即报数剩下一个人的时候结束。
	{
		for(int i=1;i<m;i++)
		{/for循环实现功能:使p指向要出列的结点,q指向p的前驱
			q=p;
			p=p->next;
		}
		printf("%d\n",p->number);
		q->next=p->next;//将要出列的结点从链表“剔除”
		free(p);
		p=q->next;p指向出列的下一个结点,重新开始报数
	}
	printf("%d\n",q->number);/输出最后一个人
	free(q);
}



2、第二种办法就是用数组存储,难度将大大增加。但思路还是跟链表有点相似的。首先将要出列的元素输出,然后将它后面的所有元素都向前移一位,将已出列的元素填充掉。然后再向后找下一个要出列的元素。

注意:当搜索到最后一个元素a[i]以后,用求余"%"功能,让数组和循环链表一样实现循环。另外,每次输出一个元素并把它填充掉以后,数组的总元素个数i会减一。

具体代码如下:

void Array_kind(int n,int m)
{/n个人进行报数,报到m的出列
	int *a,i,j,k;
	a=(int*)malloc(sizeof(int));//为数组a动态分配内存
	for(i=1;i<=n;i++)
		a[i]=i;///对每个元素进行编号,代表每个人,注意编号从a[1]开始
	for(i=n,k=1;i>=1;i--)/i为数组当前元素总个数
	{
		k=(k+m-1)%i;//令k指向要出列的元素
		if(k==0)//从上式知,当k+m-1=i时才会(k+m-1)%i=0。因为数组是从a[1]开始的,k=0时出列的元素应该是a[i],而不是a[0]。
			k=i;
		printf("%d\n",a[k]);//输出要出列的元素
		for(j=k;j<i;j++)//k之后的元素都向前移一位,填充出列元素的位置。
			a[j]=a[j+1];
	}
}

理解代码最好的方式就是举具体的例子,我们假设n=7,m=3,求出列顺序,代码的实现如下:

(下图表示第二个for循环的执行过程,每一行表示执行一次循环)




转载请注明出处,谢谢!(原文链接:http://blog.csdn.net/bone_ace/article/details/41213215

题目: 每个人手里有个密码。开始给定一个正数m,做为报数上限,从某个人开始循环报数,报到m的人出列;再以该出列的人手中的密码为报数上限,依次报数。打印出列的人的序号的先后顺序。 一. 需求分析 1. 本演示程序中,人数n应为任意的,首先应输入一个值赋给初始报数上限m,程序应能自动保存出列人的序号和将出列的人所持的密码赋给m,再次作为报数上限,如此循环,直至所有人都出列为止。 2. 演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入相应数据(即每个人所持的密码),每个人的序号由程序自动分配。 3. 程序执行的命令包括: (1)构造链表;(2)输入数据;(3)执行报数,储存出列人的序号,删除出列人的信息以及把出列人的密码赋给m;(4)结束。 4. 测试数据 (1)m=20,n=7,7个人的密码依次为:3,1,7,2,4,8,4,首先m值为6,则这正确的出列顺序为6,1,4,7,2,3,5。 确的出列顺序为6,1,4,7,2,3,5。 二. 概要设计 为了实现上述操作,应以单向循环链表为存储结构。 1. 基本操作: code( ) 操作结果:构造空链表,若成功就初始化每个人的相关信息 code( ) 初始条件:线性链表存在 操作结果:释放指向出列的人的结点,并重新报数 2. 本程序包含三个模块: (1) 主程序模块; (2) 构造链表并输入每个人信息模块; (3) 释放结点模块;
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值