加载中...
加载中...
约瑟夫生死者游戏(循环单链表实现)

约瑟夫生死者游戏(循环单链表实现) 原创

约瑟夫生死者游戏

[问题描述]

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

[基本要求]

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

[测试数据]

m的初值为20;密码:3172484(正确的结果应为6147235)。

[实现提示]

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

算法代码

复制收展Markdown#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#define OK 1
#define ERROR -1
#define OVERFLOW 0
//约瑟夫生死者游戏(循环单链表实现) 2019-12-30
//[测试数据]m的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。
typedef struct LNode
{ // 结点类型定义
int no; //编号
int pwd; //报m的人出列,将他的密码作为新的m值
int length; //长度
struct LNode *next;
}LNode, *LinkList;
//初始化链表,函数调用完毕后,L会指向一个空的链表,即会改变指针的值。所以要用*L指向指针的指针
int InitList_CL( LinkList *L ) // 生成只含头结点的空循环单链表
{
*L = (LinkList)malloc(sizeof(LNode));
if(!(*L))
exit(OVERFLOW);
(*L)->next = *L;
(*L)->length=0;
return OK;
}
//创建链表
int CreateList_CL( LinkList L, int n )
{ // 按尾插入法建立含n个元素的循环单链表
LNode *p, *q;
int i,no;
L->length=n; //长度
q = L;
//int pwds[]={0,3,1,7,2,4,8,4};
for(i=1; i<=n; i++)
{
p = (LNode *)malloc(sizeof(LNode)); // p指向新结点
//scanf ("%d",&p->data);
p->no = i; //编号
//密码
//p->pwd= i*i+1;
//p->pwd= pwds[i];
printf("输入第%d个人的密码pwd=", i);
scanf("%d", &(p->pwd));
//添加结点
p->next = q->next; //新增结点最后一个结点p指向头结点L
q->next = p; //
q = p; // q指向表尾结点
}
return OK;
}

// 遍历循环单链表L
int TraverseList_CL( LinkList L )
{
LNode *p;
p = L->next;
while( p!=L )
{
printf ("no=%d ,pwd=%d\n",p->no, p->pwd);
p = p->next;
}
printf("\n");
return OK;
}

//约瑟夫(Joeph)问题
int yuesefu( LinkList L, int m)
{ LNode *p, *q;
int i=0;
p=L;
//结束 递归出口
if(L->length == 0) return OK;
//报到m时停止报数
m = m % (L->length);
//最后一个得到的余数是0,且m此时和链表此时的长度一样
if(m == 0) m= L->length;
//printf("m=%d\n",m);
for(i=1;i<m;i++){
p = p->next;
//printf("p->no=%d\n",p->no);
}
//q是要出去的要删除的
q=p->next;
printf("编号为【%d】的人出列\n",q->no);
p->next=q->next;
L->length = L->length - 1;
//printf("L->length=%d\n",L->length);
//printf("他们的编号是:\n");
//TraverseList_CL( L );
//printf("q->pwd=%d\n",q->pwd);
//+m是从第一个开始,模拟上一次的
return yuesefu(L, q->pwd+m-1);
}

void main()
{
LinkList L;
int i, m, n;
//初始化
InitList_CL(&L);
printf("-----------约瑟夫生死者游戏-----------\n");
printf("【游戏规则】游戏编号为1,2,3…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。\n");
n=7;
m=20;
printf("一共有n个人n=");
scanf ("%d",&n);
//创建链表
CreateList_CL( L, n );
printf("最开始他们的编号/密码是:\n");
TraverseList_CL( L );
printf("m的初值为m=");
scanf ("%d",&m);
//使用递归实现
yuesefu(L, m);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117


效果


 

没有更多推荐了 [去首页]
image
文章
376
原创
293
转载
83
翻译
0
访问量
183411
喜欢
73
粉丝
5
码龄
7年
资源
3

文章目录

加载中...
0
0