约瑟夫环算法?
约瑟夫环指的是,n个人按编号顺序围成一个环,设置一个数字m,其中m<n(一般m取0-9之间的数);并从环中的第一个人开始,按顺时针数数,每数了m个位置,排在m号的位置上的人出列,然后从出列的位置的下一个位置上的人开始数,一直到环中剩下最后一个人为止。
算法步骤:
(1)确定存储结构:由于是一个环,所以建立一个循环链表
(2)设置指针个数:设置一个头指针*front永远指向第一个结点(按数字顺序的话是指向环中最小的那个节点也可又从0开始数),再设置一个尾指针*prior用于指向报数的人的位置,每报一次数,尾指针指向下一个节点,数到m号时,则删除该节点,并将尾指针指向下一个节点,一直循环下去。
定义节点类型:
typedef struct Node
{
int data;
struct Node *next;
struct Node *front;
struct Node *prior;
}Node,*LinkList;
(3)向链表插入n个人(采用尾插法):
LinkList Create_cirlce()
{
LinkList L,r,p;
L = (Node *) malloc ( sizeof (Node)); //初始化链表
L->next = L;
r = L; //r始终指向最后一个结点
int n;
while ( scanf ( “%d” ,&n) != EOF)
{
p = (Node *) malloc ( sizeof (Node));
p->data = n;
p->next = r->next;
r->next = p;
r = p;
}
r->next = L;
return L;
}
(4)根据指针判断链表是否已出列到最后一个:判断*prior->next!=L
(5)利用循环遍历出出列的人:此时需利用两个循环,外循环代表遍历到最后一个所需要的循环次数,内循环代表遍历出列的人
void Josephus(int n,int m){
for(int i=0;i<n-1;i++){
for(int j=0;i<m-1;j++){
Next();//遍历出出列的人
cout<<“出列的人是:”<<current;//显示出当前出列的人的位置
延伸阅读
数据结构编程:求解报数问题。设有n个人占成一排,从左向右的编号分别为1到n,现在从左往右报数“1,2?
这个问题就是『约瑟夫环』问题嘛。
1 问题描述
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 k 的人开始报数,数到 m 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。
例如:有10个人围成一圈进行此游戏,每个人编号为 1-10,。若规定数到 3 的人出圈。则游戏过程如下。
(1)开始报数,第一个数到 3 的人为 3 号,3 号出圈。 ??1, 2, 【3】, 4, 5, 6, 7, 8, 9, 10。 (2)从4号重新从1开始计数,则接下来数到3的人为6号,6号出圈。 ??1, 2, 【3】, 4, 5, 【6】, 7, 8, 9, 10。 (3)从7号重新从1开始计数,则接下来数到3的人为9号,9号出圈。 ??1, 2, 【3】, 4, 5, 【6】, 7, 8, 【9】, 10。 (4)从10号重新从1开始计数,由于10个人称环形结构,则接下来数到3的人为2号,2号出圈。 ??1, 【2】, 【3】, 4, 5, 【6】, 7, 8, 【9】, 10。 (5)从4号重新从1开始计数,则接下来数到3的人为7号,7号出圈。 ??1, 【2】, 【3】, 4, 5, 【6】, 【7】, 8, 【9】, 10。 (6)从8号重新从1开始计数,则接下来数到3的人为1号,1号出圈。 ??【1】, 【2】, 【3】, 4, 5, 【6】, 【7】, 8, 【9】, 10。 (7)从4号重新从1开始计数,则接下来数到3的人为8号,8号出圈。 ??【1】, 【2】, 【3】, 4, 5, 【6】, 【7】, 【8】, 【9】, 10。 (8)从10号重新从1开始计数,则接下来数到3的人为5号,5号出圈。 ??【1】, 【2】, 【3】, 4, 【5】, 【6】, 【7】, 【8】, 【9】, 10。 (9)从10号重新从1开始计数,则接下来数到3的人为10号,10号出圈。 ??【1】, 【2】, 【3】, 4, 【5】, 【6】, 【7】, 【8】, 【9】, 【10】。 (10)最终剩余 4 号,4 号为胜利者。
2 数组求解
2.1 解题思想
用数组求解的基本思想就是用一个一维数组去标识这 n 个人的状态,默认全为 1 ,也就是都在圈子内,当数到 m的人出圈之后,标识置为 0(就是出圈了),同时报数器清 0,下一个人要从 1 开始。在每次报数之前要判断他是否在圈子内(也就是他的标识是否为 1 ),如果在圈子里面才会继续报数。定义一个变量记录出圈的人数, 出圈的人数等于 n-1 时,则游戏结束。
2.2 代码实现
3 循环链表求解3.1 解题思想
约瑟夫环问题可以转化为循环链表的数据结构来求解。可以将每个人看做链表的单个节点,每个节点之间通过链表的 next 指针连接起来,并且将链表末尾节点指向头节点就形成的环,由链表构成的环形结构在数据结构中称为循环链表。
3.2 代码实现
4 递推公式求解4.1 解题思想
约瑟夫环中,每当有一个人出圈,出圈的人的下一个人成为新的环的头,相当于把数组向前移动 m 位。若已知 n-1 个人时,胜利者的下标位置位 f(n?1,m) ,则 n 个人的时候,就是往后移动 m 位,(因为有可能数组越界,超过的部分会被接到头上,所以还要模 n ),根据此推导过程得到的计算公式为: ??f(n,m) = (f(n?1,m) + m) % n。 其中,f(n,m) 表示 n 个人进行报数时,每报到 m 时杀掉那个人,最终的编号,f(n?1,m) 表示,n-1 个人报数,每报到 m 时杀掉那个人,最终胜利者的编号。有了递推公式后即可使用递归的方式实现。
4.2 递归代码实现
4.3 迭代代码实现
实际应用
比如你们公司需要团建,你可以设计这个游戏,根据游戏人数的多少,将你和你心仪的妹子安排在合适的座位上,一同进最后的决赛圈~
什么叫约瑟问题?
约瑟夫问题(有时也称为约瑟夫斯置换,是一个计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.)
约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3。
分析:(1)由于对于每个人只有死和活两种状态,因此可以用布尔型数组标记每个人的状态,可用true表示死,false表示活。(2)开始时每个人都是活的,所以数组初值全部赋为false。(3)模拟杀人过程,直到所有人都被杀死为止。